1

I have a multilingual site with 2 languages (English and French) and 4 ISO codes (us, gb, fr, and be). I want Drupal to understand that /us and /gb are aliases for /en. (They share the same content.)

Is there a way to programmatically achieve this?

2

I was able to achieve what I wanted using the following service.

services.yml

mymodule.path_processor:
  class: Drupal\mymodule\PathProcessor\PathProcessor
  arguments: ['@language_manager', '@config.factory', '@path.alias_manager']
  tags:
    - { name: path_processor_inbound, priority: 200 }

PathProcessor.php

/**
 * Processes the inbound path using path alias lookups.
 */
class PathProcessorCustom implements InboundPathProcessorInterface, OutboundPathProcessorInterface {

  protected $language_manager;
  protected $configFactory;
  protected $aliasManager;

  public function __construct(LanguageManagerInterface $language_manager, ConfigFactoryInterface $config_factory, AliasManagerInterface $alias_manager) {
    $this->languageManager = $language_manager;
    $this->configFactory = $config_factory;
    $this->aliasManager = $alias_manager;
  }

  public function processInbound($path, Request $request) {
    if (!strpos($path, '/admin/')) {
      $path = $this->removeISOCode($path);
    }

    return $path;
  }

  public function processOutbound($path, &$options = array(), Request $request = NULL, BubbleableMetadata $bubbleable_metadata = NULL) {
    if (!strpos($path, '/admin/')) {
      $path = $this->insertISOCode($path);
    }

    return $path;
  }

  protected function removeISOCode($path) {
    $langcode = $this->languageManager
      ->getDefaultLanguage()
      ->getId();
    $isocodes = $this->getISOCodeMapping();
    $path_items = explode('/', $path);
    if (isset($path_items[1]) && strlen($path_items[1]) == 2 && in_array($path_items[1], $isocodes[$langcode])) {
      $config_negotiation_url = $this->configFactory->get('language.negotiation')->get('url');
      if (!in_array($path_items[1], $config_negotiation_url['prefixes'])) {
        array_splice($path_items, 1, 1);
        if (count($path_items) == 1) {
          $config_system_site = $this->configFactory->get('system.site')->get('page');
          $path = $config_system_site['front'];
        }
        else {
          $path = implode('/', $path_items);
          $path = $this->aliasManager->getPathByAlias($path, 'en');
        }
      }
    }

    return $path;
  }

  protected function insertISOCode($path) {
    $path_items = explode('/', $path);
    if (isset($path_items[1]) && strlen($path_items[1]) == 2 && $path_items[1] == 'gb') {
      $config_negotiation_url = $this->configFactory->get('language.negotiation')->get('url');
      if (!in_array($path_items[1], $config_negotiation_url['prefixes'])) {
        $path_items[1] = $language;
      }
    }

    return implode('/', $path_items);
  }
    
  protected function getISOCodeMapping() {
    return [
      'en' => ['gb', 'us'],
      'fr' => ['fr', 'be']
    ];
  }

}

What I do is decompose the URL, remove what I know I don't need, and map the URL to an actual content URL.

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.