I have a very simple (block) view to list a node's title. This view has an id from url contextual filter and a single filter to filter on Content language set for the page (by URL prefix). This block is then placed using Layout Builder on the Full Content view mode for this node type. The view is set to use Tag based caching. When I switch the page back and forth between languages; the title language does not change.

Disabling views caching fixes this.

A little digging and I see that Views cache context is based on Interface language but the Title is content; so it needs to be based on Content language. I have seen a few posts on setting cache context and cache tags but those don't seem to work.

So far I have tried this:

function mycustom_views_pre_view(ViewExecutable $view, $display_id, array &$args) {
  $language_manager = \Drupal::languageManager();
  $langcode = $language_manager->getCurrentLanguage(LanguageInterface::TYPE_CONTENT)->getId();
  if (isset($view->element['#cache']['contexts']) && is_array($view->element['#cache']['contexts'])) {
    foreach ($view->element['#cache']['contexts'] as $key => $context) {
      if (stristr($context, 'language_interface')) {
    $view->element['#cache']['contexts'][] = 'languages:language_content';
    $view->element['#cache']['tags'][] = 'language:' . $langcode;

None of this seems to help.

Is it possible I have fixed the view caching but the block is still not cached properly?

2 Answers 2


For Views rendering fields you can add the cache metadata to the field, so that it can be used already for the cached rows and then bubble up to the rendered view and block.

 * Implements hook_preprocess_views_view_field().
function mymodule_preprocess_views_view_field(array &$variables) {
  // target specific view and field
  $variables['#cache']['contexts'][] = languages:language_content';

You can add a backend class for the block, then add a cache context on language to that block.

First, you need to get the config key for the view block. I believe it is views.view.[BLOCK_ID]. You can get the block ID in the advanced section of the view.

Next, you add a custom class to the block. Here is how that is done for the system branding block.

 * Implements hook_block_alter().
 * Changes the class for the system branding block to add a cache
 * context for language.
function [MODULE]_block_alter(array &$definitions) {
  // Set custom callback for system menu block
  $definitions['system_branding_block']['class'] = 'Drupal\[MODULE]\Plugin\Block\SystemBrandingBlockOverride';

Then you can add a cache context on language to in the class:

namespace Drupal\[MODULE]\Plugin\Block;

use Drupal\system\Plugin\Block\SystemBrandingBlock;

 * Adds group caching to the system branding block.
class SystemBrandingBlockOverride extends SystemBrandingBlock {

   * {@inheritdoc}
  public function getCacheContexts() {
    $contexts = parent::getCacheContexts();

    $contexts[] = 'languages';

    return $contexts;


Note that you may want to use one one of the following cache contexts instead:

  • languages:language_interface
  • languages:language_content
  • Wouldnt be surprised if this also works; but 4k4's answer was 1 line - so picked that one.
    – liquidcms
    Commented Jan 11, 2022 at 22:50
  • If his works, then all the better!
    – Jaypan
    Commented Jan 11, 2022 at 23:07
  • The system branding block is the only core block I know which doesn't render the block content. You don't need this workaround for other blocks. In the contrary, it often doesn't work for rendered content. In general it's the best approach to add the cache metadata to the most granular piece of content it belongs to and let it bubble up.
    – 4uk4
    Commented Jan 12, 2022 at 7:33

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.