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?

  • You can take a look to core/modules/language/src/Plugin/Block/LanguageBlock.php this is responsible for the menu to change language. – rpayanm Apr 23 '15 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 Apr 23 '15 at 14:00
  • I meant I could only find a markup with the class "language-switcher", not an actual class in php. :) – Undrium Apr 24 '15 at 12:21
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();
6

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

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

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.

  • What is $language? A language code? – leymannx Oct 9 '18 at 8:40

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.