Skip to content

Instantly share code, notes, and snippets.

@webflo
Created April 26, 2026 04:58
Show Gist options
  • Select an option

  • Save webflo/af03a8d49cd546ead4903669fe9dadf8 to your computer and use it in GitHub Desktop.

Select an option

Save webflo/af03a8d49cd546ead4903669fe9dadf8 to your computer and use it in GitHub Desktop.
MailLanguageManager and LanguageNegotiationMail
<?php
namespace Drupal\example\Plugin\LanguageNegotiation;
use Drupal\Core\Language\LanguageInterface;
use Drupal\Core\StringTranslation\TranslatableMarkup;
use Drupal\language\Attribute\LanguageNegotiation;
use Drupal\language\LanguageNegotiationMethodBase;
use Symfony\Component\HttpFoundation\Request;
#[LanguageNegotiation(
id: LanguageNegotiationMail::METHOD_ID,
name: new TranslatableMarkup('Mail'),
types: [
LanguageInterface::TYPE_INTERFACE,
LanguageInterface::TYPE_CONTENT,
LanguageInterface::TYPE_URL,
],
weight: -50,
description: new TranslatableMarkup("Language from context (for Mail rendering).")
)]
class LanguageNegotiationMail extends LanguageNegotiationMethodBase {
/**
* The language negotiation method id.
*/
const string METHOD_ID = 'language-mail';
const string REQUEST_ATTRIBUTE = 'example_module_mail_langcode';
public function getLangcode(?Request $request = NULL) {
return $request?->attributes->get($this::REQUEST_ATTRIBUTE);
}
}
<?php
namespace Drupal\example;
use Drupal\example\Plugin\LanguageNegotiation\LanguageNegotiationMail;
use Drupal\Core\Cache\MemoryCache\MemoryCacheInterface;
use Drupal\Core\DependencyInjection\AutowireTrait;
use Drupal\Core\Entity\EntityFieldManagerInterface;
use Drupal\Core\Language\LanguageManagerInterface;
use Drupal\Core\StringTranslation\TranslationInterface;
use Drupal\Core\TypedData\TypedDataManager;
use Drupal\Core\TypedData\TypedDataManagerInterface;
use Drupal\language\EventSubscriber\LanguageRequestSubscriber;
use Drupal\language\LanguageNegotiatorInterface;
use Symfony\Component\DependencyInjection\Attribute\Autowire;
class MailLanguageManager {
use AutowireTrait;
public function __construct(
protected LanguageManagerInterface $languageManager,
#[Autowire(service: 'string_translation')]
protected TranslationInterface $stringTranslation,
protected LanguageNegotiatorInterface $languageNegotiator,
#[Autowire(service: 'language_request_subscriber')]
protected LanguageRequestSubscriber $languageRequestSubscriber,
protected TypedDataManagerInterface $typedDataManager,
protected EntityFieldManagerInterface $entityFieldManager,
#[Autowire(service: 'entity.memory_cache')]
protected MemoryCacheInterface $entityMemoryCache,
) {
}
public function reset() {
\Drupal::request()->attributes->remove(LanguageNegotiationMail::REQUEST_ATTRIBUTE);
$this->languageRequestSubscriber->onContainerInitializeSubrequestFinished();
// Clear prototype cache in typed data manager.
// @see https://www.drupal.org/i/2276749
// @see https://www.drupal.org/i/3221375
$resetPrototypes = \Closure::bind(
function (): void {
$this->prototypes = [];
},
$this->typedDataManager,
$this->typedDataManager
);
$resetPrototypes();
// Rest options_allowed_values, because is not language aware.
drupal_static_reset('options_allowed_values');
// Flush cache in EntityFieldManager
// \Drupal\Core\Entity\EntityFieldManager::getBaseFieldDefinitions has a
// static cache and it not language aware.
$this->entityFieldManager->useCaches(FALSE);
$this->entityFieldManager->useCaches(TRUE);
$this->entityMemoryCache->deleteAll();
}
public function setLanguage($langcode) {
$this->reset();
\Drupal::request()->attributes->set(LanguageNegotiationMail::REQUEST_ATTRIBUTE, $langcode);
$this->languageRequestSubscriber->onContainerInitializeSubrequestFinished();
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment