<?php

namespace Drupal\language\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;

/**
 * Determines the language to be assigned to URLs when none is detected.
 *
 * The language negotiation process has a fallback chain that ends with the
 * default language negotiation method. Each built-in language type has a
 * separate initialization:
 * - Interface language, which is the only configurable one, always gets a valid
 *   value. If no request-specific language is detected, the default language
 *   will be used.
 * - Content language merely inherits the interface language by default.
 * - URL language is detected from the requested URL and will be used to rewrite
 *   URLs appearing in the page being rendered. If no language can be detected,
 *   there are two possibilities:
 *   - If the default language has no configured path prefix or domain, then the
 *     default language is used. This guarantees that (missing) URL prefixes are
 *     preserved when navigating through the site.
 *   - If the default language has a configured path prefix or domain, a
 *     requested URL having an empty prefix or domain is an anomaly that must be
 *     fixed. This is done by introducing a prefix or domain in the rendered
 *     page matching the detected interface language.
 */
#[LanguageNegotiation(
  id: LanguageNegotiationUrlFallback::METHOD_ID,
  name: new TranslatableMarkup('URL fallback'),
  types: [LanguageInterface::TYPE_URL],
  weight: 8,
  description: new TranslatableMarkup('Use an already detected language for URLs if none is found.'),
)]
class LanguageNegotiationUrlFallback extends LanguageNegotiationMethodBase {

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

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

    if ($this->languageManager) {
      $default = $this->languageManager->getDefaultLanguage();
      $config = $this->config->get('language.negotiation')->get('url');
      $prefix = ($config['source'] == LanguageNegotiationUrl::CONFIG_PATH_PREFIX);

      // If the default language is not configured to convey language
      // information, a missing URL language information indicates that URL
      // language should be the default one, otherwise we fall back to an
      // already detected language.
      if (($prefix && empty($config['prefixes'][$default->getId()])) || (!$prefix && empty($config['domains'][$default->getId()]))) {
        $langcode = $default->getId();
      }
      else {
        $langcode = $this->languageManager->getCurrentLanguage()->getId();
      }
    }

    return $langcode;
  }

}
