I use translation, locale and i18n. I want to change the language switcher block (id="block-locale-language").

The language links look like this at default:

<div class="content">
  <ul class="language-switcher-locale-url">
    <li class="en first active"><a href="/en" class="language-link active">English</a></li>
    <li class="fr"><a href="/fr" class="language-link">Français</a></li>
    <li class="de last"><a href="/de" class="language-link">Deutsch</a></li>
  </ul>
</div>

I want to change the links to this (example for the French link):

    <li class="fr last"><a href="/fr" class="language-link"><abbr title="Français">fr</abbr></a></li>

(I added a <abbr> element; the language's label is the title value, the language shortcode is the content of the abbr)

I have no idea how to accomplish that (never worked with coding/theming much).

I can overwrite the block with block--locale.tpl.php, but how do I access the HTML markup of the links?

Comments

VM’s picture

may be worth checking the module to see if there is a theme function
copy it to template.php of your theme
override it and change what you need to change

may also want to investigate preprocess functions

no2e’s picture

Sorry, I have no experience with this topic …

may be worth checking the module to see if there is a theme function

Hm, how can I spot theme functions? And in which files (inside of the module's folder) should I look for it?

VM’s picture

theme functions start with the word theme

I suggest the devel.module and learning how to work with it and the docs for themeing http://drupal.org/theme-guide/6-7

There is a section in the above link which discusses overrding/modifying theme output.

idflood’s picture

It's a bit late, but it may be useful for others.

In your theme template.php, add this function and then clear the cache. (replace yourtheme with the name of your theme)

function yourtheme_links__locale_block(&$vars) {
  foreach($vars['links'] as $language => $langInfo) {
    $abbr = $langInfo['language']->language;
    $name = $langInfo['language']->name;
    $vars['links'][$language]['title'] = '<abbr title="' . $name . '">' . $abbr . '</abbr>';
    $vars['links'][$language]['html'] = TRUE;
  }
  $content = theme_links($vars);
  return $content;
}

David Mignot
www.idflood.com
gittip

eidoscom’s picture

This is quite good, but I think that is better to set the title of the abbr to the native name of the language:

function yourtheme_links__locale_block(&$vars) {
  foreach($vars['links'] as $language => $langInfo) {
    $abbr = $langInfo['language']->language;
    $name = $langInfo['language']->native;
    $vars['links'][$language]['title'] = '<abbr title="' . $name . '">' . $abbr . '</abbr>';
    $vars['links'][$language]['html'] = TRUE;
  }
  $content = theme_links($vars);
  return $content;
}
jack-pl’s picture

Great job! but with theme_links() there is no possibility to theme li elements. If someone will need to custom all list elements (ul, li, links) then I suggest to use theme_item_list() function:

function MYTHEME_links__locale_block(&$variables) {
   
  // an array of list items
  $items = array();
  foreach($variables['links'] as $language => $info) {

      $name     = $info['language']->native;
      $href     = isset($info['href']) ? $info['href'] : '';
	  $li_classes   = array('list-item-class');
	  $link_classes = array('link-class1', 'link-class2');
      $options = array('attributes' => array('class'    => $link_classes),
                                             'language' => $info['language'],
											 'html'     => true
                                             );
      $link = l($name, $href, $options);
	
      // display only translated links
      if ($href) $items[] = array('data' => $link, 'class' => $li_classes);
    }

  // output
  $attributes = array('class' => array('my-list'));   
  $output = theme_item_list(array('items' => $items,
                                  'title' => '',
                                  'type'  => 'ul',
                                  'attributes' => $attributes
                                  ));
  return $output;
}
duncan.moo’s picture

Thanks Jack-pl that put me 99% there, just was not getting an active state for the current language, so added that in in the version below:

<?php
function MYTHEME_links__locale_block(&$variables) {
  // the global $language variable tells you what the current language is
  global $language;

  // an array of list items
  $items = array();
  foreach($variables['links'] as $lang => $info) {

      $name     = $info['language']->native;
      $href     = isset($info['href']) ? $info['href'] : '';
      $li_classes   = array('list-item-class');
      // if the global language is that of this item's language, add the active class
      if($lang === $language->language){
            $li_classes[] = 'active';
      }
      $link_classes = array('link-class1', 'link-class2');
      $options = array('attributes' => array('class'    => $link_classes),
                                             'language' => $info['language'],
                                             'html'     => true
                                             );
      $link = l($name, $href, $options);
   
      // display only translated links
      if ($href) $items[] = array('data' => $link, 'class' => $li_classes);
    }

  // output
  $attributes = array('class' => array('my-list'));  
  $output = theme_item_list(array('items' => $items,
                                  'title' => '',
                                  'type'  => 'ul',
                                  'attributes' => $attributes
                                  ));
  return $output;
}
?>

Changes:

  1. Brought in global $language variable
  2. Changed foreach key variable from $language to $lang
  3. Add active to <li> if link item is the same as the current global $language
jack-pl’s picture

Yes, you're right. Don't know how I forgot about it. Now the example is complete. Thanks.

Tubia87’s picture

Hi all,
this snippet works like a charm but: there is a way to remove the theme_item_list() wrapper

?
I think I have some problems rewriting theme_item_list()

Thank you for possible solutions :)

jack-pl’s picture

I've got two solutions:

Solution #1:
You can copy theme_item_list() and place into the template.php file (replace 'theme' for your_theme_name) but in this way you will remove the div wherever theme_item_list() will be called.

Solution #2:
Create a module and put the language switcher stuff there.

Module files:

file: custom_language_switcher.info

name = Custom language switcher
description = Custom Language Switcher and Links
dependencies[] = locale
package = My custom modules
core = 7.x
files[] = custom_language_switcher.module

file: custom_language_switcher.module

/**
 * @file
 * Custom language switcher and links
 */

/**
 * Implements hook_theme()
 */
function custom_language_switcher_theme() {
  return array(
    'custom_language_switcher_item_list' => array(
      'variables' => array(
        'items' => NULL,
        'title' => NULL,
        'type' => NULL,
        'attributes' => NULL,
        'wrapper' => NULL
      )
    ),
    'custom_language_switcher_links' => array(
      'variables' => array(
        'links' => NULL,
        'attributes' => NULL,
        'heading' => NULL
      )
    )									 
  );
}

/**
 * Implements hook_theme_registry_alter for theme_links()
 */
function custom_language_switcher_theme_registry_alter(&$theme_registry) {

  $mod_path = drupal_get_path('module', 'custom_language_switcher');

  if (isset($theme_registry['links'])) {	
    $theme_registry['links__locale_block']['theme path'] = $mod_path;
    $theme_registry['links__locale_block']['function'] = 'custom_language_switcher_links';
  }
}

/**
 * Custom theme_item_list()
 * The modification allows to customize the list wrapper 
 * Example:
 * theme('item_list', array(
     'items' => $items,
     'title' => 'List title',
     'type' => 'ul',
     'attributes' => $attributes,
     'wrapper' => array('type' => 'div', 'class' => array('pPanel'), 'id' => 'some_id'),
     )
   );
 */
function theme_custom_language_switcher_item_list($variables) {
  $items = $variables['items'];
  $title = $variables['title'];
  $type = $variables['type'];
  $attributes = $variables['attributes'];

  // Jack-PL: Check for the $variables array called 'wrapper'
  $wrapper = $variables['wrapper'];

  if ($wrapper) {
    $wrapper_type = array_shift($wrapper); // only the first key 'type' is required
    $wrapper_attributes = '';
    foreach ($wrapper as $key => $val) {
      if (!is_array($val)) {
        $wrapper_attributes.= ' '.$key.'="'.$val.'"';
      }
      else {
        $wrapper_attributes.= ' '.$key.'="'.implode(' ', $wrapper[$key]).'"';
      }
    }
  }

  // Only output the list container and title, if there are any list items.
  // Check to see whether the block title exists before adding a header.
  // Empty headers are not semantic and present accessibility challenges.
  // Jack-PL: Create custom wrapper
  
  $output = $wrapper ? '<'.$wrapper_type . $wrapper_attributes . '>' : '';
  if (isset($title) && $title !== '') {
    $output .= '<h3>' . $title . '</h3>';
  }
  if (!empty($items)) {
    $output .= "<$type" . drupal_attributes($attributes) . '>';
    $num_items = count($items);
    foreach ($items as $i => $item) {
      $attributes = array();
      $children = array();
      $data = '';
      if (is_array($item)) {
        foreach ($item as $key => $value) {
          if ($key == 'data') {
            $data = $value;
          }
          elseif ($key == 'children') {
            $children = $value;
          }
          else {
            $attributes[$key] = $value;
          }
        }
      }
      else {
        $data = $item;
      }
	  if (count($children) > 0) {
        // Render nested list.
        $data .= theme_item_list(array('items' => $children, 'title' => NULL, 'type' => $type, 'attributes' => $attributes));
      }
      if ($i == 0) {
        $attributes['class'][] = 'first';
      }
      if ($i == $num_items - 1) {
        $attributes['class'][] = 'last';
      }
      $output .= '<li' . drupal_attributes($attributes) . '>' . $data . "</li>\n";
    }
    $output .= "</$type>";
  }
  $output .= $wrapper ? "</$wrapper_type>" : '';
  return $output;
}

/**
 * Custom theme_links.
 */
function custom_language_switcher_links(&$variables) {

  // the global $language variable tells you what the current language is
  global $language;

  // an array of list items
  $items = array();
  foreach($variables['links'] as $lang => $info) {

    $name = $info['language']->native;
    $href = isset($info['href']) ? $info['href'] : '';
    $li_classes = array('list-item-class');
    // if the global language is that of this item's language, add the active class
    if($lang === $language->language){
      $li_classes[] = 'active';
    }
    $link_classes = array('link-class1', 'link-class2');
    $options = array(
      'attributes' => array(
        'class' => $link_classes),
        'language' => $info['language'],
        'html' => true
       );
    $link = l($name, $href, $options);

    // display only translated links
    if ($href) $items[] = array('data' => $link, 'class' => $li_classes);
  }

  // output
  $attributes = array('class' => array('my-list')); 
  $output = theme('custom_language_switcher_item_list', array(
    'items' => $items,
    'title' => '',
    'type'  => 'ul',
    'attributes' => $attributes,
    // You can define your custom wrapper if you wish (it's not required)
    'wrapper' => array(
      'type' => 'div',
      'id' => 'custom-wrapper-id',
      'class' => array('custom-wrapper-class')
    ),
  ));
  return $output;
}

/**
 * Implements hook_node_view_alter().
 */
function custom_language_switcher_node_view_alter(&$build) {
  if (isset($build['links']['translation'])) {
    $build['links'] = array(
      'translation' => array(
      '#theme' => 'links__node__translation',
      '#links' => $build['links']['translation']['#links'],
      '#attributes' => array('id' => 'translation_links', 'class' => array('links'))
      )
    );
  }
}
miksha’s picture

Only to notice that "custom_language_switcher.info" goes without PHP tags.

DieterAtWork’s picture

Hi, it seems that this doesn't work anymore, as the language isn't any more in the $info! So $info['language'] can't be used. As for just displaying the language name, I can use the 'title', but for generating the link with l(), I have to have the language in order for it to work. So if anyone can bring this solution up-to-date.

DetectivePixel’s picture

The following makes the title of the language into capital and the first two letters, can be changed accordingly.

It needs to be placed in a custom module

/**
 * Implements hook_language_switch_links_alter().
 */

function mymodule_language_switch_links_alter(array &$links, $type, $path) {
  foreach($links as $key => $link) {
    $links[$key]['title'] = strtoupper($link['language']->language);
  }
}
yvesvanlaer’s picture

Does somebody have a snippet how to get it done in Drupal 8?
Just changing the name of the language is strangely not working here.

I can't seem to find a snippet anywhere :-).

yvesvanlaer’s picture

In case anybody is looking for a snippet:
Create a module called "language_switcher_alter"

Implement the following code in your language_switcher_alter.module file.

<?php

function language_switcher_alter_language_switch_links_alter(array &$links, $type, $path) {
  foreach($links as $key => $link) {
    $links[$key]['title'] = strtoupper($link['language']->getId());
  }
}
michaellenahan’s picture

Or this:

function language_switcher_alter_language_switch_links_alter(array &$links, $type, $path) {
  foreach($links as $key => $link) {
    $links[$key]['title'] = strtoupper($key);
  }
}
sachbearbeiter’s picture

Thanks for the D8 examples ...

kubrt’s picture

After a while of D8-naive digging around I've found this line:

core/modules/language/src/Plugin/Block/LanguageBlock.php: '#theme' => 'links__language_block',

So just copy the

core/modules/system/templates/links.html.twig

into your theme's templates directory, call it

links--language-block.html.twig

and adjust its guts as needed. Twig!

kubrt’s picture

NOTE: Next time I need to find where something is coming from I'll definitely use the twig debugging feature. Just set

parameters: twig.config: debug: true

in your services.yml (the new sibbling of settings.php)

and you'll get a stream of goodness like this

<!-- FILE NAME SUGGESTIONS:
   x links--language-block.html.twig
   x links--language-block.html.twig
   * links.html.twig
-->

in a form of comments in your html source.
There used to be that useful Theme developer module. Just something that displays these twig debug comments painlessly ? Does it already exist ?