Verified Commit ea0226fd authored by Théodore Biadala's avatar Théodore Biadala
Browse files

Issue #3531600 by catch, berdir: Refactor _ckeditor5_get_langcode_mapping()

(cherry picked from commit 2592e8ba)
parent c4340b27
Loading
Loading
Loading
Loading
Loading
+11 −40
Original line number Diff line number Diff line
@@ -16,6 +16,7 @@
use Drupal\Core\Ajax\ReplaceCommand;
use Drupal\Core\Ajax\RemoveCommand;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Language\LanguageManagerInterface;

/**
 * Form submission handler for filter format forms.
@@ -148,50 +149,20 @@ function _update_ckeditor5_html_filter(array $form, FormStateInterface $form_sta
 *
 * @return array|mixed|string
 *   The associated CKEditor 5 langcode.
 *
 * @deprecated in drupal:11.3.0 and is removed from drupal:12.0.0. Use
 * \Drupal\Core\Language\LanguageManagerInterface instead.
 *
 * @see https://www.drupal.org/node/3531600
 */
function _ckeditor5_get_langcode_mapping($lang = FALSE) {
  // Cache the file system based language list calculation because this would
  // be expensive to calculate all the time. The cache is cleared on core
  // upgrades which is the only situation the CKEditor file listing should
  // change.
  $langcode_cache = \Drupal::cache()->get('ckeditor5.langcodes');
  if (!empty($langcode_cache)) {
    $langcodes = $langcode_cache->data;
  }
  if (empty($langcodes)) {
    $langcodes = [];
    // Collect languages included with CKEditor 5 based on file listing.
    $files = scandir('core/assets/vendor/ckeditor5/ckeditor5-dll/translations');
    foreach ($files as $file) {
      if (str_ends_with($file, '.js')) {
        $langcode = basename($file, '.js');
        $langcodes[$langcode] = $langcode;
      }
    }
    \Drupal::cache()->set('ckeditor5.langcodes', $langcodes);
  }

  // Get language mapping if available to map to Drupal language codes.
  // This is configurable in the user interface and not expensive to get, so
  // we don't include it in the cached language list.
  $language_mappings = \Drupal::moduleHandler()->moduleExists('language') ? language_get_browser_drupal_langcode_mappings() : [];
  foreach ($langcodes as $langcode) {
    // If this language code is available in a Drupal mapping, use that to
    // compute a possibility for matching from the Drupal langcode to the
    // CKEditor langcode.
    // For instance, CKEditor uses the langcode 'no' for Norwegian, Drupal
    // uses 'nb'. This would then remove the 'no' => 'no' mapping and
    // replace it with 'nb' => 'no'. Now Drupal knows which CKEditor
    // translation to load.
    if (isset($language_mappings[$langcode]) && !isset($langcodes[$language_mappings[$langcode]])) {
      $langcodes[$language_mappings[$langcode]] = $langcode;
      unset($langcodes[$langcode]);
    }
  }
  @trigger_error('_ckeditor5_get_langcode_mapping() is deprecated in drupal:11.3.0 and is removed from drupal:13.0.0. Use \Drupal\Core\Language\LanguageManagerInterface instead. See https://www.drupal.org/node/3531600', E_USER_DEPRECATED);
  if ($lang) {
    return $langcodes[$lang] ?? 'en';
    return \Drupal::service(LanguageManagerInterface::class)->getMapping($lang);
  }
  else {
    return \Drupal::service(LanguageManagerInterface::class)->getMappings();
  }
  return $langcodes;
}

/**
+2 −0
Original line number Diff line number Diff line
@@ -22,3 +22,5 @@ services:
  logger.channel.ckeditor5:
    parent: logger.channel_base
    arguments: [ 'ckeditor5' ]
  Drupal\ckeditor5\LanguageMapper:
    autowire: true
+9 −2
Original line number Diff line number Diff line
@@ -2,6 +2,7 @@

namespace Drupal\ckeditor5\Hook;

use Drupal\ckeditor5\LanguageMapper;
use Drupal\Core\Hook\Order\OrderAfter;
use Drupal\Core\Language\LanguageInterface;
use Drupal\Core\Asset\AttachedAssetsInterface;
@@ -22,6 +23,12 @@ class Ckeditor5Hooks {

  use StringTranslationTrait;

  public function __construct(
    protected LanguageMapper $languageMapper,
  ) {

  }

  /**
   * Implements hook_help().
   */
@@ -234,7 +241,7 @@ public function libraryInfoAlter(&$libraries, $extension): void {
      return;
    }
    // All possibles CKEditor 5 languages that can be used by Drupal.
    $ckeditor_langcodes = array_values(_ckeditor5_get_langcode_mapping());
    $ckeditor_langcodes = array_values($this->languageMapper->getMappings());
    if ($extension === 'core') {
      // Generate libraries for each of the CKEditor 5 translation files so that
      // the correct translation file can be attached depending on the current
@@ -329,7 +336,7 @@ public function jsAlter(&$javascript, AttachedAssetsInterface $assets, LanguageI
      if (!\Drupal::moduleHandler()->moduleExists('locale')) {
        return;
      }
      $ckeditor5_language = _ckeditor5_get_langcode_mapping($language->getId());
      $ckeditor5_language = $this->languageMapper->getMapping($language->getId());
      // Remove all CKEditor 5 translations files that are not in the current
      // language.
      foreach ($javascript as $index => &$item) {
+96 −0
Original line number Diff line number Diff line
<?php

declare(strict_types=1);

namespace Drupal\ckeditor5;

use Drupal\Core\Cache\BackendChain;
use Drupal\Core\Cache\CacheBackendInterface;
use Drupal\Core\Extension\ModuleHandlerInterface;
use Symfony\Component\DependencyInjection\Attribute\Autowire;

/**
 * Manages language mappings and discovery for ckeditor translations.
 */
class LanguageMapper {

  /**
   * Cache backend.
   */
  protected BackendChain $cache;

  public function __construct(
    #[Autowire('@cache.discovery')]
    CacheBackendInterface $persistent_cache,
    #[Autowire('@cache.memory')]
    CacheBackendInterface $memory_cache,
    protected ModuleHandlerInterface $moduleHandler,
  ) {
    $this->cache = new BackendChain();
    $this->cache->appendBackend($memory_cache);
    $this->cache->appendBackend($persistent_cache);
  }

  /**
   * Returns a list of language codes supported by CKEditor 5.
   *
   * @return array
   *   The CKEditor 5 language codes.
   */
  public function getMappings(): array {
    // Cache the file system based language list calculation because this would
    // be expensive to calculate all the time. The cache is cleared on core
    // upgrades which is the only situation the CKEditor file listing should
    // change.
    $langcode_cache = $this->cache->get('ckeditor5.langcodes');
    if (!empty($langcode_cache)) {
      $langcodes = $langcode_cache->data;
    }
    if (empty($langcodes)) {
      $langcodes = [];
      // Collect languages included with CKEditor 5 based on file listing.
      $files = scandir('core/assets/vendor/ckeditor5/ckeditor5-dll/translations');
      foreach ($files as $file) {
        if (str_ends_with($file, '.js')) {
          $langcode = basename($file, '.js');
          $langcodes[$langcode] = $langcode;
        }
      }

      $this->cache->set('ckeditor5.langcodes', $langcodes);
    }

    // Get language mapping if available to map to Drupal language codes.
    // This is configurable in the user interface and not expensive to get, so
    // we don't include it in the cached language list.
    $language_mappings = $this->moduleHandler->moduleExists('language') ? language_get_browser_drupal_langcode_mappings() : [];
    foreach ($langcodes as $langcode) {
      // If this language code is available in a Drupal mapping, use that to
      // compute a possibility for matching from the Drupal langcode to the
      // CKEditor langcode.
      // For instance, CKEditor uses the langcode 'no' for Norwegian, Drupal
      // uses 'nb'. This would then remove the 'no' => 'no' mapping and
      // replace it with 'nb' => 'no'. Now Drupal knows which CKEditor
      // translation to load.
      if (isset($language_mappings[$langcode]) && !isset($langcodes[$language_mappings[$langcode]])) {
        $langcodes[$language_mappings[$langcode]] = $langcode;
        unset($langcodes[$langcode]);
      }
    }
    return $langcodes;
  }

  /**
   * Returns a specific ckeditor langcode based on the requested one.
   *
   * @param string $langcode
   *   The Drupal langcode to match.
   *
   * @return string
   *   The associated CKEditor 5 langcode.
   */
  public function getMapping(string $langcode): string {
    return $this->getMappings()[$langcode] ?? 'en';
  }

}
+20 −4
Original line number Diff line number Diff line
@@ -5,6 +5,7 @@
namespace Drupal\ckeditor5\Plugin\Editor;

use Drupal\ckeditor5\HTMLRestrictions;
use Drupal\ckeditor5\LanguageMapper;
use Drupal\ckeditor5\Plugin\CKEditor5Plugin\Heading;
use Drupal\ckeditor5\Plugin\CKEditor5PluginDefinition;
use Drupal\ckeditor5\Plugin\CKEditor5PluginManagerInterface;
@@ -105,6 +106,13 @@ class CKEditor5 extends EditorBase implements ContainerFactoryPluginInterface {
   */
  protected $logger;

  /**
   * The ckeditor language mapper.
   *
   * @var \Drupal\ckeditor5\LanguageMapper
   */
  protected LanguageMapper $languageMapper;

  /**
   * Constructs a CKEditor 5 editor plugin.
   *
@@ -126,8 +134,10 @@ class CKEditor5 extends EditorBase implements ContainerFactoryPluginInterface {
   *   The cache.
   * @param \Psr\Log\LoggerInterface $logger
   *   A logger instance.
   * @param \Drupal\ckeditor5\LanguageMapper $languageMapper
   *   The ckeditor language mapper.
   */
  public function __construct(array $configuration, $plugin_id, $plugin_definition, CKEditor5PluginManagerInterface $ckeditor5_plugin_manager, LanguageManagerInterface $language_manager, ModuleHandlerInterface $module_handler, SmartDefaultSettings $smart_default_settings, CacheBackendInterface $cache, LoggerInterface $logger) {
  public function __construct(array $configuration, $plugin_id, $plugin_definition, CKEditor5PluginManagerInterface $ckeditor5_plugin_manager, LanguageManagerInterface $language_manager, ModuleHandlerInterface $module_handler, SmartDefaultSettings $smart_default_settings, CacheBackendInterface $cache, LoggerInterface $logger, LanguageMapper $languageMapper) {
    parent::__construct($configuration, $plugin_id, $plugin_definition);
    $this->ckeditor5PluginManager = $ckeditor5_plugin_manager;
    $this->languageManager = $language_manager;
@@ -135,6 +145,11 @@ public function __construct(array $configuration, $plugin_id, $plugin_definition
    $this->smartDefaultSettings = $smart_default_settings;
    $this->cache = $cache;
    $this->logger = $logger;
    if (!$languageMapper) {
      @trigger_error('Calling ' . __METHOD__ . ' without the $languageMapper argument is deprecated in drupal:11.3.0 and it will be required in drupal:12.0.0. See https://www.drupal.org/node/3551652', E_USER_DEPRECATED);
      $languageMapper = \Drupal::service(LanguageMapper::class);
    }
    $this->languageMapper = $languageMapper;
  }

  /**
@@ -150,7 +165,8 @@ public static function create(ContainerInterface $container, array $configuratio
      $container->get('module_handler'),
      $container->get('ckeditor5.smart_default_settings'),
      $container->get('cache.default'),
      $container->get('logger.channel.ckeditor5')
      $container->get('logger.channel.ckeditor5'),
      $container->get(LanguageMapper::class)
    );
  }

@@ -930,7 +946,7 @@ public function getJSSettings(EditorEntity $editor) {

    if ($this->moduleHandler->moduleExists('locale')) {
      $language_interface = $this->languageManager->getCurrentLanguage();
      $settings['language']['ui'] = _ckeditor5_get_langcode_mapping($language_interface->getId());
      $settings['language']['ui'] = $this->languageMapper->getMapping($language_interface->getId());
    }

    return $settings;
@@ -944,7 +960,7 @@ public function getLibraries(EditorEntity $editor) {

    if ($this->moduleHandler->moduleExists('locale')) {
      $language_interface = $this->languageManager->getCurrentLanguage();
      $plugin_libraries[] = 'core/ckeditor5.translations.' . _ckeditor5_get_langcode_mapping($language_interface->getId());
      $plugin_libraries[] = 'core/ckeditor5.translations.' . $this->languageMapper->getMapping($language_interface->getId());
    }

    return $plugin_libraries;
Loading