5

Looking for a way to change between languages on our site, the Drupal 8s LanguageManager doesn't seem to have a straightforward method for this. We cannot use URL-switching, just want to do this through code.

So we want to go from "en" to "fr" for instance. Is there a method like "setCurrentLanguage" available somewhere?

3
  • You can take a look to core/modules/language/src/Plugin/Block/LanguageBlock.php this is responsible for the menu to change language.
    – rpayanm
    Commented Apr 23, 2015 at 13:00
  • Thanks but I still cannot find anything (except for a class called language-switcher) which gives me an indication how to actually change the language.
    – Undrium
    Commented Apr 23, 2015 at 14:00
  • I meant I could only find a markup with the class "language-switcher", not an actual class in php. :)
    – Undrium
    Commented Apr 24, 2015 at 12:21

4 Answers 4

6

You can change the current language to $lang_code with the following code.

$lang_code = 'fr';     
\Drupal::configFactory()->getEditable('system.site')->set('default_langcode', $lang_code)->save();
3
  • 4
    How is this the accepted answer? This will permanently change the default language of the site, not switch the current language.
    – Chris
    Commented Oct 28, 2020 at 7:01
  • @Chris , 4 years and 1 month ago :). but what do you mean by switching the current language? what is the current language? isn't it the default language of the website?
    – Yuseferi
    Commented Oct 28, 2020 at 10:23
  • 2
    Current language is the currently active language for the user, not the default language of the site. I can recommend Colin Shipton's answer.
    – hoanns
    Commented Aug 15, 2021 at 9:47
13

In a custom module, you should use a custom LanguageNegotiator and assign it to your LanguageManager, using LanguageManager->setNegotiator();

1) First, you must define a CustomLanguageNegotiator, which overwrites initializeType() method. That method should return a Language object, which you can externally define using a custom setLanguageCode() method:

<?php

namespace Drupal\custom_module\Language;


/**
 * Class responsible for performing language negotiation.
 */
class CustomLanguageNegotiator extends \Drupal\language\LanguageNegotiator {

    var $languageCode = NULL;

    /**
     * {@inheritdoc}
     */
    public function initializeType($type) {
        $language = NULL;
        $method_id = static::METHOD_ID;
        $availableLanguages = $this->languageManager->getLanguages();

        if ($this->languageCode && isset($availableLanguages[$this->languageCode])) {
            $language = $availableLanguages[$this->languageCode];
        }
        else {
            // If no other language was found use the default one.
            $language = $this->languageManager->getDefaultLanguage();
        }

        return array($method_id => $language);
    }

    /**
     * @param string $languageCode
     */
    public function setLanguageCode($languageCode)
    {
        $this->languageCode = $languageCode;
    }


}

2) Define your CustomLanguageNegotiator as a service, in your custom module service file, "custom_module.services.yml":

custom_module.language_negotiator:
  class: Drupal\custom_module\Language\CustomLanguageNegotiator
  arguments: ['@language_manager', '@plugin.manager.language_negotiation_method', '@config.factory', '@settings', '@request_stack']
  calls:
    - [initLanguageManager]

3) Rebuild your cache and use your CustomLanguageNegotiator like this:

$languageManager = \Drupal::languageManager();
$customLanguageNegotiator = \Drupal::service('custom.language_negotiator');
$languageManager->setNegotiator($customLanguageNegotiator);


// Set new language by its langcode
$languageManager->reset(); // Needed to re-run language negotiation
$languageManager->getNegotiator()->setLanguageCode('fr'); // 'en', 'es', 'fr', etc

// Run any code, and its output will be displayed in french
// ...

$languageManager->reset(); 
$languageManager->getNegotiator()->setLanguageCode('en');

// Run any code, and its output will be displayed in english
// ...

// Do not forget to set language to its initial value
$languageManager->reset(); 
$languageManager->getNegotiator()->setLanguageCode('XX');
3
  • Is it possible that there is some missing part to this howto? I don't have success when letting the renderer render twigs containing the |t filter... Commented May 27, 2020 at 10:22
  • I also can't get this to have any effect with twig templates
    – Chris
    Commented Oct 28, 2020 at 7:13
  • @informatik-handwerk.de, I found out here that t() or |t stores the language in its own service where you need to set the langcode, too.
    – 4uk4
    Commented Mar 10, 2023 at 9:34
8

Best way is to create a new Language Negotiation plugin, create a new file in a custom module in the folder src/Plugin/LanguageNegotiation, to keep with naming convention I called my class LanguageNegotiationXXX, the contents of this file should be:

<?php

namespace Drupal\my_module\Plugin\LanguageNegotiation;

use Drupal\language\LanguageNegotiationMethodBase;
use Symfony\Component\HttpFoundation\Request;

/**
 * Custom class for identifying language.
 *
 * @LanguageNegotiation(
 *   id = Drupal\my_module\Plugin\LanguageNegotiation\LanguageNegotiationXXX::METHOD_ID,
 *   weight = -99,
 *   name = @Translation("XXX Language Switching"),
 *   description = @Translation("Language based on XXX."),
 * )
 */
class LanguageNegotiationXXX extends LanguageNegotiationMethodBase {

  /**
   * The language negotiation method id.
   */
  const METHOD_ID = 'language-XXX';

  /**
   * {@inheritdoc}
   */
  public function getLangcode(Request $request = NULL) {
    $langcode = NULL;

    // Custom logic goes here, but should set a langcode such as fr

    return $langcode;
  }

}

Enable module or clear caches for this to take effect, go to admin/config/regional/language/detection and enable your new detection method.

This worked perfectly for me with all users, all the other methods I tried didn't work with anonymous users.

1
  • 2
    Thanks, @Colin Shipton! This plugin approach worked for me, and it's consistent with how the Drupal core language negotiators are implemented. I recommend. Commented May 27, 2021 at 12:11
1

A little bit or research lead me to the settings under configuration "Languages" then "Detection and selection". Removed the option "URL" and selected "Session". I wanted this solution to be as flexible as possible so I made an action in a controller which did this (along with the applications language switching logic):

    $config = \Drupal::config('language.negotiation')->get('session');
    $param = $config['parameter'];
    //Just set it BRUTALLY!
    $_SESSION[$param] = $language;

This works like a charm, feels sort of nude to just set the session to notify Drupal but it's allright. My flow was basically, call the controller action with an XMLrequest, once done reload the website and language changed.

3
  • 1
    What is $language? A language code?
    – leymannx
    Commented Oct 9, 2018 at 8:40
  • The downside is (like you said) you need to reload the webpage after that for drupal to detect the new language. The solution from Colin Shipton works without needing to do that.
    – hoanns
    Commented Aug 15, 2021 at 9:43
  • @leymannx, correct, sorry for late answer "en", "sv", "de" etc.
    – Undrium
    Commented Aug 16, 2021 at 8:25

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.