LanguageFormatter is not used for nodes because it's still hard coded in NodeViewBuilder

Created on 18 December 2015, almost 9 years ago
Updated 17 March 2023, over 1 year ago

Problem/Motivation

NodeViewBuilder hardcodes the display of the langcode field ignoring any formatter configuration. This is a barrier if you want to create new formatter such as:

  • Display name with native names
  • Add flag icons for languages
  • Display source language

Proposed resolution

Remove the hardcode langcode element in NodeViewBuilder and keep the wrapper for BC.

Remaining tasks

Review

User interface changes

The display of the language field will change a little, because the 'field-language-display' wrapper will be gone.

API changes

The 'field-language-display' wrapper will be gone. However, this fixes a potential issue with having multiple same ID's on the same page, e.g. on a node list.

Data model changes

None

Release notes snippet

Through the removal of the hardcoded display of the langcode field, are <a href="https://www.drupal.org/node/3325438">developers be able to provide new formatters</a>, so that sitebuilder can configure a different output.

-- Original report --

Any options that are selected for language field formatter are ignored and the language field is always displayed as plain text language name.

Steps to reproduce:

  1. Enable translations.
  2. Create translatable content type.
  3. Select language field to be displayed.
  4. Check formatter option "Link to the Content".
  5. Create new node.
  6. View the node and you'll see plain text language name instead of a link.

I have noticed this when I was writing custom field formatter for the language field. It's easy to see the problem once you try to change the output for the core's language field. For example try this formatter:

namespace Drupal\custom_formatter\Plugin\Field\FieldFormatter;

use Drupal\Core\Field\FieldItemInterface;
use Drupal\Core\Field\Plugin\Field\FieldFormatter\LanguageFormatter as BaseFormatter;

/**
 * Plugin implementation of the 'custom_formatter' formatter.
 *
 * @FieldFormatter(
 *   id = "language_custom_fomatter",
 *   label = @Translation("Language with flag"),
 *   field_types = {
 *     "language"
 *   }
 * )
 */
class LanguageCustomFormatter extends BaseFormatter {

  /**
   * {@inheritdoc}
   */
  protected function viewValue(FieldItemInterface $item) {
    $view = parent::viewValue($item);

    $view['#plain_text'] .= ' Test';

    return $view;
  }
}

The formatter itself is registered correctly, you can enable it for the language field. The settings form works fine, but the actual output of the formatter is totally ignored. For example instead of seeing "English Test" I always get "English".

πŸ› Bug report
Status

Needs work

Version

10.1 ✨

Component
Node systemΒ  β†’

Last updated about 5 hours ago

No maintainer
Created by

πŸ‡΅πŸ‡±Poland SiliconMind

Live updates comments and jobs are added and updated live.
  • D8MI

    (Drupal 8 Multilingual Initiative) is the tag used by the multilingual initiative to mark core issues (and some contributed module issues). For versions other than Drupal 8, use the i18n (Internationalization) tag on issues which involve or affect multilingual / multinational support. That is preferred over Translation.

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.

  • πŸ‡¨πŸ‡΄Colombia jidrone

    Added test for the post_update.

  • πŸ‡¨πŸ‡΄Colombia jidrone

    Git was recognizing one file as binary when it generates the patch, by I found a workaround.

  • πŸ‡¨πŸ‡΄Colombia jidrone

    Fixed CS error.

  • πŸ‡¨πŸ‡΄Colombia jidrone

    Those dump files for update tests produce a lot of weird errors, hopefully I fixed all.

  • πŸ‡¨πŸ‡΄Colombia jidrone

    Maybe disabling the Spell check on some config imports.

    Interdiff agains 83 because 84 didn't improve the issue.

  • πŸ‡ΊπŸ‡ΈUnited States smustgrave

    +1 for me but will let someone else see what they think.

  • Status changed to Needs work almost 2 years ago
  • πŸ‡ΊπŸ‡ΎUruguay rpayanm

    I tested manually the patch from #85.

    Test #1
    1. I used an empty Drupal 10.1.x
    2. Applied the patch
    3. Installed Drupal
    4. Followed the patch from the IS

    It worked as expected.

    Test #2:
    1. I used an empty Drupal 10.1.x
    2. Installed Drupal
    3. Followed the steps from IS
    4. Applied the patch from the IS
    5. Ran "drush updb".

    It worked as expected, but I had to repeat the step 4: Check formatter option "Link to the Content", because it was unchecked after the update.

    Let me know if I did something wrong.

  • Status changed to Needs review almost 2 years ago
  • πŸ‡¨πŸ‡΄Colombia jidrone

    Hi rpayanm,

    That's the expected behavior after running the update, because it sets the formatter to match the hardcoded values to avoid unintended results on existing sites using that formatter.

  • Status changed to RTBC almost 2 years ago
  • πŸ‡ΊπŸ‡ΎUruguay rpayanm

    Oh ok, thank you.

  • Status changed to Needs work over 1 year ago
  • πŸ‡¬πŸ‡§United Kingdom catch

    #2226493: Apply formatters and widgets to Node base fields β†’ says it covered this, but looks like it didn't?

    1. +++ b/core/modules/language/language.post_update.php
      @@ -13,3 +16,32 @@ function language_removed_post_updates() {
      +
      +/**
      + * Set language form display component as plain text and with label above.
      + */
      +function language_post_update_language_component_plain_text(&$sandbox = []) {
      +  $config_entity_updater = \Drupal::classResolver(ConfigEntityUpdater::class);
      +
      +  $callback = function (EntityViewDisplayInterface $view_display) {
      +    // Only update node view modes.
      +    if ($view_display->getTargetEntityTypeId() !== 'node') {
      +      return FALSE;
      +    }
      +    // Update language component if present.
      +    if ($view_display->getComponent('langcode')) {
      +      // Set label above as it was.
      +      $langcode['label'] = 'above';
      +      // Set to show it as plain text.
      +      $langcode['settings'] = [
      +        'link_to_entity' => FALSE,
      +        'native_language' => FALSE,
      +      ];
      +      $view_display->setComponent('langcode', $langcode);
      +      return TRUE;
      +    }
      +    return FALSE;
      +  };
      +
      +  $config_entity_updater->update($sandbox, 'entity_view_display', $callback);
      

      The logic here also needs to run in config entity presave so that it's applied to configuration shipped with modules and install profiles. Quite a lot of examples of this in 9.5 and 10.1, especially but not exclusively in views.

    2. +++ b/core/modules/node/src/NodeViewBuilder.php
      @@ -41,16 +41,6 @@ public function buildComponents(array &$build, array $entities, array $displays,
       
      -      // 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>',
      -        ];
      -      }
           }
      

      Does the configured formatter end up in the same place in the render array?

Production build 0.71.5 2024