Enhancement of Language Icons Functionality for Improved Multilingual Support

Created on 1 March 2024, 4 months ago

I've made an enhancement to the Language Icons module to improve the user experience on multilingual sites. This adjustment ensures language switcher icons are only displayed when translations for the displayed content are available, now extended to include Views alongside Nodes, Commerce Products, and Taxonomy Terms. The aim is to avoid confusing end-users and improve SEO by preventing links to untranslated content. Unfortunately, I was not able to create a patch myself and believe it would be best for a developer to review these changes first.

languageicons.module

<?php

/**
 * @file
 * Main functions and hook implementations for the Language Icons module.
 *
 * This is a spin off from the Internationalization (i18n) package.
 */

declare(strict_types = 1);

use Drupal\Component\Utility\Html;
use Drupal\Core\Routing\RouteMatchInterface;
use Drupal\Core\Url;

/**
 * Implements hook_theme().
 */
function languageicons_theme() {
  return [
    'languageicons_link_content' => [
      'variables' => [
        'language' => NULL,
        'separator' => ' ',
        'text' => NULL,
        'title' => NULL,
      ],
    ],
  ];
}

/**
 * Implements hook_help().
 *
 * @todo The @handbook link needs to change to a module specific one.
 */
function languageicons_help($route_name, RouteMatchInterface $route_match): string {
  switch ($route_name) {
    case 'help.page.languageicons':
      $output = '<p>' . t('This module manages language icons for multilingual sites:') . '</p>';
      $output .= '<ul>';
      $output .= '<li>' . t('Automatically adds icons to language links.') . '</li>';
      $output .= '<li>' . t('Provides related theme functions.') . '</li>';
      $output .= '</ul>';
      $output .= '<p>' . t('For more information, please see <a href="@handbook">the online handbook section</a>.', ['@handbook' => 'http://drupal.org/node/133977']) . '</p>';
      break;

    case 'languageicons.settings':
      $output = '<p>' . t('To enable multilingual support for specific content types go to <a href="@configure_content_types">configure content types</a>.', ['@configure_content_types' => Url::fromRoute('entity.node_type.collection')->toString()]) . '</p>';
      break;

    default:
      $output = '';
  }
  return $output;
}

/**
 * Implements hook_language_switch_links_alter().
 *
 * Adds language icons to language switcher block links only if the content has translations.
 */
function languageicons_language_switch_links_alter(array &$links, $type, $path): void {
  if (\Drupal::config('languageicons.settings')->get('show_block') || \Drupal::config('languageicons.settings')->get('show_node')) {
    $route_match = \Drupal::routeMatch();
    $entity = NULL;

    // Check for node, product, and taxonomy term entities.
    if ($node = $route_match->getParameter('node')) {
      $entity = $node;
    } elseif ($product = $route_match->getParameter('commerce_product')) {
      $entity = $product;
    } elseif ($term = $route_match->getParameter('taxonomy_term')) {
      $entity = $term;
    }

    if ($entity) {
      foreach (array_keys($links) as $langcode) {
        if ($entity->hasTranslation($langcode)) {
          if (!isset($links[$langcode]['language'])) {
            $links[$langcode]['language'] = \Drupal::languageManager()->getLanguage($langcode);
          }
          languageicons_link_add($links[$langcode]);
        } else {
          unset($links[$langcode]);
        }
      }
    } else {
      // Check if the current route is for a view page without specifying a particular view
      if (strpos($route_match->getRouteName(), 'view.') === 0) {
        // Assume we want to display icons for all languages on view pages
        foreach (array_keys($links) as $langcode) {
          if (!isset($links[$langcode]['language'])) {
            $links[$langcode]['language'] = \Drupal::languageManager()->getLanguage($langcode);
          }
          languageicons_link_add($links[$langcode]);
        }
      }
    }
  }
}

/**
 * Add language icon to link.
 */
function languageicons_link_add(&$link, $title = NULL): void {
  $link['title'] = [
    '#theme' => 'languageicons_link_content',
    '#language' => $link['language_icon'] ?? $link['language'],
    '#text' => $link['title'],
    '#title' => $title ? $title : $link['title'],
  ];

  $link['html'] = TRUE;
}

/**
 * Prepares variables for rendering the content of a language link.
 */
function template_preprocess_languageicons_link_content(array &$variables): void {
  $language = $variables['language'];
  $title = $variables['title'] ? $variables['title'] : $language->getName();
  $size = \Drupal::config('languageicons.settings')->get('size');
  [$width, $height] = explode('x', $size);

  if ($path = \Drupal::config('languageicons.settings')->get('path')) {
    $variables['icon'] = [
      '#theme' => 'image',
      '#uri' => str_replace('*', $language->getId(), Html::escape($path)),
      '#alt' => $title,
      '#title' => $title,
      '#width' => $width,
      '#height' => $height,
      '#attributes' => ['class' => ['language-icon']],
    ];
  }
  else {
    throw new \Exception('Path to language icons is not defined.');
  }

  $variables['placement'] = \Drupal::config('languageicons.settings')->get('placement');
}
✨ Feature request
Status

Active

Version

2.0

Component

Code

Created by

Live updates comments and jobs are added and updated live.
Sign in to follow issues

Comments & Activities

Production build 0.69.0 2024