Have you ever tried to display the node’s language field with your own custom formatter? Well, I tried it for the first time yesterday. I spent half an hour searching for why it didn’t do what I wanted (and expected).

Story in short

First, let’s clarify why you cannot only use a custom formatter to change the output of the Language (langcode) field of nodes:

Because NodeViewBuilder will override the field’s formatted markup, no matter what you do.

It will be f…ed up right here:

1
2
3
4
5
6
7
8
9
10
// Add Language field text element to node render array.
if ($display->getComponent('langcode')) {
  $build[$id]['langcode'] = [
    '#type' => 'item',
    '#title' => t('Language'),
    '#markup' => $entity->language()->getName(),
    '#prefix' => '<div id="field-language-display">',
    '#suffix' => '</div>',
  ];
}

Do you say “add”? But it was there already!!! 🤬

How to work this around

Well, set up the (custom) field formatter for the langcode field like you would do normally. And right after that, implement the hook_ENTITY_TYPE_view_alter() hook for the node entity type, and in that hook, do this:

1
2
3
4
5
6
7
8
9
/**
 * Implements hook_ENTITY_TYPE_view_alter() for node.
 */
function nodeviewbuilder_fixer_node_view_alter(&$build, NodeInterface $entity, EntityViewDisplayInterface $display) {
  // Re-add the expected Language field output to the render array.
  if ($display->getComponent('langcode')) {
    $build['langcode'] = $entity->get('langcode')->view($build['#view_mode']);
  }
}

That’s it.