diff --git a/.drone.yml b/.drone.yml
index 127c9779a3a51f96779b0ad9534eec9a8dfea761..9c0a924135fee896c7a8aaf16549328e2ac0fc4d 100644
--- a/.drone.yml
+++ b/.drone.yml
@@ -120,3 +120,4 @@ matrix:
     - highest
   PHP_VERSION:
     - 7.4
+    - 8.0
diff --git a/composer.json b/composer.json
index b878e78bd2fde06a31b1bf4bbdaaee8457a3e093..f5f3d40bf69ea71d8ce0d21f798e5203a6ed404d 100644
--- a/composer.json
+++ b/composer.json
@@ -25,9 +25,11 @@
         "drupal/pathauto": "^1.8",
         "drupal/search_api": "^1.21",
         "drupal/search_api_autocomplete": "^1.5",
+        "drupal/token": "^1.10",
         "drush/drush": "^10.3",
         "easyrdf/easyrdf": "1.0.0 as 0.9.1",
         "egulias/email-validator": "^2.1.22 || ^3.0",
+        "league/csv": "^9.1",
         "nikic/php-parser": "^4.13",
         "openeuropa/code-review": "^1.7 || ^2.0",
         "openeuropa/composer-artifacts": "^1.0.0-alpha1",
@@ -40,7 +42,8 @@
         "openeuropa/oe_paragraphs": "^1.12",
         "openeuropa/oe_starter_content": "1.x-dev",
         "openeuropa/task-runner-drupal-project-symlink": "^1.0-beta5",
-        "phpspec/prophecy-phpunit": "^1 || ^2"
+        "phpspec/prophecy-phpunit": "^1 || ^2",
+        "symfony/dom-crawler": "^4.4.12"
     },
     "scripts": {
         "post-install-cmd": "./vendor/bin/run drupal:site-setup",
@@ -76,7 +79,10 @@
             "Explicit minimum version requirement of drupal/ctools module due to D9.2 compatibility.",
             "Explicit requirement for drupal/file_link due to https://www.drupal.org/project/file_link/issues/3147517. It can be removed when oe_starter_content requires oe_media version 1.15.0 or above.",
             "Explicit requirement for drupal/pathauto due to D9.2 compatibility according to https://www.drupal.org/node/2979476.",
-            "Explicit requirement for egulias/email-validator due to https://www.drupal.org/project/drupal/issues/3061074#comment-14300579. It can be removed when Drupal core 9.2 support is droppped."
+            "Explicit requirement for egulias/email-validator due to https://www.drupal.org/project/drupal/issues/3061074#comment-14300579. It can be removed when Drupal core 9.2 support is droppped.",
+            "Explicit requirement for league/csv due to PHP 8.0 compatibility",
+            "Explicit minimum version requirement for symfony/dom-crawler due to its lower versions using the deprecated function libxml_disable_entity_loader() in PHP8.",
+            "Explicit requirement of token module due to PHP 8 compatbility."
         ],
         "installer-paths": {
             "build/core": [
diff --git a/config/optional/block.block.oe_whitelabel_branding.yml b/config/optional/block.block.oe_whitelabel_branding.yml
index 4964f51fab8952fea9d923b0c807aac2a3c83e69..e860d6197e4cf0911984eb98b465d32a735fa3b6 100644
--- a/config/optional/block.block.oe_whitelabel_branding.yml
+++ b/config/optional/block.block.oe_whitelabel_branding.yml
@@ -14,8 +14,8 @@ plugin: system_branding_block
 settings:
   id: system_branding_block
   label: 'Site branding'
-  provider: system
   label_display: '0'
+  provider: system
   use_site_logo: true
   use_site_name: true
   use_site_slogan: true
diff --git a/config/optional/block.block.oe_whitelabel_breadcrumbs.yml b/config/optional/block.block.oe_whitelabel_breadcrumbs.yml
index 23f53fc397172940c16e33bbde491d518679315b..6f028eaf455e6ff1486758fdaac6e5ac5db26ae4 100644
--- a/config/optional/block.block.oe_whitelabel_breadcrumbs.yml
+++ b/config/optional/block.block.oe_whitelabel_breadcrumbs.yml
@@ -14,6 +14,6 @@ plugin: system_breadcrumb_block
 settings:
   id: system_breadcrumb_block
   label: Breadcrumbs
-  provider: system
   label_display: '0'
+  provider: system
 visibility: {  }
diff --git a/config/optional/block.block.oe_whitelabel_ec_corporate_footer.yml b/config/optional/block.block.oe_whitelabel_ec_corporate_footer.yml
index d52ef57935895e1a13ef3600f215c23beb2f1393..b671493d2a4c2185ff9aa9690ad571b7211ac4c6 100644
--- a/config/optional/block.block.oe_whitelabel_ec_corporate_footer.yml
+++ b/config/optional/block.block.oe_whitelabel_ec_corporate_footer.yml
@@ -3,6 +3,7 @@ status: true
 dependencies:
   module:
     - oe_corporate_blocks
+    - oe_whitelabel_helper
   theme:
     - oe_whitelabel
 id: oe_whitelabel_ec_corporate_footer
@@ -14,11 +15,11 @@ plugin: oe_corporate_blocks_ec_footer
 settings:
   id: oe_corporate_blocks_ec_footer
   label: 'EC Footer block'
-  provider: oe_corporate_blocks
   label_display: '0'
+  provider: oe_corporate_blocks
 visibility:
   oe_whitelabel_helper_current_component_library:
     id: oe_whitelabel_helper_current_component_library
-    component_library: ec
     negate: false
     context_mapping: {  }
+    component_library: ec
diff --git a/config/optional/block.block.oe_whitelabel_eu_corporate_footer.yml b/config/optional/block.block.oe_whitelabel_eu_corporate_footer.yml
index 1eaa3c403d45bc92ae949f091172175b662a3107..700c5fee4256da7864451c7a01addbaf8681688a 100644
--- a/config/optional/block.block.oe_whitelabel_eu_corporate_footer.yml
+++ b/config/optional/block.block.oe_whitelabel_eu_corporate_footer.yml
@@ -3,6 +3,7 @@ status: true
 dependencies:
   module:
     - oe_corporate_blocks
+    - oe_whitelabel_helper
   theme:
     - oe_whitelabel
 id: oe_whitelabel_eu_corporate_footer
@@ -14,11 +15,11 @@ plugin: oe_corporate_blocks_eu_footer
 settings:
   id: oe_corporate_blocks_eu_footer
   label: 'EU Footer block'
-  provider: oe_corporate_blocks
   label_display: '0'
+  provider: oe_corporate_blocks
 visibility:
   oe_whitelabel_helper_current_component_library:
     id: oe_whitelabel_helper_current_component_library
-    component_library: eu
     negate: false
     context_mapping: {  }
+    component_library: eu
diff --git a/config/optional/block.block.oe_whitelabel_eulogin.yml b/config/optional/block.block.oe_whitelabel_eulogin.yml
index 8bb5a39b509d42a597fdbccce6e54e187e777f8d..80d9e261ba57c05dcc38e795533046dfc9ac25e9 100644
--- a/config/optional/block.block.oe_whitelabel_eulogin.yml
+++ b/config/optional/block.block.oe_whitelabel_eulogin.yml
@@ -14,6 +14,6 @@ plugin: oe_authentication_login_block
 settings:
   id: oe_authentication_login_block
   label: 'EU Login Link Block'
-  provider: oe_authentication
   label_display: '0'
+  provider: oe_authentication
 visibility: {  }
diff --git a/config/optional/block.block.oe_whitelabel_language_switcher.yml b/config/optional/block.block.oe_whitelabel_language_switcher.yml
index df32e08a388b561e592246a9c63c0a4b38406992..b8b46125bd968ded5de0972c16ddd2fb1f1a640a 100644
--- a/config/optional/block.block.oe_whitelabel_language_switcher.yml
+++ b/config/optional/block.block.oe_whitelabel_language_switcher.yml
@@ -14,6 +14,6 @@ plugin: 'language_block:language_interface'
 settings:
   id: 'language_block:language_interface'
   label: 'Language switcher (Interface text)'
-  provider: language
   label_display: '0'
+  provider: language
 visibility: {  }
diff --git a/config/optional/block.block.oe_whitelabel_local_actions.yml b/config/optional/block.block.oe_whitelabel_local_actions.yml
index 0368285449e27dae2a8b5b252af528e0d16f01da..094fbea4d5915a4f01524c2fa8613b644b1aa503 100644
--- a/config/optional/block.block.oe_whitelabel_local_actions.yml
+++ b/config/optional/block.block.oe_whitelabel_local_actions.yml
@@ -6,12 +6,12 @@ dependencies:
 id: oe_whitelabel_local_actions
 theme: oe_whitelabel
 region: content
-weight: 0
+weight: -4
 provider: null
 plugin: local_actions_block
 settings:
   id: local_actions_block
   label: 'Primary admin actions'
-  provider: core
   label_display: '0'
+  provider: core
 visibility: {  }
diff --git a/config/optional/block.block.oe_whitelabel_local_tasks.yml b/config/optional/block.block.oe_whitelabel_local_tasks.yml
index 5a719a4870d9e1e8b3b22faf31fbdee384a2056a..7d5478116111febcd2f1bca899ddbc0bbebf5f04 100644
--- a/config/optional/block.block.oe_whitelabel_local_tasks.yml
+++ b/config/optional/block.block.oe_whitelabel_local_tasks.yml
@@ -6,14 +6,14 @@ dependencies:
 id: oe_whitelabel_local_tasks
 theme: oe_whitelabel
 region: content
-weight: -1
+weight: -5
 provider: null
 plugin: local_tasks_block
 settings:
   id: local_tasks_block
   label: Tabs
-  provider: core
   label_display: '0'
+  provider: core
   primary: true
   secondary: true
 visibility: {  }
diff --git a/config/optional/block.block.oe_whitelabel_main_page_content.yml b/config/optional/block.block.oe_whitelabel_main_page_content.yml
new file mode 100755
index 0000000000000000000000000000000000000000..8987832c02a8892287f54c88d659bdb6fecbbd76
--- /dev/null
+++ b/config/optional/block.block.oe_whitelabel_main_page_content.yml
@@ -0,0 +1,19 @@
+langcode: en
+status: true
+dependencies:
+  module:
+    - system
+  theme:
+    - oe_whitelabel
+id: oe_whitelabel_main_page_content
+theme: oe_whitelabel
+region: content
+weight: -2
+provider: null
+plugin: system_main_block
+settings:
+  id: system_main_block
+  label: 'Main page content'
+  label_display: '0'
+  provider: system
+visibility: {  }
diff --git a/config/optional/block.block.oe_whitelabel_messages.yml b/config/optional/block.block.oe_whitelabel_messages.yml
index cf33398e4b14d9dad84415b964c4d0c4001ae520..cf87516d5ca37d9357378bf7359f4ecc18be75d6 100644
--- a/config/optional/block.block.oe_whitelabel_messages.yml
+++ b/config/optional/block.block.oe_whitelabel_messages.yml
@@ -8,12 +8,12 @@ dependencies:
 id: oe_whitelabel_messages
 theme: oe_whitelabel
 region: content
-weight: -3
+weight: -6
 provider: null
 plugin: system_messages_block
 settings:
   id: system_messages_block
   label: 'Status messages'
-  provider: system
   label_display: '0'
+  provider: system
 visibility: {  }
diff --git a/config/optional/block.block.oe_whitelabel_neutral_footer.yml b/config/optional/block.block.oe_whitelabel_neutral_footer.yml
index 372470a5a8658bf797abe514987b4515e33607a6..b1cf2e875e022df87b5dbc073e4b91ba7c1274bd 100644
--- a/config/optional/block.block.oe_whitelabel_neutral_footer.yml
+++ b/config/optional/block.block.oe_whitelabel_neutral_footer.yml
@@ -14,11 +14,11 @@ plugin: oe_corporate_blocks_neutral_footer
 settings:
   id: oe_corporate_blocks_neutral_footer
   label: 'Neutral Footer block'
-  provider: oe_whitelabel_helper
   label_display: '0'
+  provider: oe_whitelabel_helper
 visibility:
   oe_whitelabel_helper_current_component_library:
     id: oe_whitelabel_helper_current_component_library
-    component_library: neutral
     negate: false
     context_mapping: {  }
+    component_library: neutral
diff --git a/config/optional/block.block.oe_whitelabel_search_form.yml b/config/optional/block.block.oe_whitelabel_search_form.yml
index c45778cf7f4dce05d8011495774a6f92efb5c4d1..22437b3aa239c48894a9d02b76966da4cc4fdd8e 100644
--- a/config/optional/block.block.oe_whitelabel_search_form.yml
+++ b/config/optional/block.block.oe_whitelabel_search_form.yml
@@ -14,8 +14,8 @@ plugin: whitelabel_search_block
 settings:
   id: whitelabel_search_block
   label: 'Whitelabel Search Block'
-  provider: oe_whitelabel_search
   label_display: '0'
+  provider: oe_whitelabel_search
   form:
     action: '#'
   input:
@@ -26,7 +26,7 @@ settings:
   button:
     classes: ''
   view_options:
+    enable_autocomplete: false
     id: null
     display: null
-    enable_autocomplete: false
 visibility: {  }
diff --git a/docker-compose.yml b/docker-compose.yml
index 789155aac7a54c542e5772f0f0be6da3848f8427..6eb4b18ebbe41fd004a78c696c1209515c778836 100644
--- a/docker-compose.yml
+++ b/docker-compose.yml
@@ -1,7 +1,7 @@
 version: '2'
 services:
   web:
-    image: fpfis/httpd-php-dev:7.4
+    image: fpfis/httpd-php-dev:8.0
     working_dir: /var/www/html
     ports:
       - 8080:8080
diff --git a/modules/oe_whitelabel_multilingual/oe_whitelabel_multilingual.info.yml b/modules/oe_whitelabel_multilingual/oe_whitelabel_multilingual.info.yml
new file mode 100755
index 0000000000000000000000000000000000000000..467182d49203cbfccc06b5cdde0269c7fc99c622
--- /dev/null
+++ b/modules/oe_whitelabel_multilingual/oe_whitelabel_multilingual.info.yml
@@ -0,0 +1,7 @@
+name: OpenEuropa Whitelabel Multilingual
+type: module
+description: Adds additional functionality to the Multilingual module
+package: OpenEuropa Whitelabel Theme
+core_version_requirement: ^9.2
+dependencies:
+  - openeuropa:oe_multilingual
diff --git a/modules/oe_whitelabel_multilingual/oe_whitelabel_multilingual.module b/modules/oe_whitelabel_multilingual/oe_whitelabel_multilingual.module
new file mode 100755
index 0000000000000000000000000000000000000000..203182b58c16d7c40216aa5ad50d05c5e4734196
--- /dev/null
+++ b/modules/oe_whitelabel_multilingual/oe_whitelabel_multilingual.module
@@ -0,0 +1,123 @@
+<?php
+
+/**
+ * @file
+ * OE Whitelabel theme Multilingual.
+ */
+
+declare(strict_types =  1);
+
+use Drupal\Component\Utility\Html;
+
+/**
+ * Implements hook_preprocess_links().
+ */
+function oe_whitelabel_multilingual_preprocess_links__oe_multilingual_content_language_block(array &$variables): void {
+  // Generate the label for the unavailable language.
+  /** @var \Drupal\Core\Language\LanguageInterface[] $languages */
+  $languages = \Drupal::service('language_manager')->getNativeLanguages();
+  $variables['unavailable_language'] = $languages[$variables['current_language_id']]->getName();
+
+  // Normalize the links to an array of optional languages suitable for the BCL.
+  $variables['languages'] = [];
+  foreach ($variables['links'] as $language_code => $link) {
+    /** @var \Drupal\Core\Url $url */
+    $url = $link['link']['#url'];
+    $href = $url
+      ->setOptions($link['link']['#options'])
+      ->setAbsolute(TRUE)
+      ->toString();
+
+    $variables['languages'][] = [
+      'path' => $href,
+      'hreflang' => $language_code,
+      'label' => $link['link']['#title'],
+      'current' => FALSE,
+    ];
+  }
+
+  // Add the current language to the list.
+  /** @var \Drupal\oe_multilingual\MultilingualHelper $multilingual_helper */
+  $multilingual_helper = \Drupal::service('oe_multilingual.helper');
+  $entity = $multilingual_helper->getEntityFromCurrentRoute();
+  $translation = $multilingual_helper->getCurrentLanguageEntityTranslation($entity);
+  // If we don't have a language id defined yet, the current translation wasn't
+  // saved, so we don't add it to the list.
+  if ($translation->language()->getId() !== 'und') {
+    $variables['languages'][] = [
+      'path' => $translation->toUrl()->setAbsolute(TRUE)->toString(),
+      'hreflang' => $translation->language()->getId(),
+      'label' => $languages[$translation->language()->getId()]->getName(),
+      'current' => TRUE,
+      'icon_position' => 'before',
+      'remove_icon_spacers' => FALSE,
+      'icon' => [
+        'name' => 'check-lg',
+        'path' => $variables['bcl_icon_path'],
+        'size' => 'xs',
+        '#attributes' => ['class' => ['me-2']],
+      ],
+    ];
+  }
+
+  // Generate required ids.
+  $variables['expandable_id'] = Html::getUniqueId('bcl-expandable');
+}
+
+/**
+ * Implements hook_preprocess_links__language_block().
+ */
+function oe_whitelabel_multilingual_preprocess_links__language_block(&$variables) {
+  $currentLanguage = \Drupal::languageManager()->getCurrentLanguage();
+  $current_language_id = $currentLanguage->getId();
+  $language_config_storage = \Drupal::entityTypeManager()->getStorage('configurable_language');
+  $eu_links = [];
+  $non_eu_links = [];
+
+  foreach ($variables['links'] as $language_code => $link) {
+    /** @var \Drupal\Core\Url $url */
+    $url = $link['link']['#url'];
+    $href = $url
+      ->setOptions($link['link']['#options'])
+      ->setAbsolute(TRUE)
+      ->toString();
+    $label = $link['link']['#title'];
+
+    $link = [
+      'href' => $href,
+      'name' => $label,
+      'id' => 'link_' . $language_code,
+      'hreflang' => $language_code,
+    ];
+
+    if (!empty($current_language_id) && $language_code === $current_language_id) {
+      $variables['language']['link'] = $link;
+      $variables['language']['link']['target'] = 'languageModal';
+      $link['active'] = TRUE;
+    }
+
+    $language_config = $language_config_storage->load($language_code);
+    $category = $language_config->getThirdPartySetting('oe_multilingual', 'category');
+
+    if ($category === 'eu') {
+      $eu_links[$language_code] = $link;
+    }
+    else {
+      $non_eu_links[$language_code] = $link;
+    }
+  }
+
+  $variables['language']['modal'] = [
+    'id' => 'languageModal',
+    'size' => 'fullscreen',
+    'header' => [
+      'title' => t('Select your language'),
+      'label' => t('Close'),
+    ],
+    'eu_links' => $eu_links,
+    'non_eu_links' => $non_eu_links,
+    'footer' => [
+      'label' => t('Close'),
+    ],
+  ];
+}
diff --git a/modules/oe_whitelabel_starter_event/oe_whitelabel_starter_event.info.yml b/modules/oe_whitelabel_starter_event/oe_whitelabel_starter_event.info.yml
index 29c37b071d3889a1b88ae9bc1cae2d4c894dab7c..ce2617f0d2bca0068c5a541a1eaf402eb709bdf6 100755
--- a/modules/oe_whitelabel_starter_event/oe_whitelabel_starter_event.info.yml
+++ b/modules/oe_whitelabel_starter_event/oe_whitelabel_starter_event.info.yml
@@ -10,6 +10,6 @@ dependencies:
 
 config_devel:
   install:
+    - core.date_format.oe_whitelabel_starter_event_date
     - core.entity_view_display.node.oe_sc_event.full
     - core.entity_view_display.node.oe_sc_event.teaser
-    - core.date_format.oe_whitelabel_starter_event_date
diff --git a/modules/oe_whitelabel_starter_news/oe_whitelabel_starter_news.info.yml b/modules/oe_whitelabel_starter_news/oe_whitelabel_starter_news.info.yml
index cd71e3993dcd798a149aadd9f76d900f8d41fd51..dc47e64bec603cea4cd4c9ec6b326c38a048c4ee 100644
--- a/modules/oe_whitelabel_starter_news/oe_whitelabel_starter_news.info.yml
+++ b/modules/oe_whitelabel_starter_news/oe_whitelabel_starter_news.info.yml
@@ -10,6 +10,6 @@ dependencies:
 
 config_devel:
   install:
-    - core.date_format.oe_whitelabel_starter_news_date.yml
-    - core.entity_view_display.node.oe_sc_news.full.yml
-    - core.entity_view_display.node.oe_sc_news.teaser.yml
+    - core.date_format.oe_whitelabel_starter_news_date
+    - core.entity_view_display.node.oe_sc_news.full
+    - core.entity_view_display.node.oe_sc_news.teaser
diff --git a/oe_whitelabel.info.yml b/oe_whitelabel.info.yml
index c334912dc62032627690574f5c9ec676aab85fa1..c3e080e884438a020a217aed4881782cf78fd42a 100644
--- a/oe_whitelabel.info.yml
+++ b/oe_whitelabel.info.yml
@@ -35,15 +35,16 @@ config_devel:
   install:
     - oe_whitelabel.settings
   optional:
-    - block.block.breadcrumbs
-    - block.block.corporateeclogoblock
-    - block.block.ecfooterblock
-    - block.block.euloginlinkblock.yml
-    - block.block.languageswitcherinterfacetext
     - block.block.oe_whitelabel_branding
+    - block.block.oe_whitelabel_breadcrumbs
+    - block.block.oe_whitelabel_ec_corporate_footer
+    - block.block.oe_whitelabel_eu_corporate_footer
+    - block.block.oe_whitelabel_eulogin
+    - block.block.oe_whitelabel_language_switcher
     - block.block.oe_whitelabel_local_actions
     - block.block.oe_whitelabel_local_tasks
+    - block.block.oe_whitelabel_main_navigation
+    - block.block.oe_whitelabel_main_page_content
     - block.block.oe_whitelabel_messages
-    - block.block.oe_whitelabel_page_title
-    - block.block.whitelabelsearchblock
-    - cas.settings.yml
+    - block.block.oe_whitelabel_neutral_footer
+    - block.block.oe_whitelabel_search_form
diff --git a/oe_whitelabel.theme b/oe_whitelabel.theme
index d591f9cf16e5ab1ed8abbb0983bc0e6e9f6a2489..5da6c190eebd347b07f207bc2265114b0e6df528 100644
--- a/oe_whitelabel.theme
+++ b/oe_whitelabel.theme
@@ -19,64 +19,6 @@ foreach (glob($includes_path) as $filename) {
   require_once __DIR__ . '/includes/' . basename($filename);
 }
 
-/**
- * Implements hook__preprocess_links__language_block().
- */
-function oe_whitelabel_preprocess_links__language_block(&$variables) {
-  $currentLanguage = \Drupal::languageManager()->getCurrentLanguage();
-  $current_language_id = $currentLanguage->getId();
-  $language_config_storage = \Drupal::entityTypeManager()->getStorage('configurable_language');
-  $eu_links = [];
-  $non_eu_links = [];
-
-  foreach ($variables['links'] as $language_code => $link) {
-    /** @var \Drupal\Core\Url $url */
-    $url = $link['link']['#url'];
-    $href = $url
-      ->setOptions($link['link']['#options'])
-      ->setAbsolute(TRUE)
-      ->toString();
-    $label = $link['link']['#title'];
-
-    $link = [
-      'href' => $href,
-      'name' => $label,
-      'id' => 'link_' . $language_code,
-      'hreflang' => $language_code,
-    ];
-
-    if (!empty($current_language_id) && $language_code === $current_language_id) {
-      $variables['language']['link'] = $link;
-      $variables['language']['link']['target'] = 'languageModal';
-      $link['active'] = TRUE;
-    }
-
-    $language_config = $language_config_storage->load($language_code);
-    $category = $language_config->getThirdPartySetting('oe_multilingual', 'category');
-
-    if ($category === 'eu') {
-      $eu_links[$language_code] = $link;
-    }
-    else {
-      $non_eu_links[$language_code] = $link;
-    }
-  }
-
-  $variables['language']['modal'] = [
-    'id' => 'languageModal',
-    'size' => 'fullscreen',
-    'header' => [
-      'title' => t('Select your language'),
-      'label' => t('Close'),
-    ],
-    'eu_links' => $eu_links,
-    'non_eu_links' => $non_eu_links,
-    'footer' => [
-      'label' => t('Close'),
-    ],
-  ];
-}
-
 /**
  * Implements hook_form_FORM_ID_alter() for facets_forms.
  */
diff --git a/runner.yml.dist b/runner.yml.dist
index 5a33a96b9fa9e1a966ab5e30dd83589bfb4e1fa4..17e68fd13c793c6c8bfc4a1d7bff8b029f845a01 100644
--- a/runner.yml.dist
+++ b/runner.yml.dist
@@ -19,7 +19,7 @@ drupal:
     - "./vendor/bin/drush en field_ui -y"
     - "./vendor/bin/drush en oe_authentication -y"
     - "./vendor/bin/drush en oe_corporate_blocks -y"
-    - "./vendor/bin/drush en oe_multilingual -y"
+    - "./vendor/bin/drush en oe_whitelabel_multilingual -y"
     - "./vendor/bin/drush en oe_whitelabel_contact_forms -y"
     - "./vendor/bin/drush en oe_whitelabel_helper -y"
     - "./vendor/bin/drush en oe_whitelabel_search -y"
diff --git a/templates/overrides/navigation/links--oe-multilingual-content-language-block.html.twig b/templates/overrides/navigation/links--oe-multilingual-content-language-block.html.twig
new file mode 100644
index 0000000000000000000000000000000000000000..784fbbf2f9324630b427745ad00fbc88dbf4d79f
--- /dev/null
+++ b/templates/overrides/navigation/links--oe-multilingual-content-language-block.html.twig
@@ -0,0 +1,51 @@
+{% apply spaceless %}
+  {# This template uses the BCL composition for the
+  language switcher.
+  _id, _message and _expandable are overwritten.
+  @todo Call include once BCL 0.20 is available.
+  #}
+  {% set _id = expandable_id %}
+  {% set _message = {
+    message: "This page is not available in @language."|t({'@language': unavailable_language}),
+    path: bcl_icon_path,
+    variant: "warning",
+  }%}
+  {% set _expandable = {
+    label: "Choose another language"|t,
+    icon: {
+      name: "caret-down-fill",
+      path: bcl_icon_path,
+    },
+    outline: "true",
+  } %}
+
+  {% set _languages = languages|default([]) %}
+  {% set _expandable_attributes = _expandable.attributes ?: create_attribute() %}
+  {% set _expandable_attributes = _expandable_attributes
+    .setAttribute('data-bs-toggle', 'collapse')
+    .setAttribute('autocomplete', 'off')
+    .setAttribute('aria-expanded', 'false')
+    .setAttribute('aria-controls', _id)
+    .setAttribute('data-bs-target', '#' ~ _id)
+  %}
+
+  {% include '@oe-bcl/bcl-alert/alert.html.twig' with _message only %}
+  <div class="mb-3">
+    {% include '@oe-bcl/bcl-button/button.html.twig' with _expandable|merge({
+      attributes: _expandable_attributes
+    }) only %}
+
+    <div class="collapse mt-3" id="{{ _id }}">
+      <div
+        class="d-md-grid"
+        style="grid-auto-flow: column; grid-template-rows: repeat(4, 1fr)"
+      >
+        {% for language in languages %}
+          {% include '@oe-bcl/bcl-link/link.html.twig' with language|merge({
+            attributes: create_attribute().addClass(["btn", "btn-link", "d-block", "ps-0", "text-start"])
+          }) only %}
+        {% endfor %}
+      </div>
+    </div>
+  </div>
+{% endapply %}
diff --git a/tests/src/Kernel/ContentLanguageSwitcherTest.php b/tests/src/Kernel/ContentLanguageSwitcherTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..49c72b792642ca7b70fc5614f2d389164e03b4f5
--- /dev/null
+++ b/tests/src/Kernel/ContentLanguageSwitcherTest.php
@@ -0,0 +1,215 @@
+<?php
+
+declare(strict_types = 1);
+
+namespace Drupal\Tests\oe_whitelabel\Kernel;
+
+use Drupal\node\Entity\Node;
+use Drupal\KernelTests\KernelTestBase;
+use Symfony\Component\DomCrawler\Crawler;
+use Symfony\Component\HttpFoundation\Request;
+
+/**
+ * Test content language switcher rendering.
+ */
+class ContentLanguageSwitcherTest extends KernelTestBase {
+
+  /**
+   * {@inheritdoc}
+   */
+  public static $modules = [
+    'block',
+    'content_translation',
+    'language',
+    'locale',
+    'node',
+    'oe_bootstrap_theme_helper',
+    'oe_corporate_blocks',
+    'oe_multilingual',
+    'oe_whitelabel_helper',
+    'oe_whitelabel_multilingual',
+    'system',
+    'user',
+  ];
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function setUp(): void {
+    parent::setUp();
+
+    $this->installEntitySchema('user');
+    $this->installSchema('system', 'sequences');
+    $this->installSchema('user', ['users_data']);
+    $this->installConfig(['user']);
+
+    $this->installSchema('locale', [
+      'locales_location',
+      'locales_source',
+      'locales_target',
+    ]);
+
+    $this->installEntitySchema('node');
+    $this->installSchema('node', 'node_access');
+    $this->installConfig([
+      'content_translation',
+      'language',
+      'locale',
+      'oe_multilingual',
+      'oe_whitelabel_helper',
+      'system',
+    ]);
+    $this->container->get('module_handler')->loadInclude('oe_multilingual', 'install');
+    oe_multilingual_install(FALSE);
+
+    $this->container->get('theme_installer')->install(['oe_whitelabel']);
+    $this->config('system.theme')->set('default', 'oe_whitelabel')->save();
+
+    // Call the installation hook of the User module which creates the
+    // Anonymous user and User 1. This is needed because the Anonymous user
+    // is loaded to provide the current User context which is needed
+    // in places like route enhancers.
+    // @see CurrentUserContext::getRuntimeContexts().
+    // @see EntityConverter::convert().
+    module_load_include('install', 'user');
+    user_install();
+
+    \Drupal::service('kernel')->rebuildContainer();
+  }
+
+  /**
+   * Tests the rendering of the language switcher block.
+   */
+  public function testMultilingualLanguageSwitcherBlockRendering(): void {
+    $node = Node::create([
+      'title' => 'Hello, world!',
+      'type' => 'oe_demo_translatable_page',
+    ]);
+    /** @var \Drupal\Core\Entity\EntityInterface $translation */
+    $node->addTranslation('es', ['title' => '¡Hola mundo!'])->save();
+
+    // Simulate a request to the canonical route of the node with Bulgarian
+    // language prefix.
+    $this->setCurrentRequest('/bg/node/' . $node->id());
+
+    // Setup and render language switcher block.
+    $block_manager = \Drupal::service('plugin.manager.block');
+    $config = [
+      'id' => 'oe_multilingual_content_language_switcher',
+      'label' => 'Content language switcher',
+      'provider' => 'oe_multilingual',
+      'label_display' => '0',
+    ];
+
+    /** @var \Drupal\Core\Block\BlockBase $plugin_block */
+    $plugin_block = $block_manager->createInstance('oe_multilingual_content_language_switcher', $config);
+    $render = $plugin_block->build();
+
+    $html = (string) $this->container->get('renderer')->renderRoot($render);
+    $crawler = new Crawler($html);
+
+    // Make sure that content language switcher block is present.
+    $actual = $crawler->filter('div.collapse.mt-3');
+    $this->assertCount(1, $actual);
+
+    // Warning message doesn't contain the unavailable language, the translation
+    // will have it.
+    $this->assertUnavailableLanguage($crawler, 'This page is not available in български.');
+
+    // Make sure that selected language is properly rendered.
+    $this->assertSelectedLanguage($crawler, 'English');
+
+    // Make sure that available languages are properly rendered.
+    $this->assertTranslationLinks($crawler, ['español']);
+
+    // Remove the spanish translation.
+    $node->removeTranslation('es');
+    $node->save();
+
+    // Re-render the block assuming a request to the Spanish version of the
+    // node.
+    $this->setCurrentRequest('/es/node/' . $node->id());
+    $render = $plugin_block->build();
+
+    $html = (string) $this->container->get('renderer')->renderRoot($render);
+    $crawler = new Crawler($html);
+
+    // Verify that the requested language is set as unavailable.
+    $this->assertUnavailableLanguage($crawler, 'This page is not available in español.');
+
+    // Verify that the content has been rendered in the fallback language.
+    $this->assertSelectedLanguage($crawler, 'English');
+
+    // Make sure that no language links are rendered.
+    $this->assertTranslationLinks($crawler, []);
+  }
+
+  /**
+   * Asserts that a language is marked as the current rendered.
+   *
+   * @param \Symfony\Component\DomCrawler\Crawler $crawler
+   *   The content language block crawler.
+   * @param string $expected
+   *   The label of the language.
+   */
+  protected function assertSelectedLanguage(Crawler $crawler, string $expected): void {
+    // The selected language link will contain a svg, so we target that.
+    $actual = $crawler->filter('div.collapse.mt-3 > div > a > svg')->parents()->first()->text();
+    $this->assertEquals($expected, trim($actual));
+  }
+
+  /**
+   * Asserts that a language is marked as unavailable.
+   *
+   * @param \Symfony\Component\DomCrawler\Crawler $crawler
+   *   The content language block crawler.
+   * @param string $expected
+   *   The label of the language.
+   */
+  protected function assertUnavailableLanguage(Crawler $crawler, string $expected): void {
+    $actual = $crawler->filter('div.alert div.alert-content')->text();
+    $this->assertStringContainsString($expected, trim($actual));
+  }
+
+  /**
+   * Asserts the rendered translation links in the content language switcher.
+   *
+   * @param \Symfony\Component\DomCrawler\Crawler $crawler
+   *   The content language block crawler.
+   * @param array $expected
+   *   The labels of the translations that should be rendered as links.
+   */
+  protected function assertTranslationLinks(Crawler $crawler, array $expected): void {
+    $elements = $crawler->filter('div.collapse.mt-3 > div > a');
+    // Filter out the selected language.
+    $elements = $elements->reduce(function (Crawler $crawler) {
+      return $crawler->filter('svg')->count() === 0;
+    });
+    $this->assertSameSize($expected, $elements);
+
+    $actual = array_column(iterator_to_array($elements), 'nodeValue');
+    $this->assertEquals($expected, $actual);
+  }
+
+  /**
+   * Sets a request to a certain URI as the current in the request stack.
+   *
+   * @param string $uri
+   *   The URI of the request. It needs to match a valid Drupal route.
+   */
+  protected function setCurrentRequest(string $uri): void {
+    // Simulate a request to a node canonical route with a language prefix.
+    $request = Request::create($uri);
+    // Let the Drupal router populate all the request parameters.
+    $parameters = \Drupal::service('router.no_access_checks')->matchRequest($request);
+    $request->attributes->add($parameters);
+    // Set the prepared request as current.
+    \Drupal::requestStack()->push($request);
+    // Reset any discovered language. KernelTestBase creates a request to the
+    // root of the website for legacy purposes, so the language is set by
+    // default to the default one.
+    // @see \Drupal\KernelTests\KernelTestBase::bootKernel()
+    \Drupal::languageManager()->reset();
+  }
+
+}
diff --git a/tests/src/Kernel/MultilingualBlockTest.php b/tests/src/Kernel/MultilingualBlockTest.php
index aa7053f842317df9abead6dd7a372151420c5707..8e21820ebb44726694206d574f27ef9cb2bf09a1 100644
--- a/tests/src/Kernel/MultilingualBlockTest.php
+++ b/tests/src/Kernel/MultilingualBlockTest.php
@@ -23,6 +23,7 @@ class MultilingualBlockTest extends KernelTestBase {
     'locale',
     'oe_bootstrap_theme_helper',
     'oe_multilingual',
+    'oe_whitelabel_multilingual',
     'path',
     'path_alias',
     'pathauto',