diff --git a/typo3/sysext/backend/Classes/Controller/PageLayoutController.php b/typo3/sysext/backend/Classes/Controller/PageLayoutController.php
index 1cd2c49f948890c798f420cb3a144665bc37a701..be3f4f48df0db58eea98dd41f1cf43b19c178d1a 100644
--- a/typo3/sysext/backend/Classes/Controller/PageLayoutController.php
+++ b/typo3/sysext/backend/Classes/Controller/PageLayoutController.php
@@ -25,6 +25,7 @@ use TYPO3\CMS\Backend\Template\Components\ButtonBar;
 use TYPO3\CMS\Backend\Template\ModuleTemplate;
 use TYPO3\CMS\Backend\Utility\BackendUtility;
 use TYPO3\CMS\Backend\View\BackendLayoutView;
+use TYPO3\CMS\Backend\View\PageLayoutContext;
 use TYPO3\CMS\Backend\View\PageLayoutView;
 use TYPO3\CMS\Core\Authentication\BackendUserAuthentication;
 use TYPO3\CMS\Core\Configuration\Features;
@@ -160,9 +161,9 @@ class PageLayoutController
     protected $uriBuilder;
 
     /**
-     * @var BackendLayoutView
+     * @var PageLayoutContext
      */
-    protected $backendLayouts;
+    protected $context;
 
     /**
      * Injects the request object for the current request or subrequest
@@ -179,13 +180,18 @@ class PageLayoutController
         $this->iconFactory = $this->moduleTemplate->getIconFactory();
         $this->uriBuilder = GeneralUtility::makeInstance(UriBuilder::class);
         $this->buttonBar = $this->moduleTemplate->getDocHeaderComponent()->getButtonBar();
-        $this->backendLayouts = GeneralUtility::makeInstance(BackendLayoutView::class);
         $this->getLanguageService()->includeLLFile('EXT:backend/Resources/Private/Language/locallang_layout.xlf');
         // Setting module configuration / page select clause
         $this->id = (int)($request->getParsedBody()['id'] ?? $request->getQueryParams()['id'] ?? 0);
 
         // Load page info array
         $this->pageinfo = BackendUtility::readPageAccess($this->id, $this->getBackendUser()->getPagePermsClause(Permission::PAGE_SHOW));
+        $this->context = GeneralUtility::makeInstance(
+            PageLayoutContext::class,
+            $this->pageinfo,
+            GeneralUtility::makeInstance(BackendLayoutView::class)->getBackendLayoutForPage($this->id)
+        );
+
         /** @var SiteInterface $currentSite */
         $currentSite = $request->getAttribute('site');
         $this->availableLanguages = $currentSite->getAvailableLanguages($this->getBackendUser(), false, $this->id);
@@ -547,8 +553,9 @@ class PageLayoutController
                 }
             ');
 
+            $backendLayout = $this->context->getBackendLayout();
+
             // Find backend layout / columns
-            $backendLayout = $this->backendLayouts->getBackendLayoutForPage($this->id);
             if (!empty($backendLayout->getColumnPositionNumbers())) {
                 $this->colPosList = implode(',', $backendLayout->getColumnPositionNumbers());
             }
@@ -619,26 +626,26 @@ class PageLayoutController
         $this->pageRenderer->loadRequireJsModule('TYPO3/CMS/Backend/LayoutModule/Paste');
         $this->pageRenderer->addInlineLanguageLabelFile('EXT:backend/Resources/Private/Language/locallang_layout.xlf');
 
-        $backendLayout = $this->backendLayouts->getBackendLayoutForPage((int)$this->id);
+        $backendLayout = $this->context->getBackendLayout();
 
-        $configuration = $backendLayout->getDrawingConfiguration();
-        $configuration->setPageId($this->id);
+        $configuration = $this->context->getDrawingConfiguration();
         $configuration->setDefaultLanguageBinding(!empty($this->modTSconfig['properties']['defLangBinding']));
         $configuration->setActiveColumns(GeneralUtility::trimExplode(',', $this->activeColPosList));
         $configuration->setShowHidden((bool)$this->MOD_SETTINGS['tt_content_showHidden']);
         $configuration->setLanguageColumns($this->MOD_MENU['language']);
-        $configuration->setLanguageColumnsPointer((int)$this->current_sys_language);
+        $configuration->setShowNewContentWizard(empty($this->modTSconfig['properties']['disableNewContentElementWizard']));
+        $configuration->setSelectedLanguageId((int)$this->MOD_SETTINGS['language']);
         if ($this->MOD_SETTINGS['function'] == 2) {
             $configuration->setLanguageMode(true);
         }
-        $configuration->setShowNewContentWizard(empty($this->modTSconfig['properties']['disableNewContentElementWizard']));
+
         $numberOfHiddenElements = $this->getNumberOfHiddenElements($configuration->getLanguageColumns());
 
         if (GeneralUtility::makeInstance(Features::class)->isFeatureEnabled('fluidBasedPageModule')) {
-            $pageLayoutDrawer = $backendLayout->getBackendLayoutRenderer();
+            $pageLayoutDrawer = $this->context->getBackendLayoutRenderer();
 
             $pageActionsCallback = null;
-            if ($configuration->isPageEditable()) {
+            if ($this->context->isPageEditable()) {
                 $languageOverlayId = 0;
                 $pageLocalizationRecord = BackendUtility::getRecordLocalization('pages', $this->id, (int)$this->current_sys_language);
                 if (is_array($pageLocalizationRecord)) {
@@ -655,7 +662,7 @@ class PageLayoutController
             $this->pageRenderer->loadRequireJsModule('TYPO3/CMS/Backend/PageActions', $pageActionsCallback);
             $tableOutput = $pageLayoutDrawer->drawContent();
         } else {
-            $dbList = PageLayoutView::createFromDrawingConfiguration($configuration);
+            $dbList = PageLayoutView::createFromPageLayoutContext($this->context);
             // Setting up the tt_content columns to show
             $colList = array_keys($backendLayout->getUsedColumns());
             if ($this->colPosList !== '') {
diff --git a/typo3/sysext/backend/Classes/Preview/StandardContentPreviewRenderer.php b/typo3/sysext/backend/Classes/Preview/StandardContentPreviewRenderer.php
index e08a4503cc81c5908bc724849ee074a16bd355a4..059f7063b53b40fc1fdd68b471c8b7c8982bccc4 100644
--- a/typo3/sysext/backend/Classes/Preview/StandardContentPreviewRenderer.php
+++ b/typo3/sysext/backend/Classes/Preview/StandardContentPreviewRenderer.php
@@ -54,7 +54,7 @@ class StandardContentPreviewRenderer implements PreviewRendererInterface, Logger
     public function renderPageModulePreviewHeader(GridColumnItem $item): string
     {
         $record = $item->getRecord();
-        $itemLabels = $item->getBackendLayout()->getDrawingConfiguration()->getItemLabels();
+        $itemLabels = $item->getContext()->getItemLabels();
 
         $outHeader = '';
 
@@ -81,14 +81,14 @@ class StandardContentPreviewRenderer implements PreviewRendererInterface, Logger
         $out = '';
         $record = $item->getRecord();
 
-        $contentTypeLabels = $item->getBackendLayout()->getDrawingConfiguration()->getContentTypeLabels();
+        $contentTypeLabels = $item->getContext()->getContentTypeLabels();
         $languageService = $this->getLanguageService();
 
         $drawItem = true;
         $hookPreviewContent = '';
         // Hook: Render an own preview of a record
         if (!empty($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['cms/layout/class.tx_cms_layout.php']['tt_content_drawItem'])) {
-            $pageLayoutView = PageLayoutView::createFromDrawingConfiguration($item->getBackendLayout()->getDrawingConfiguration());
+            $pageLayoutView = PageLayoutView::createFromPageLayoutContext($item->getContext());
             foreach ($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['cms/layout/class.tx_cms_layout.php']['tt_content_drawItem'] ?? [] as $className) {
                 $hookObject = GeneralUtility::makeInstance($className);
                 if (!$hookObject instanceof PageLayoutViewDrawItemHookInterface) {
@@ -169,7 +169,7 @@ class StandardContentPreviewRenderer implements PreviewRendererInterface, Logger
             case 'list':
                 $hookOut = '';
                 if (!empty($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['cms/layout/class.tx_cms_layout.php']['list_type_Info'])) {
-                    $pageLayoutView = PageLayoutView::createFromDrawingConfiguration($item->getBackendLayout()->getDrawingConfiguration());
+                    $pageLayoutView = PageLayoutView::createFromPageLayoutContext($item->getBackendLayout());
                     $_params = ['pObj' => &$pageLayoutView, 'row' => $record];
                     foreach (
                         $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['cms/layout/class.tx_cms_layout.php']['list_type_Info'][$record['list_type']] ??
@@ -240,7 +240,7 @@ class StandardContentPreviewRenderer implements PreviewRendererInterface, Logger
 
         // Call drawFooter hooks
         if (!empty($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['cms/layout/class.tx_cms_layout.php']['tt_content_drawFooter'])) {
-            $pageLayoutView = PageLayoutView::createFromDrawingConfiguration($item->getBackendLayout()->getDrawingConfiguration());
+            $pageLayoutView = PageLayoutView::createFromPageLayoutContext($item->getBackendLayout());
             foreach ($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['cms/layout/class.tx_cms_layout.php']['tt_content_drawFooter'] ?? [] as $className) {
                 $hookObject = GeneralUtility::makeInstance($className);
                 if (!$hookObject instanceof PageLayoutViewDrawFooterHookInterface) {
@@ -273,7 +273,7 @@ class StandardContentPreviewRenderer implements PreviewRendererInterface, Logger
 
     protected function getProcessedValue(GridColumnItem $item, string $fieldList, array &$info): void
     {
-        $itemLabels = $item->getBackendLayout()->getDrawingConfiguration()->getItemLabels();
+        $itemLabels = $item->getContext()->getItemLabels();
         $record = $item->getRecord();
         $fieldArr = explode(',', $fieldList);
         foreach ($fieldArr as $field) {
diff --git a/typo3/sysext/backend/Classes/View/BackendLayout/BackendLayout.php b/typo3/sysext/backend/Classes/View/BackendLayout/BackendLayout.php
index 7a838be53a8affdd258676df17fdab333b56d3e8..cd15ee4d4980d6c1c909a9d84554727dee5465bb 100644
--- a/typo3/sysext/backend/Classes/View/BackendLayout/BackendLayout.php
+++ b/typo3/sysext/backend/Classes/View/BackendLayout/BackendLayout.php
@@ -15,14 +15,7 @@
 
 namespace TYPO3\CMS\Backend\View\BackendLayout;
 
-use TYPO3\CMS\Backend\Utility\BackendUtility;
-use TYPO3\CMS\Backend\View\BackendLayout\Grid\Grid;
-use TYPO3\CMS\Backend\View\BackendLayout\Grid\GridColumn;
-use TYPO3\CMS\Backend\View\BackendLayout\Grid\GridRow;
-use TYPO3\CMS\Backend\View\BackendLayout\Grid\LanguageColumn;
 use TYPO3\CMS\Backend\View\BackendLayoutView;
-use TYPO3\CMS\Backend\View\Drawing\BackendLayoutRenderer;
-use TYPO3\CMS\Backend\View\Drawing\DrawingConfiguration;
 use TYPO3\CMS\Core\Utility\GeneralUtility;
 
 /**
@@ -67,26 +60,6 @@ class BackendLayout
      */
     protected $data;
 
-    /**
-     * @var DrawingConfiguration
-     */
-    protected $drawingConfiguration;
-
-    /**
-     * @var ContentFetcher
-     */
-    protected $contentFetcher;
-
-    /**
-     * @var LanguageColumn[]
-     */
-    protected $languageColumns = [];
-
-    /**
-     * @var RecordRememberer
-     */
-    protected $recordRememberer;
-
     /**
      * @param string $identifier
      * @param string $title
@@ -110,9 +83,6 @@ class BackendLayout
      */
     public function __construct($identifier, $title, $configuration)
     {
-        $this->drawingConfiguration = GeneralUtility::makeInstance(DrawingConfiguration::class);
-        $this->contentFetcher = GeneralUtility::makeInstance(ContentFetcher::class, $this);
-        $this->recordRememberer = GeneralUtility::makeInstance(RecordRememberer::class);
         $this->setIdentifier($identifier);
         $this->setTitle($title);
         if (is_array($configuration)) {
@@ -250,90 +220,8 @@ class BackendLayout
         return $this->structure;
     }
 
-    /**
-     * @return LanguageColumn[]
-     */
-    public function getLanguageColumns(): iterable
-    {
-        if (empty($this->languageColumns)) {
-            $availableLanguageColumns = $this->getDrawingConfiguration()->getLanguageColumns();
-            foreach ($this->getDrawingConfiguration()->getSiteLanguages() as $siteLanguage) {
-                if (!isset($availableLanguageColumns[$siteLanguage->getLanguageId()])) {
-                    continue;
-                }
-                $backendLayout = clone $this;
-                $backendLayout->getDrawingConfiguration()->setLanguageColumnsPointer($siteLanguage->getLanguageId());
-                $this->languageColumns[] = GeneralUtility::makeInstance(LanguageColumn::class, $backendLayout, $siteLanguage);
-            }
-        }
-        return $this->languageColumns;
-    }
-
-    public function getGrid(): Grid
-    {
-        $grid = GeneralUtility::makeInstance(Grid::class, $this);
-        foreach ($this->structure['__config']['backend_layout.']['rows.'] ?? [] as $row) {
-            $rowObject = GeneralUtility::makeInstance(GridRow::class, $this);
-            foreach ($row['columns.'] as $column) {
-                $columnObject = GeneralUtility::makeInstance(GridColumn::class, $this, $column);
-                $rowObject->addColumn($columnObject);
-            }
-            $grid->addRow($rowObject);
-        }
-        $pageId = $this->drawingConfiguration->getPageId();
-        $allowInconsistentLanguageHandling = (bool)(BackendUtility::getPagesTSconfig($pageId)['mod.']['web_layout.']['allowInconsistentLanguageHandling'] ?? false);
-        if (!$allowInconsistentLanguageHandling && $this->getLanguageModeIdentifier() === 'connected') {
-            $grid->setAllowNewContent(false);
-        }
-        return $grid;
-    }
-
     public function getColumnPositionNumbers(): array
     {
         return $this->structure['__colPosList'];
     }
-
-    public function getContentFetcher(): ContentFetcher
-    {
-        return $this->contentFetcher;
-    }
-
-    public function setContentFetcher(ContentFetcher $contentFetcher): void
-    {
-        $this->contentFetcher = $contentFetcher;
-    }
-
-    public function getDrawingConfiguration(): DrawingConfiguration
-    {
-        return $this->drawingConfiguration;
-    }
-
-    public function setDrawingConfiguration(DrawingConfiguration $drawingConfiguration): void
-    {
-        $this->drawingConfiguration = $drawingConfiguration;
-    }
-
-    public function getBackendLayoutRenderer(): BackendLayoutRenderer
-    {
-        return GeneralUtility::makeInstance(BackendLayoutRenderer::class, $this);
-    }
-
-    public function getRecordRememberer(): RecordRememberer
-    {
-        return $this->recordRememberer;
-    }
-
-    public function getLanguageModeIdentifier(): string
-    {
-        $contentRecordsPerColumn = $this->contentFetcher->getContentRecordsPerColumn(null, $this->drawingConfiguration->getLanguageColumnsPointer());
-        $contentRecords = empty($contentRecordsPerColumn) ? [] : array_merge(...$contentRecordsPerColumn);
-        $translationData = $this->contentFetcher->getTranslationData($contentRecords, $this->drawingConfiguration->getLanguageColumnsPointer());
-        return $translationData['mode'] ?? '';
-    }
-
-    public function __clone()
-    {
-        $this->drawingConfiguration = clone $this->drawingConfiguration;
-        $this->contentFetcher->setBackendLayout($this);
-    }
 }
diff --git a/typo3/sysext/backend/Classes/View/BackendLayout/ContentFetcher.php b/typo3/sysext/backend/Classes/View/BackendLayout/ContentFetcher.php
index 64add58c75a4f54aa88c1e0c1a5b76fca24ddeb6..4a5785f4f0c902871965e71650f410294e68cf47 100644
--- a/typo3/sysext/backend/Classes/View/BackendLayout/ContentFetcher.php
+++ b/typo3/sysext/backend/Classes/View/BackendLayout/ContentFetcher.php
@@ -19,7 +19,10 @@ namespace TYPO3\CMS\Backend\View\BackendLayout;
 
 use Doctrine\DBAL\Driver\Statement;
 use TYPO3\CMS\Backend\Utility\BackendUtility;
+use TYPO3\CMS\Backend\View\PageLayoutContext;
 use TYPO3\CMS\Backend\View\PageLayoutView;
+use TYPO3\CMS\Core\Cache\CacheManager;
+use TYPO3\CMS\Core\Cache\Frontend\VariableFrontend;
 use TYPO3\CMS\Core\Database\ConnectionPool;
 use TYPO3\CMS\Core\Database\Query\QueryBuilder;
 use TYPO3\CMS\Core\Database\Query\Restriction\DeletedRestriction;
@@ -41,30 +44,19 @@ use TYPO3\CMS\Core\Utility\GeneralUtility;
 class ContentFetcher
 {
     /**
-     * @var BackendLayout
+     * @var PageLayoutContext
      */
-    protected $backendLayout;
+    protected $context;
 
     /**
      * @var array
      */
     protected $fetchedContentRecords = [];
 
-    /**
-     * Stores whether a certain language has translations in it
-     *
-     * @var array
-     */
-    protected $languageHasTranslationsCache = [];
-
-    public function __construct(BackendLayout $backendLayout)
+    public function __construct(PageLayoutContext $pageLayoutContext)
     {
-        $this->backendLayout = $backendLayout;
-    }
-
-    public function setBackendLayout(BackendLayout $backendLayout): void
-    {
-        $this->backendLayout = $backendLayout;
+        $this->context = $pageLayoutContext;
+        $this->fetchedContentRecords = $this->getRuntimeCache()->get('ContentFetcher_fetchedContentRecords') ?: [];
     }
 
     /**
@@ -77,18 +69,30 @@ class ContentFetcher
      */
     public function getContentRecordsPerColumn(?int $columnNumber = null, ?int $languageId = null): iterable
     {
+        $languageId = $languageId ?? $this->context->getSiteLanguage()->getLanguageId();
+
         if (empty($this->fetchedContentRecords)) {
+            $isLanguageMode = $this->context->getDrawingConfiguration()->getLanguageMode();
             $queryBuilder = $this->getQueryBuilder();
             $records = $this->getResult($queryBuilder->execute());
             foreach ($records as $record) {
                 $recordLanguage = (int)$record['sys_language_uid'];
                 $recordColumnNumber = (int)$record['colPos'];
+                if ($recordLanguage === -1) {
+                    // Record is set to "all languages", place it according to view mode.
+                    if ($isLanguageMode) {
+                        // Force the record to only be shown in default language in "Languages" view mode.
+                        $recordLanguage = 0;
+                    } else {
+                        // Force the record to be shown in the currently active language in "Columns" view mode.
+                        $recordLanguage = $languageId;
+                    }
+                }
                 $this->fetchedContentRecords[$recordLanguage][$recordColumnNumber][] = $record;
             }
+            $this->getRuntimeCache()->set('ContentFetcher_fetchedContentRecords', $this->fetchedContentRecords);
         }
 
-        $languageId = $languageId ?? $this->backendLayout->getDrawingConfiguration()->getLanguageColumnsPointer();
-
         $contentByLanguage = &$this->fetchedContentRecords[$languageId];
 
         if ($columnNumber === null) {
@@ -98,9 +102,8 @@ class ContentFetcher
         return $contentByLanguage[$columnNumber] ?? [];
     }
 
-    public function getFlatContentRecords(): iterable
+    public function getFlatContentRecords(int $languageId): iterable
     {
-        $languageId = $this->backendLayout->getDrawingConfiguration()->getLanguageColumnsPointer();
         $contentRecords = $this->getContentRecordsPerColumn(null, $languageId);
         return empty($contentRecords) ? [] : array_merge(...$contentRecords);
     }
@@ -114,11 +117,11 @@ class ContentFetcher
     {
         $unrendered = [];
         $hookArray = $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['cms/layout/class.tx_cms_layout.php']['record_is_used'] ?? [];
-        $pageLayoutView = PageLayoutView::createFromDrawingConfiguration($this->backendLayout->getDrawingConfiguration());
+        $pageLayoutView = PageLayoutView::createFromPageLayoutContext($this->context);
 
-        $knownColumnPositionNumbers = $this->backendLayout->getColumnPositionNumbers();
-        $rememberer = $this->backendLayout->getRecordRememberer();
-        foreach ($this->fetchedContentRecords[$this->backendLayout->getDrawingConfiguration()->getLanguageColumnsPointer()] ?? [] as $contentRecordsInColumn) {
+        $knownColumnPositionNumbers = $this->context->getBackendLayout()->getColumnPositionNumbers();
+        $rememberer = GeneralUtility::makeInstance(RecordRememberer::class);
+        foreach ($this->getContentRecordsPerColumn(null, 0) as $contentRecordsInColumn) {
             foreach ($contentRecordsInColumn as $contentRecord) {
                 $used = $rememberer->isRemembered((int)$contentRecord['uid']);
                 // A hook mentioned that this record is used somewhere, so this is in fact "rendered" already
@@ -136,47 +139,45 @@ class ContentFetcher
 
     public function getTranslationData(iterable $contentElements, int $language): array
     {
-        $configuration = $this->backendLayout->getDrawingConfiguration();
-
         if ($language === 0) {
             return [];
         }
 
-        if (!isset($this->languageHasTranslationsCache[$language])) {
-            if ($language) {
-                $contentRecordsInDefaultLanguage = $this->getContentRecordsPerColumn(null, 0);
-                if (!empty($contentRecordsInDefaultLanguage)) {
-                    $contentRecordsInDefaultLanguage = array_merge(...$contentRecordsInDefaultLanguage);
-                }
-            } else {
-                $contentRecordsInDefaultLanguage = $contentElements;
+        $languageTranslationInfo = $this->getRuntimeCache()->get('ContentFetcher_TranslationInfo_' . $language) ?: [];
+        if (empty($languageTranslationInfo)) {
+            $contentRecordsInDefaultLanguage = $this->getContentRecordsPerColumn(null, 0);
+            if (!empty($contentRecordsInDefaultLanguage)) {
+                $contentRecordsInDefaultLanguage = array_merge(...$contentRecordsInDefaultLanguage);
             }
             $untranslatedRecordUids = array_flip(array_column($contentRecordsInDefaultLanguage, 'uid'));
 
             foreach ($contentElements as $contentElement) {
+                if ((int)$contentElement['sys_language_uid'] === -1) {
+                    continue;
+                }
                 if ((int)$contentElement['l18n_parent'] === 0) {
-                    $this->languageHasTranslationsCache[$language]['hasStandAloneContent'] = true;
-                    $this->languageHasTranslationsCache[$language]['mode'] = 'free';
+                    $languageTranslationInfo['hasStandAloneContent'] = true;
+                    $languageTranslationInfo['mode'] = 'free';
                 }
                 if ((int)$contentElement['l18n_parent'] > 0) {
-                    $this->languageHasTranslationsCache[$language]['hasTranslations'] = true;
-                    $this->languageHasTranslationsCache[$language]['mode'] = 'connected';
+                    $languageTranslationInfo['hasTranslations'] = true;
+                    $languageTranslationInfo['mode'] = 'connected';
                 }
                 if ((int)$contentElement['l10n_source'] > 0) {
                     unset($untranslatedRecordUids[(int)$contentElement['l10n_source']]);
                 }
             }
-            if (!isset($this->languageHasTranslationsCache[$language])) {
-                $this->languageHasTranslationsCache[$language]['hasTranslations'] = false;
+            if (!isset($languageTranslationInfo['hasTranslations'])) {
+                $languageTranslationInfo['hasTranslations'] = false;
             }
-            $this->languageHasTranslationsCache[$language]['untranslatedRecordUids'] = array_keys($untranslatedRecordUids);
+            $languageTranslationInfo['untranslatedRecordUids'] = array_keys($untranslatedRecordUids);
 
             // Check for inconsistent translations, force "mixed" mode and dispatch a FlashMessage to user if such a case is encountered.
-            if (isset($this->languageHasTranslationsCache[$language]['hasStandAloneContent'])
-                && $this->languageHasTranslationsCache[$language]['hasTranslations']
+            if (isset($languageTranslationInfo['hasStandAloneContent'])
+                && $languageTranslationInfo['hasTranslations']
             ) {
-                $this->languageHasTranslationsCache[$language]['mode'] = 'mixed';
-                $siteLanguage = $configuration->getSiteLanguage($language);
+                $languageTranslationInfo['mode'] = 'mixed';
+                $siteLanguage = $this->context->getSiteLanguage();
                 $message = GeneralUtility::makeInstance(
                     FlashMessage::class,
                     sprintf($this->getLanguageService()->getLL('staleTranslationWarning'), $siteLanguage->getTitle()),
@@ -187,8 +188,10 @@ class ContentFetcher
                 $queue = $service->getMessageQueueByIdentifier();
                 $queue->addMessage($message);
             }
+
+            $this->getRuntimeCache()->set('ContentFetcher_TranslationInfo_' . $language, $languageTranslationInfo);
         }
-        return $this->languageHasTranslationsCache[$language];
+        return $languageTranslationInfo;
     }
 
     protected function getQueryBuilder(): QueryBuilder
@@ -207,7 +210,7 @@ class ContentFetcher
         $queryBuilder->andWhere(
             $queryBuilder->expr()->eq(
                 'tt_content.pid',
-                $queryBuilder->createNamedParameter($this->backendLayout->getDrawingConfiguration()->getPageId(), \PDO::PARAM_INT)
+                $queryBuilder->createNamedParameter($this->context->getPageId(), \PDO::PARAM_INT)
             )
         );
 
@@ -224,7 +227,7 @@ class ContentFetcher
                 $hookObject->modifyQuery(
                     $parameters,
                     'tt_content',
-                    $this->backendLayout->getDrawingConfiguration()->getPageId(),
+                    $this->context->getPageId(),
                     $additionalConstraints,
                     $fields,
                     $queryBuilder
@@ -251,4 +254,9 @@ class ContentFetcher
     {
         return $GLOBALS['LANG'];
     }
+
+    protected function getRuntimeCache(): VariableFrontend
+    {
+        return GeneralUtility::makeInstance(CacheManager::class)->getCache('cache_runtime');
+    }
 }
diff --git a/typo3/sysext/backend/Classes/View/BackendLayout/Grid/AbstractGridObject.php b/typo3/sysext/backend/Classes/View/BackendLayout/Grid/AbstractGridObject.php
index 2635bf2331ec4ee8755f799b864133ab008a657a..6c9e8a377fbd0f1692e15d948d9cae643e03939a 100644
--- a/typo3/sysext/backend/Classes/View/BackendLayout/Grid/AbstractGridObject.php
+++ b/typo3/sysext/backend/Classes/View/BackendLayout/Grid/AbstractGridObject.php
@@ -17,7 +17,7 @@ declare(strict_types=1);
 
 namespace TYPO3\CMS\Backend\View\BackendLayout\Grid;
 
-use TYPO3\CMS\Backend\View\BackendLayout\BackendLayout;
+use TYPO3\CMS\Backend\View\PageLayoutContext;
 use TYPO3\CMS\Core\Authentication\BackendUserAuthentication;
 use TYPO3\CMS\Core\Imaging\IconFactory;
 use TYPO3\CMS\Core\Localization\LanguageService;
@@ -38,9 +38,9 @@ use TYPO3\CMS\Core\Utility\StringUtility;
 abstract class AbstractGridObject
 {
     /**
-     * @var BackendLayout
+     * @var PageLayoutContext
      */
-    protected $backendLayout;
+    protected $context;
 
     /**
      * @var IconFactory
@@ -52,9 +52,9 @@ abstract class AbstractGridObject
      */
     protected $uniqueId;
 
-    public function __construct(BackendLayout $backendLayout)
+    public function __construct(PageLayoutContext $context)
     {
-        $this->backendLayout = $backendLayout;
+        $this->context = $context;
         $this->iconFactory = GeneralUtility::makeInstance(IconFactory::class);
     }
 
@@ -63,9 +63,9 @@ abstract class AbstractGridObject
         return $this->uniqueId ?? $this->uniqueId = StringUtility::getUniqueId();
     }
 
-    public function getBackendLayout(): BackendLayout
+    public function getContext(): PageLayoutContext
     {
-        return $this->backendLayout;
+        return $this->context;
     }
 
     protected function getLanguageService(): LanguageService
diff --git a/typo3/sysext/backend/Classes/View/BackendLayout/Grid/Grid.php b/typo3/sysext/backend/Classes/View/BackendLayout/Grid/Grid.php
index 9e83302540527fb4aa33950d916c54548440ef90..38be6610672f1267b6b6eac85e0926d62e7968f8 100644
--- a/typo3/sysext/backend/Classes/View/BackendLayout/Grid/Grid.php
+++ b/typo3/sysext/backend/Classes/View/BackendLayout/Grid/Grid.php
@@ -67,19 +67,9 @@ class Grid extends AbstractGridObject
         return $columns;
     }
 
-    public function isAllowNewContent(): bool
-    {
-        return $this->allowNewContent;
-    }
-
-    public function setAllowNewContent(bool $allowNewContent): void
-    {
-        $this->allowNewContent = $allowNewContent;
-    }
-
     public function getSpan(): int
     {
-        if (!isset($this->rows[0]) || $this->backendLayout->getDrawingConfiguration()->getLanguageMode()) {
+        if (!isset($this->rows[0]) || $this->context->getDrawingConfiguration()->getLanguageMode()) {
             return 1;
         }
         $span = 0;
diff --git a/typo3/sysext/backend/Classes/View/BackendLayout/Grid/GridColumn.php b/typo3/sysext/backend/Classes/View/BackendLayout/Grid/GridColumn.php
index 73ee24b53ab14ddc4c88ee7775d3393ce09489e3..fadfd6465c2dceacf4be066468027bc07957fb49 100644
--- a/typo3/sysext/backend/Classes/View/BackendLayout/Grid/GridColumn.php
+++ b/typo3/sysext/backend/Classes/View/BackendLayout/Grid/GridColumn.php
@@ -19,7 +19,7 @@ namespace TYPO3\CMS\Backend\View\BackendLayout\Grid;
 
 use TYPO3\CMS\Backend\Routing\UriBuilder;
 use TYPO3\CMS\Backend\Utility\BackendUtility;
-use TYPO3\CMS\Backend\View\BackendLayout\BackendLayout;
+use TYPO3\CMS\Backend\View\PageLayoutContext;
 use TYPO3\CMS\Core\Type\Bitmask\Permission;
 use TYPO3\CMS\Core\Utility\GeneralUtility;
 
@@ -67,31 +67,19 @@ class GridColumn extends AbstractGridObject
      */
     protected $rowSpan = 1;
 
-    /**
-     * @var array
-     */
-    protected $records;
-
-    public function __construct(BackendLayout $backendLayout, array $columnDefinition, ?array $records = null)
+    public function __construct(PageLayoutContext $context, array $columnDefinition)
     {
-        parent::__construct($backendLayout);
+        parent::__construct($context);
         $this->columnNumber = isset($columnDefinition['colPos']) ? (int)$columnDefinition['colPos'] : $this->columnNumber;
         $this->columnName = $columnDefinition['name'] ?? $this->columnName;
         $this->icon = $columnDefinition['icon'] ?? $this->icon;
         $this->colSpan = (int)($columnDefinition['colspan'] ?? $this->colSpan);
         $this->rowSpan = (int)($columnDefinition['rowspan'] ?? $this->rowSpan);
-        if ($this->columnNumber !== null) {
-            $this->records = $records ?? $backendLayout->getContentFetcher()->getContentRecordsPerColumn($this->columnNumber, $backendLayout->getDrawingConfiguration()->getLanguageColumnsPointer());
-            foreach ($this->records as $contentRecord) {
-                $columnItem = GeneralUtility::makeInstance(GridColumnItem::class, $backendLayout, $this, $contentRecord);
-                $this->addItem($columnItem);
-            }
-        }
     }
 
     public function isActive(): bool
     {
-        return $this->columnNumber !== null && in_array($this->columnNumber, $this->backendLayout->getDrawingConfiguration()->getActiveColumns());
+        return $this->columnNumber !== null && in_array($this->columnNumber, $this->context->getDrawingConfiguration()->getActiveColumns());
     }
 
     public function addItem(GridColumnItem $item): void
@@ -99,11 +87,6 @@ class GridColumn extends AbstractGridObject
         $this->items[] = $item;
     }
 
-    public function getRecords(): iterable
-    {
-        return $this->records;
-    }
-
     /**
      * @return GridColumnItem[]
      */
@@ -129,7 +112,7 @@ class GridColumn extends AbstractGridObject
 
     public function getColSpan(): int
     {
-        if ($this->backendLayout->getDrawingConfiguration()->getLanguageMode()) {
+        if ($this->context->getDrawingConfiguration()->getLanguageMode()) {
             return 1;
         }
         return $this->colSpan;
@@ -137,7 +120,7 @@ class GridColumn extends AbstractGridObject
 
     public function getRowSpan(): int
     {
-        if ($this->backendLayout->getDrawingConfiguration()->getLanguageMode()) {
+        if ($this->context->getDrawingConfiguration()->getLanguageMode()) {
             return 1;
         }
         return $this->rowSpan;
@@ -157,9 +140,9 @@ class GridColumn extends AbstractGridObject
         if (empty($this->items)) {
             return null;
         }
-        $pageRecord = $this->backendLayout->getDrawingConfiguration()->getPageRecord();
+        $pageRecord = $this->context->getPageRecord();
         if (!$this->getBackendUser()->doesUserHaveAccess($pageRecord, Permission::CONTENT_EDIT)
-            || !$this->getBackendUser()->checkLanguageAccess($this->backendLayout->getDrawingConfiguration()->getLanguageColumnsPointer())) {
+            || !$this->getBackendUser()->checkLanguageAccess($this->context->getSiteLanguage()->getLanguageId())) {
             return null;
         }
         $pageTitleParamForAltDoc = '&recTitle=' . rawurlencode(
@@ -172,10 +155,10 @@ class GridColumn extends AbstractGridObject
 
     public function getNewContentUrl(): string
     {
-        $pageId = $this->backendLayout->getDrawingConfiguration()->getPageId();
+        $pageId = $this->context->getPageId();
         $urlParameters = [
             'id' => $pageId,
-            'sys_language_uid' => $this->backendLayout->getDrawingConfiguration()->getLanguageColumnsPointer(),
+            'sys_language_uid' => $this->context->getSiteLanguage()->getLanguageId(),
             'colPos' => $this->getColumnNumber(),
             'uid_pid' => $pageId,
             'returnUrl' => GeneralUtility::getIndpEnv('REQUEST_URI')
@@ -190,7 +173,7 @@ class GridColumn extends AbstractGridObject
     {
         $columnNumber = $this->getColumnNumber();
         $colTitle = (string)BackendUtility::getProcessedValue('tt_content', 'colPos', $columnNumber);
-        foreach ($this->backendLayout->getUsedColumns() as $colPos => $title) {
+        foreach ($this->context->getBackendLayout()->getUsedColumns() as $colPos => $title) {
             if ($colPos === $columnNumber) {
                 $colTitle = (string)$this->getLanguageService()->sL($title);
             }
@@ -221,9 +204,9 @@ class GridColumn extends AbstractGridObject
         if ($this->getBackendUser()->isAdmin()) {
             return true;
         }
-        $pageRecord = $this->backendLayout->getDrawingConfiguration()->getPageRecord();
+        $pageRecord = $this->context->getPageRecord();
         return !$pageRecord['editlock']
             && $this->getBackendUser()->doesUserHaveAccess($pageRecord, Permission::CONTENT_EDIT)
-            && $this->getBackendUser()->checkLanguageAccess($this->backendLayout->getDrawingConfiguration()->getLanguageColumnsPointer());
+            && $this->getBackendUser()->checkLanguageAccess($this->context->getSiteLanguage()->getLanguageId());
     }
 }
diff --git a/typo3/sysext/backend/Classes/View/BackendLayout/Grid/GridColumnItem.php b/typo3/sysext/backend/Classes/View/BackendLayout/Grid/GridColumnItem.php
index cf996b5e8fdcc4448640a6027e867a89b38021f2..e636f357b0ec74ede26f21cb4e7cda32589f7bf5 100644
--- a/typo3/sysext/backend/Classes/View/BackendLayout/Grid/GridColumnItem.php
+++ b/typo3/sysext/backend/Classes/View/BackendLayout/Grid/GridColumnItem.php
@@ -20,7 +20,7 @@ namespace TYPO3\CMS\Backend\View\BackendLayout\Grid;
 use TYPO3\CMS\Backend\Preview\StandardPreviewRendererResolver;
 use TYPO3\CMS\Backend\Routing\UriBuilder;
 use TYPO3\CMS\Backend\Utility\BackendUtility;
-use TYPO3\CMS\Backend\View\BackendLayout\BackendLayout;
+use TYPO3\CMS\Backend\View\PageLayoutContext;
 use TYPO3\CMS\Core\Imaging\Icon;
 use TYPO3\CMS\Core\Site\Entity\SiteLanguage;
 use TYPO3\CMS\Core\Type\Bitmask\Permission;
@@ -49,13 +49,11 @@ class GridColumnItem extends AbstractGridObject
      */
     protected $column;
 
-    public function __construct(BackendLayout $backendLayout, GridColumn $column, array $record)
+    public function __construct(PageLayoutContext $context, GridColumn $column, array $record)
     {
-        parent::__construct($backendLayout);
+        parent::__construct($context);
         $this->column = $column;
         $this->record = $record;
-        $backendLayout->getRecordRememberer()->rememberRecordUid((int)$record['uid']);
-        $backendLayout->getRecordRememberer()->rememberRecordUid((int)$record['l18n_parent']);
     }
 
     public function isVersioned(): bool
@@ -70,7 +68,7 @@ class GridColumnItem extends AbstractGridObject
             ->resolveRendererFor(
                 'tt_content',
                 $record,
-                $this->backendLayout->getDrawingConfiguration()->getPageId()
+                $this->context->getPageId()
             );
         $previewHeader = $previewRenderer->renderPageModulePreviewHeader($this);
         $previewContent = $previewRenderer->renderPageModulePreviewContent($this);
@@ -82,7 +80,7 @@ class GridColumnItem extends AbstractGridObject
         $wrapperClassNames = [];
         if ($this->isDisabled()) {
             $wrapperClassNames[] = 't3-page-ce-hidden t3js-hidden-record';
-        } elseif (!in_array($this->record['colPos'], $this->backendLayout->getColumnPositionNumbers())) {
+        } elseif (!in_array($this->record['colPos'], $this->context->getBackendLayout()->getColumnPositionNumbers())) {
             $wrapperClassNames[] = 't3-page-ce-warning';
         }
 
@@ -92,7 +90,7 @@ class GridColumnItem extends AbstractGridObject
     public function isDelible(): bool
     {
         $backendUser = $this->getBackendUser();
-        if (!$backendUser->doesUserHaveAccess($this->backendLayout->getDrawingConfiguration()->getPageRecord(), Permission::CONTENT_EDIT)) {
+        if (!$backendUser->doesUserHaveAccess($this->context->getPageRecord(), Permission::CONTENT_EDIT)) {
             return false;
         }
         return !(bool)($backendUser->getTSConfig()['options.']['disableDelete.']['tt_content'] ?? $backendUser->getTSConfig()['options.']['disableDelete'] ?? false);
@@ -126,7 +124,7 @@ class GridColumnItem extends AbstractGridObject
             ->resolveRendererFor(
                 'tt_content',
                 $record,
-                $this->backendLayout->getDrawingConfiguration()->getPageId()
+                $this->context->getPageId()
             );
         return $previewRenderer->renderPageModulePreviewFooter($this);
     }
@@ -162,9 +160,11 @@ class GridColumnItem extends AbstractGridObject
             $icon = BackendUtility::wrapClickMenuOnIcon($icon, $table, $row['uid']);
         }
         $icons[] = $icon;
-        $siteLanguage = $this->backendLayout->getDrawingConfiguration()->getSiteLanguage((int)$row['sys_language_uid']);
-        if ($siteLanguage instanceof SiteLanguage) {
-            $icons[] = $this->renderLanguageFlag($siteLanguage);
+        if ($row['sys_language_uid'] >= 0) {
+            $siteLanguage = $this->context->getSiteLanguage();
+            if ($siteLanguage instanceof SiteLanguage) {
+                $icons[] = $this->renderLanguageFlag($siteLanguage);
+            }
         }
 
         if ($lockInfo = BackendUtility::isRecordLocked('tt_content', $row['uid'])) {
@@ -204,22 +204,6 @@ class GridColumnItem extends AbstractGridObject
             || $enableCols['endtime'] && $row[$enableCols['endtime']] && $row[$enableCols['endtime']] < $GLOBALS['EXEC_TIME'];
     }
 
-    public function hasTranslation(): bool
-    {
-        $contentElements = $this->column->getRecords();
-        $id = $this->backendLayout->getDrawingConfiguration()->getPageId();
-        $language = $this->backendLayout->getDrawingConfiguration()->getLanguageColumnsPointer();
-        // If in default language, you may always create new entries
-        // Also, you may override this strict behavior via user TS Config
-        // If you do so, you're on your own and cannot rely on any support by the TYPO3 core.
-        $allowInconsistentLanguageHandling = (bool)(BackendUtility::getPagesTSconfig($id)['mod.']['web_layout.']['allowInconsistentLanguageHandling'] ?? false);
-        if ($language === 0 || $allowInconsistentLanguageHandling) {
-            return false;
-        }
-
-        return $this->backendLayout->getContentFetcher()->getTranslationData($contentElements, $language)['hasTranslations'] ?? false;
-    }
-
     public function isDeletePlaceholder(): bool
     {
         return VersionState::cast($this->record['t3ver_state'])->equals(VersionState::DELETE_PLACEHOLDER);
@@ -227,11 +211,11 @@ class GridColumnItem extends AbstractGridObject
 
     public function isEditable(): bool
     {
-        $languageId = $this->backendLayout->getDrawingConfiguration()->getLanguageColumnsPointer();
+        $languageId = $this->context->getSiteLanguage()->getLanguageId();
         if ($this->getBackendUser()->isAdmin()) {
             return true;
         }
-        $pageRecord = $this->backendLayout->getDrawingConfiguration()->getPageRecord();
+        $pageRecord = $this->context->getPageRecord();
         return !$pageRecord['editlock']
             && $this->getBackendUser()->doesUserHaveAccess($pageRecord, Permission::CONTENT_EDIT)
             && ($languageId === null || $this->getBackendUser()->checkLanguageAccess($languageId));
@@ -239,7 +223,7 @@ class GridColumnItem extends AbstractGridObject
 
     public function isDragAndDropAllowed(): bool
     {
-        $pageRecord = $this->backendLayout->getDrawingConfiguration()->getPageRecord();
+        $pageRecord = $this->context->getPageRecord();
         return (int)$this->record['l18n_parent'] === 0 &&
             (
                 $this->getBackendUser()->isAdmin()
@@ -262,10 +246,10 @@ class GridColumnItem extends AbstractGridObject
 
     public function getNewContentAfterUrl(): string
     {
-        $pageId = $this->backendLayout->getDrawingConfiguration()->getPageId();
+        $pageId = $this->context->getPageId();
         $urlParameters = [
             'id' => $pageId,
-            'sys_language_uid' => $this->backendLayout->getDrawingConfiguration()->getLanguageColumnsPointer(),
+            'sys_language_uid' => $this->context->getSiteLanguage()->getLanguageId(),
             'colPos' => $this->column->getColumnNumber(),
             'uid_pid' => -$this->record['uid'],
             'returnUrl' => GeneralUtility::getIndpEnv('REQUEST_URI')
diff --git a/typo3/sysext/backend/Classes/View/BackendLayout/Grid/LanguageColumn.php b/typo3/sysext/backend/Classes/View/BackendLayout/Grid/LanguageColumn.php
index a2dbb8b635e75e73672d30032d77850681f218d8..c28dc07064c30ece5a61db3817629610a27c5236 100644
--- a/typo3/sysext/backend/Classes/View/BackendLayout/Grid/LanguageColumn.php
+++ b/typo3/sysext/backend/Classes/View/BackendLayout/Grid/LanguageColumn.php
@@ -19,9 +19,8 @@ namespace TYPO3\CMS\Backend\View\BackendLayout\Grid;
 
 use TYPO3\CMS\Backend\Routing\UriBuilder;
 use TYPO3\CMS\Backend\Utility\BackendUtility;
-use TYPO3\CMS\Backend\View\BackendLayout\BackendLayout;
+use TYPO3\CMS\Backend\View\PageLayoutContext;
 use TYPO3\CMS\Core\Imaging\Icon;
-use TYPO3\CMS\Core\Site\Entity\SiteLanguage;
 use TYPO3\CMS\Core\Utility\GeneralUtility;
 use TYPO3\CMS\Core\Versioning\VersionState;
 
@@ -42,96 +41,45 @@ use TYPO3\CMS\Core\Versioning\VersionState;
  */
 class LanguageColumn extends AbstractGridObject
 {
-    /**
-     * @var SiteLanguage
-     */
-    protected $siteLanguage;
-
-    /**
-     * @var array
-     */
-    protected $localizedPageRecord = [];
-
     /**
      * @var array
      */
     protected $localizationConfiguration = [];
 
     /**
-     * @var GridColumn|null
+     * @var Grid|null
      */
     protected $grid;
 
-    public function __construct(BackendLayout $backendLayout, SiteLanguage $language)
-    {
-        parent::__construct($backendLayout);
-        $this->siteLanguage = $language;
-        $this->localizationConfiguration = BackendUtility::getPagesTSconfig($backendLayout->getDrawingConfiguration()->getPageId())['mod.']['web_layout.']['localization.'] ?? [];
-        if ($this->siteLanguage->getLanguageId() > 0) {
-            $pageLocalizationRecord = BackendUtility::getRecordLocalization(
-                'pages',
-                $backendLayout->getDrawingConfiguration()->getPageId(),
-                $language->getLanguageId()
-            );
-            if (is_array($pageLocalizationRecord)) {
-                $pageLocalizationRecord = reset($pageLocalizationRecord);
-            }
-            BackendUtility::workspaceOL('pages', $pageLocalizationRecord);
-            $this->localizedPageRecord = $pageLocalizationRecord;
-        } else {
-            $this->localizedPageRecord = $backendLayout->getDrawingConfiguration()->getPageRecord();
-        }
-    }
-
-    public function getLocalizedPageRecord(): ?array
-    {
-        return $this->localizedPageRecord ?: null;
-    }
+    /**
+     * @var array
+     */
+    protected $translationInfo = [
+        'hasStandaloneContent' => false,
+        'hasTranslations' => false,
+        'untranslatedRecordUids' => [],
+    ];
 
-    public function getSiteLanguage(): SiteLanguage
+    public function __construct(PageLayoutContext $context, Grid $grid, array $translationInfo)
     {
-        return $this->siteLanguage;
+        parent::__construct($context);
+        $this->localizationConfiguration = BackendUtility::getPagesTSconfig($context->getPageId())['mod.']['web_layout.']['localization.'] ?? [];
+        $this->grid = $grid;
+        $this->translationInfo = $translationInfo;
     }
 
-    public function getGrid(): Grid
+    public function getGrid(): ?Grid
     {
-        if (empty($this->grid)) {
-            $this->grid = $this->backendLayout->getGrid();
-        }
         return $this->grid;
     }
 
-    public function getLanguageModeLabelClass(): string
-    {
-        $contentRecordsPerColumn = $this->backendLayout->getContentFetcher()->getFlatContentRecords();
-        $translationData = $this->backendLayout->getContentFetcher()->getTranslationData($contentRecordsPerColumn, $this->siteLanguage->getLanguageId());
-        return $translationData['mode'] === 'mixed' ? 'danger' : 'info';
-    }
-
-    public function getLanguageMode(): string
-    {
-        switch ($this->backendLayout->getLanguageModeIdentifier()) {
-            case 'mixed':
-                $languageMode = $this->getLanguageService()->getLL('languageModeMixed');
-                break;
-            case 'connected':
-                $languageMode = $this->getLanguageService()->getLL('languageModeConnected');
-                break;
-            case 'free':
-                $languageMode = $this->getLanguageService()->getLL('languageModeFree');
-                break;
-            default:
-                $languageMode = '';
-        }
-        return $languageMode;
-    }
-
     public function getPageIcon(): string
     {
+        $localizedPageRecord = $this->context->getLocalizedPageRecord() ?? $this->context->getPageRecord();
         return BackendUtility::wrapClickMenuOnIcon(
-            $this->iconFactory->getIconForRecord('pages', $this->localizedPageRecord, Icon::SIZE_SMALL)->render(),
+            $this->iconFactory->getIconForRecord('pages', $localizedPageRecord, Icon::SIZE_SMALL)->render(),
             'pages',
-            $this->localizedPageRecord['uid']
+            $localizedPageRecord['uid']
         );
     }
 
@@ -142,8 +90,7 @@ class LanguageColumn extends AbstractGridObject
 
     public function getTranslationData(): array
     {
-        $contentFetcher = $this->backendLayout->getContentFetcher();
-        return $contentFetcher->getTranslationData($contentFetcher->getFlatContentRecords(), $this->siteLanguage->getLanguageId());
+        return $this->translationInfo;
     }
 
     public function getAllowTranslateCopy(): bool
@@ -171,13 +118,13 @@ class LanguageColumn extends AbstractGridObject
         $urlParameters = [
             'edit' => [
                 'pages' => [
-                    $this->localizedPageRecord['uid'] => 'edit'
+                    $this->context->getLocalizedPageRecord()['uid'] => 'edit'
                 ]
             ],
             // Disallow manual adjustment of the language field for pages
             'overrideVals' => [
                 'pages' => [
-                    'sys_language_uid' => $this->siteLanguage->getLanguageId()
+                    'sys_language_uid' => $this->context->getSiteLanguage()->getLanguageId()
                 ]
             ],
             'returnUrl' => GeneralUtility::getIndpEnv('REQUEST_URI')
@@ -188,7 +135,7 @@ class LanguageColumn extends AbstractGridObject
 
     public function getAllowViewPage(): bool
     {
-        return !VersionState::cast($this->backendLayout->getDrawingConfiguration()->getPageRecord()['t3ver_state'])->equals(VersionState::DELETE_PLACEHOLDER);
+        return !VersionState::cast($this->context->getPageRecord()['t3ver_state'])->equals(VersionState::DELETE_PLACEHOLDER);
     }
 
     public function getViewPageLinkTitle(): string
@@ -198,14 +145,14 @@ class LanguageColumn extends AbstractGridObject
 
     public function getViewPageOnClick(): string
     {
-        $pageId = $this->backendLayout->getDrawingConfiguration()->getPageId();
+        $pageId = $this->context->getPageId();
         return BackendUtility::viewOnClick(
             $pageId,
             '',
             BackendUtility::BEgetRootLine($pageId),
             '',
             '',
-            '&L=' . $this->backendLayout->getDrawingConfiguration()->getLanguageColumnsPointer()
+            '&L=' . $this->context->getSiteLanguage()->getLanguageId()
         );
     }
 }
diff --git a/typo3/sysext/backend/Classes/View/BackendLayout/RecordRememberer.php b/typo3/sysext/backend/Classes/View/BackendLayout/RecordRememberer.php
index 40f47db281a86448db4044b4e700d0226c31b8d8..e9e9d11a1e03f1616071f75cf6a0e0b5ecce9cc0 100644
--- a/typo3/sysext/backend/Classes/View/BackendLayout/RecordRememberer.php
+++ b/typo3/sysext/backend/Classes/View/BackendLayout/RecordRememberer.php
@@ -26,6 +26,14 @@ class RecordRememberer implements SingletonInterface
      */
     protected $rememberedUids = [];
 
+    public function rememberRecords(iterable $records): void
+    {
+        foreach ($records as $record) {
+            $this->rememberRecordUid($record['uid'] ?? 0);
+            $this->rememberRecordUid($record['l18n_parent'] ?? 0);
+        }
+    }
+
     public function rememberRecordUid(int $uid): void
     {
         $this->rememberedUids[$uid] = $uid;
diff --git a/typo3/sysext/backend/Classes/View/Drawing/BackendLayoutRenderer.php b/typo3/sysext/backend/Classes/View/Drawing/BackendLayoutRenderer.php
index 77ba30f9a45404baae6c150318c99ea7f7cc7a83..e2b6b9aaa2c15155a8cad1441b365fa695ddf48d 100644
--- a/typo3/sysext/backend/Classes/View/Drawing/BackendLayoutRenderer.php
+++ b/typo3/sysext/backend/Classes/View/Drawing/BackendLayoutRenderer.php
@@ -20,10 +20,14 @@ namespace TYPO3\CMS\Backend\View\Drawing;
 use Psr\Log\LoggerAwareTrait;
 use TYPO3\CMS\Backend\Clipboard\Clipboard;
 use TYPO3\CMS\Backend\Utility\BackendUtility;
-use TYPO3\CMS\Backend\View\BackendLayout\BackendLayout;
+use TYPO3\CMS\Backend\View\BackendLayout\ContentFetcher;
 use TYPO3\CMS\Backend\View\BackendLayout\Grid\Grid;
 use TYPO3\CMS\Backend\View\BackendLayout\Grid\GridColumn;
+use TYPO3\CMS\Backend\View\BackendLayout\Grid\GridColumnItem;
 use TYPO3\CMS\Backend\View\BackendLayout\Grid\GridRow;
+use TYPO3\CMS\Backend\View\BackendLayout\Grid\LanguageColumn;
+use TYPO3\CMS\Backend\View\BackendLayout\RecordRememberer;
+use TYPO3\CMS\Backend\View\PageLayoutContext;
 use TYPO3\CMS\Core\Authentication\BackendUserAuthentication;
 use TYPO3\CMS\Core\Imaging\Icon;
 use TYPO3\CMS\Core\Imaging\IconFactory;
@@ -57,9 +61,14 @@ class BackendLayoutRenderer
     protected $iconFactory;
 
     /**
-     * @var BackendLayout
+     * @var PageLayoutContext
      */
-    protected $backendLayout;
+    protected $context;
+
+    /**
+     * @var ContentFetcher
+     */
+    protected $contentFetcher;
 
     /**
      * @var Clipboard
@@ -71,9 +80,10 @@ class BackendLayoutRenderer
      */
     protected $view;
 
-    public function __construct(BackendLayout $backendLayout)
+    public function __construct(PageLayoutContext $context)
     {
-        $this->backendLayout = $backendLayout;
+        $this->context = $context;
+        $this->contentFetcher = GeneralUtility::makeInstance(ContentFetcher::class, $context);
         $this->iconFactory = GeneralUtility::makeInstance(IconFactory::class);
         $this->initializeClipboard();
         $objectManager = GeneralUtility::makeInstance(ObjectManager::class);
@@ -84,7 +94,64 @@ class BackendLayoutRenderer
         $this->view->getRenderingContext()->setControllerContext($controllerContext);
         $this->view->getRenderingContext()->getTemplatePaths()->fillDefaultsByPackageName('backend');
         $this->view->getRenderingContext()->setControllerName('PageLayout');
-        $this->view->assign('backendLayout', $backendLayout);
+        $this->view->assign('context', $context);
+    }
+
+    public function getGridForPageLayoutContext(PageLayoutContext $context): Grid
+    {
+        $grid = GeneralUtility::makeInstance(Grid::class, $context);
+        $recordRememberer = GeneralUtility::makeInstance(RecordRememberer::class);
+        if ($context->getDrawingConfiguration()->getLanguageMode()) {
+            $languageId = $context->getSiteLanguage()->getLanguageId();
+        } else {
+            $languageId = $context->getDrawingConfiguration()->getSelectedLanguageId();
+        }
+        foreach ($context->getBackendLayout()->getStructure()['__config']['backend_layout.']['rows.'] ?? [] as $row) {
+            $rowObject = GeneralUtility::makeInstance(GridRow::class, $context);
+            foreach ($row['columns.'] as $column) {
+                $columnObject = GeneralUtility::makeInstance(GridColumn::class, $context, $column);
+                $rowObject->addColumn($columnObject);
+                $records = $this->contentFetcher->getContentRecordsPerColumn((int)$column['colPos'], $languageId);
+                $recordRememberer->rememberRecords($records);
+                foreach ($records as $contentRecord) {
+                    $columnItem = GeneralUtility::makeInstance(GridColumnItem::class, $context, $columnObject, $contentRecord);
+                    $columnObject->addItem($columnItem);
+                }
+            }
+            $grid->addRow($rowObject);
+        }
+        return $grid;
+    }
+
+    /**
+     * @return LanguageColumn[]
+     */
+    public function getLanguageColumnsForPageLayoutContext(PageLayoutContext $context): iterable
+    {
+        $languageColumns = [];
+        foreach ($context->getLanguagesToShow() as $siteLanguage) {
+            $localizedLanguageId = $siteLanguage->getLanguageId();
+            if ($localizedLanguageId > 0) {
+                $localizedContext = $context->cloneForLanguage($siteLanguage);
+                if (!$localizedContext->getLocalizedPageRecord()) {
+                    continue;
+                }
+            } else {
+                $localizedContext = $context;
+            }
+            $translationInfo = $this->contentFetcher->getTranslationData(
+                $this->contentFetcher->getFlatContentRecords($localizedLanguageId),
+                $localizedContext->getSiteLanguage()->getLanguageId()
+            );
+            $languageColumnObject = GeneralUtility::makeInstance(
+                LanguageColumn::class,
+                $localizedContext,
+                $this->getGridForPageLayoutContext($localizedContext),
+                $translationInfo
+            );
+            $languageColumns[] = $languageColumnObject;
+        }
+        return $languageColumns;
     }
 
     /**
@@ -93,20 +160,20 @@ class BackendLayoutRenderer
      */
     public function drawContent(bool $renderUnused = true): string
     {
-        $this->view->assign('pageLayoutConfiguration', $this->backendLayout->getDrawingConfiguration());
-        $this->view->assign('hideRestrictedColumns', (bool)(BackendUtility::getPagesTSconfig($this->backendLayout->getDrawingConfiguration()->getPageId())['mod.']['web_layout.']['hideRestrictedCols'] ?? false));
-        if (!$this->backendLayout->getDrawingConfiguration()->getLanguageMode()) {
-            $this->view->assign('grid', $this->backendLayout->getGrid());
-        }
+        $this->view->assign('hideRestrictedColumns', (bool)(BackendUtility::getPagesTSconfig($this->context->getPageId())['mod.']['web_layout.']['hideRestrictedCols'] ?? false));
         $this->view->assign('newContentTitle', $this->getLanguageService()->getLL('newContentElement'));
         $this->view->assign('newContentTitleShort', $this->getLanguageService()->getLL('content'));
         $this->view->assign('allowEditContent', $this->getBackendUser()->check('tables_modify', 'tt_content'));
 
+        if ($this->context->getDrawingConfiguration()->getLanguageMode()) {
+            $this->view->assign('languageColumns', $this->getLanguageColumnsForPageLayoutContext($this->context));
+        } else {
+            $this->view->assign('grid', $this->getGridForPageLayoutContext($this->context));
+        }
+
         $rendered = $this->view->render('PageLayout');
         if ($renderUnused) {
-            $unusedBackendLayout = clone $this->backendLayout;
-            $unusedBackendLayout->getDrawingConfiguration()->setLanguageColumnsPointer($this->backendLayout->getDrawingConfiguration()->getLanguageColumnsPointer());
-            $unusedRecords = $this->backendLayout->getContentFetcher()->getUnusedRecords();
+            $unusedRecords = $this->contentFetcher->getUnusedRecords();
 
             if (!empty($unusedRecords)) {
                 $unusedElementsMessage = GeneralUtility::makeInstance(
@@ -119,14 +186,19 @@ class BackendLayoutRenderer
                 $queue = $service->getMessageQueueByIdentifier();
                 $queue->addMessage($unusedElementsMessage);
 
-                $unusedGrid = GeneralUtility::makeInstance(Grid::class, $unusedBackendLayout);
-                $unusedRow = GeneralUtility::makeInstance(GridRow::class, $unusedBackendLayout);
-                $unusedColumn = GeneralUtility::makeInstance(GridColumn::class, $unusedBackendLayout, ['colPos' => 99, 'name' => 'unused'], $unusedRecords);
+                $unusedGrid = GeneralUtility::makeInstance(Grid::class, $this->context);
+                $unusedRow = GeneralUtility::makeInstance(GridRow::class, $this->context);
+                $unusedColumn = GeneralUtility::makeInstance(GridColumn::class, $this->context, ['colPos' => false, 'name' => 'unused']);
 
                 $unusedGrid->addRow($unusedRow);
                 $unusedRow->addColumn($unusedColumn);
 
-                $this->view->assign('unusedGrid', $unusedGrid);
+                foreach ($unusedRecords as $unusedRecord) {
+                    $item = GeneralUtility::makeInstance(GridColumnItem::class, $this->context, $unusedColumn, $unusedRecord);
+                    $unusedColumn->addItem($item);
+                }
+
+                $this->view->assign('grid', $unusedGrid);
                 $rendered .= $this->view->render('UnusedRecords');
             }
         }
@@ -148,7 +220,7 @@ class BackendLayoutRenderer
         $this->clipboard->endClipboard();
 
         $elFromTable = $this->clipboard->elFromTable('tt_content');
-        if (!empty($elFromTable) && $this->backendLayout->getDrawingConfiguration()->isPageEditable()) {
+        if (!empty($elFromTable) && $this->context->isPageEditable()) {
             $pasteItem = (int)substr(key($elFromTable), 11);
             $pasteRecord = BackendUtility::getRecord('tt_content', (int)$pasteItem);
             $pasteTitle = (string)($pasteRecord['header'] ?: $pasteItem);
diff --git a/typo3/sysext/backend/Classes/View/Drawing/DrawingConfiguration.php b/typo3/sysext/backend/Classes/View/Drawing/DrawingConfiguration.php
index 46acee084707d983cee2f8de498c3d1c00627600..6cdcc814c750e7438fbf374f0b62b5aa09cbca88 100644
--- a/typo3/sysext/backend/Classes/View/Drawing/DrawingConfiguration.php
+++ b/typo3/sysext/backend/Classes/View/Drawing/DrawingConfiguration.php
@@ -17,19 +17,8 @@ declare(strict_types=1);
 
 namespace TYPO3\CMS\Backend\View\Drawing;
 
-use TYPO3\CMS\Backend\Routing\UriBuilder;
-use TYPO3\CMS\Backend\Utility\BackendUtility;
 use TYPO3\CMS\Core\Authentication\BackendUserAuthentication;
-use TYPO3\CMS\Core\Database\ConnectionPool;
-use TYPO3\CMS\Core\Database\Query\Restriction\DeletedRestriction;
-use TYPO3\CMS\Core\Database\Query\Restriction\WorkspaceRestriction;
-use TYPO3\CMS\Core\Exception\SiteNotFoundException;
 use TYPO3\CMS\Core\Localization\LanguageService;
-use TYPO3\CMS\Core\Site\Entity\NullSite;
-use TYPO3\CMS\Core\Site\Entity\SiteLanguage;
-use TYPO3\CMS\Core\Site\SiteFinder;
-use TYPO3\CMS\Core\Type\Bitmask\Permission;
-use TYPO3\CMS\Core\Utility\GeneralUtility;
 
 /**
  * Drawing Configuration
@@ -44,66 +33,70 @@ use TYPO3\CMS\Core\Utility\GeneralUtility;
 class DrawingConfiguration
 {
     /**
+     * @var int
+     */
+    protected $selectedLanguageId = 0;
+
+    /**
+     * Determines whether rendering should happen with a visually aligned
+     * connection between default language and translation. When rendered
+     * with this flag enabled, any translated versions are vertically
+     * aligned so they are rendered in the same visual row as the original.
+     *
      * @var bool
      */
     protected $defaultLanguageBinding = true;
 
     /**
+     * If TRUE, indicates that the current rendering method shows multiple
+     * languages (e.g. the "page" module is set in "Languages" mode.
+     *
      * @var bool
      */
     protected $languageMode = false;
 
     /**
      * Key => "Language ID", Value "Label of language"
+     *
      * @var array
      */
     protected $languageColumns = [];
 
     /**
-     * @var int
-     */
-    protected $languageColumnsPointer = 0;
-
-    /**
+     * Whether or not to show hidden records when rendering column contents.
+     *
      * @var bool
      */
     protected $showHidden = true;
 
     /**
+     * An array list of currently active columns. Only column identifiers
+     * (colPos value) which are contained in this array will be rendered in
+     * the page module.
+     *
      * @var array
      */
     protected $activeColumns = [1, 0, 2, 3];
 
     /**
-     * @var array
-     */
-    protected $contentTypeLabels = [];
-
-    /**
-     * @var array
-     */
-    protected $itemLabels = [];
-
-    /**
-     * @var int
-     */
-    protected $pageId = 0;
-
-    /**
-     * @var array
-     */
-    protected $pageRecord = [];
-
-    /**
-     * @var SiteLanguage[]
-     */
-    protected $siteLanguages = [];
-
-    /**
+     * Whether or not to show the "new content" buttons that open the new content
+     * wizard, when rendering columns. Disabling this will disable the rendering
+     * of new content buttons both in column top and after each content element.
+     *
      * @var bool
      */
     protected $showNewContentWizard = true;
 
+    public function getSelectedLanguageId(): int
+    {
+        return $this->selectedLanguageId;
+    }
+
+    public function setSelectedLanguageId(int $selectedLanguageId): void
+    {
+        $this->selectedLanguageId = $selectedLanguageId;
+    }
+
     public function getDefaultLanguageBinding(): bool
     {
         return $this->defaultLanguageBinding;
@@ -137,16 +130,6 @@ class DrawingConfiguration
         $this->languageColumns = $languageColumns;
     }
 
-    public function getLanguageColumnsPointer(): int
-    {
-        return $this->languageColumnsPointer;
-    }
-
-    public function setLanguageColumnsPointer(int $languageColumnsPointer): void
-    {
-        $this->languageColumnsPointer = $languageColumnsPointer;
-    }
-
     public function getShowHidden(): bool
     {
         return $this->showHidden;
@@ -167,63 +150,6 @@ class DrawingConfiguration
         $this->activeColumns = $activeColumns;
     }
 
-    public function getContentTypeLabels(): array
-    {
-        if (empty($this->contentTypeLabels)) {
-            foreach ($GLOBALS['TCA']['tt_content']['columns']['CType']['config']['items'] as $val) {
-                $this->contentTypeLabels[$val[1]] = $this->getLanguageService()->sL($val[0]);
-            }
-        }
-        return $this->contentTypeLabels;
-    }
-
-    public function getItemLabels(): array
-    {
-        if (empty($this->itemLabels)) {
-            foreach ($GLOBALS['TCA']['tt_content']['columns'] as $name => $val) {
-                $this->itemLabels[$name] = $this->getLanguageService()->sL($val['label']);
-            }
-        }
-        return $this->itemLabels;
-    }
-
-    public function getPageId(): int
-    {
-        return $this->pageId;
-    }
-
-    public function setPageId(int $pageId): void
-    {
-        $this->pageId = $pageId;
-        $this->pageRecord = BackendUtility::getRecordWSOL('pages', $pageId);
-    }
-
-    public function getPageRecord(): array
-    {
-        return $this->pageRecord;
-    }
-
-    /**
-     * @return SiteLanguage[]
-     */
-    public function getSiteLanguages(): array
-    {
-        if (empty($this->setSiteLanguages)) {
-            try {
-                $site = GeneralUtility::makeInstance(SiteFinder::class)->getSiteByPageId($this->pageId);
-            } catch (SiteNotFoundException $e) {
-                $site = new NullSite();
-            }
-            $this->siteLanguages = $site->getAvailableLanguages($this->getBackendUser(), false, $this->pageId);
-        }
-        return $this->siteLanguages;
-    }
-
-    public function getSiteLanguage(int $languageUid): ?SiteLanguage
-    {
-        return $this->getSiteLanguages()[$languageUid] ?? null;
-    }
-
     public function getShowNewContentWizard(): bool
     {
         return $this->showNewContentWizard;
@@ -234,104 +160,6 @@ class DrawingConfiguration
         $this->showNewContentWizard = $showNewContentWizard;
     }
 
-    public function getLocalizedPageTitle(): string
-    {
-        if ($this->getLanguageColumnsPointer()) {
-            $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)
-                ->getQueryBuilderForTable('pages');
-            $queryBuilder->getRestrictions()
-                ->removeAll()
-                ->add(GeneralUtility::makeInstance(DeletedRestriction::class))
-                ->add(GeneralUtility::makeInstance(WorkspaceRestriction::class, (int)$this->getBackendUser()->workspace));
-            $localizedPage = $queryBuilder
-                ->select('*')
-                ->from('pages')
-                ->where(
-                    $queryBuilder->expr()->eq(
-                        $GLOBALS['TCA']['pages']['ctrl']['transOrigPointerField'],
-                        $queryBuilder->createNamedParameter($this->getPageId(), \PDO::PARAM_INT)
-                    ),
-                    $queryBuilder->expr()->eq(
-                        $GLOBALS['TCA']['pages']['ctrl']['languageField'],
-                        $queryBuilder->createNamedParameter($this->getLanguageColumnsPointer(), \PDO::PARAM_INT)
-                    )
-                )
-                ->setMaxResults(1)
-                ->execute()
-                ->fetch();
-            BackendUtility::workspaceOL('pages', $localizedPage);
-            return $localizedPage['title'];
-        }
-        return $this->getPageRecord()['title'];
-    }
-
-    public function isPageEditable(): bool
-    {
-        if ($this->getBackendUser()->isAdmin()) {
-            return true;
-        }
-        $pageRecord = $this->getPageRecord();
-        return !$pageRecord['editlock'] && $this->getBackendUser()->doesUserHaveAccess($pageRecord, Permission::PAGE_EDIT);
-    }
-
-    public function getNewLanguageOptions(): array
-    {
-        if (!$this->getBackendUser()->check('tables_modify', 'pages')) {
-            return '';
-        }
-        $id = $this->getPageId();
-
-        // First, select all languages that are available for the current user
-        $availableTranslations = [];
-        foreach ($this->getSiteLanguages() as $language) {
-            if ($language->getLanguageId() === 0) {
-                continue;
-            }
-            $availableTranslations[$language->getLanguageId()] = $language->getTitle();
-        }
-
-        // Then, subtract the languages which are already on the page:
-        $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('pages');
-        $queryBuilder->getRestrictions()->removeAll()
-            ->add(GeneralUtility::makeInstance(DeletedRestriction::class))
-            ->add(GeneralUtility::makeInstance(WorkspaceRestriction::class, (int)$this->getBackendUser()->workspace));
-        $queryBuilder->select('uid', $GLOBALS['TCA']['pages']['ctrl']['languageField'])
-            ->from('pages')
-            ->where(
-                $queryBuilder->expr()->eq(
-                    $GLOBALS['TCA']['pages']['ctrl']['transOrigPointerField'],
-                    $queryBuilder->createNamedParameter($id, \PDO::PARAM_INT)
-                )
-            );
-        $statement = $queryBuilder->execute();
-        while ($row = $statement->fetch()) {
-            unset($availableTranslations[(int)$row[$GLOBALS['TCA']['pages']['ctrl']['languageField']]]);
-        }
-        // If any languages are left, make selector:
-        $options = [];
-        if (!empty($availableTranslations)) {
-            $options[] = $this->getLanguageService()->getLL('new_language');
-            foreach ($availableTranslations as $languageUid => $languageTitle) {
-                // Build localize command URL to DataHandler (tce_db)
-                // which redirects to FormEngine (record_edit)
-                // which, when finished editing should return back to the current page (returnUrl)
-                $parameters = [
-                    'justLocalized' => 'pages:' . $id . ':' . $languageUid,
-                    'returnUrl' => GeneralUtility::getIndpEnv('REQUEST_URI')
-                ];
-                $uriBuilder = GeneralUtility::makeInstance(UriBuilder::class);
-                $redirectUrl = (string)$uriBuilder->buildUriFromRoute('record_edit', $parameters);
-                $targetUrl = BackendUtility::getLinkToDataHandlerAction(
-                    '&cmd[pages][' . $id . '][localize]=' . $languageUid,
-                    $redirectUrl
-                );
-
-                $options[$targetUrl] = $languageTitle;
-            }
-        }
-        return $options;
-    }
-
     protected function getBackendUser(): BackendUserAuthentication
     {
         return $GLOBALS['BE_USER'];
diff --git a/typo3/sysext/backend/Classes/View/PageLayoutContext.php b/typo3/sysext/backend/Classes/View/PageLayoutContext.php
new file mode 100644
index 0000000000000000000000000000000000000000..7df86cca58940e9685214d2b0da031ce3e6eb2f1
--- /dev/null
+++ b/typo3/sysext/backend/Classes/View/PageLayoutContext.php
@@ -0,0 +1,366 @@
+<?php
+
+declare(strict_types=1);
+
+namespace TYPO3\CMS\Backend\View;
+
+/*
+ * This file is part of the TYPO3 CMS project.
+ *
+ * It is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, either version 2
+ * of the License, or any later version.
+ *
+ * For the full copyright and license information, please read the
+ * LICENSE.txt file that was distributed with this source code.
+ *
+ * The TYPO3 project - inspiring people to share!
+ */
+
+use TYPO3\CMS\Backend\Routing\UriBuilder;
+use TYPO3\CMS\Backend\Utility\BackendUtility;
+use TYPO3\CMS\Backend\View\BackendLayout\BackendLayout;
+use TYPO3\CMS\Backend\View\BackendLayout\ContentFetcher;
+use TYPO3\CMS\Backend\View\Drawing\BackendLayoutRenderer;
+use TYPO3\CMS\Backend\View\Drawing\DrawingConfiguration;
+use TYPO3\CMS\Core\Authentication\BackendUserAuthentication;
+use TYPO3\CMS\Core\Database\ConnectionPool;
+use TYPO3\CMS\Core\Database\Query\Restriction\DeletedRestriction;
+use TYPO3\CMS\Core\Database\Query\Restriction\WorkspaceRestriction;
+use TYPO3\CMS\Core\Exception\SiteNotFoundException;
+use TYPO3\CMS\Core\Localization\LanguageService;
+use TYPO3\CMS\Core\Site\Entity\NullSite;
+use TYPO3\CMS\Core\Site\Entity\Site;
+use TYPO3\CMS\Core\Site\Entity\SiteLanguage;
+use TYPO3\CMS\Core\Site\SiteFinder;
+use TYPO3\CMS\Core\Type\Bitmask\Permission;
+use TYPO3\CMS\Core\Utility\GeneralUtility;
+
+class PageLayoutContext
+{
+    /**
+     * @var BackendLayout
+     */
+    protected $backendLayout;
+
+    /**
+     * @var DrawingConfiguration
+     */
+    protected $drawingConfiguration;
+
+    /**
+     * @var ContentFetcher
+     */
+    protected $contentFetcher;
+
+    /**
+     * @var BackendLayoutRenderer
+     */
+    protected $backendLayoutRenderer;
+
+    /**
+     * @var array
+     */
+    protected $pageRecord;
+
+    /**
+     * @var array|null
+     */
+    protected $localizedPageRecord;
+
+    /**
+     * @var int
+     */
+    protected $pageId;
+
+    /**
+     * @var SiteLanguage[]
+     */
+    protected $siteLanguages;
+
+    /**
+     * @var SiteLanguage
+     */
+    protected $siteLanguage;
+
+    /**
+     * @var Site
+     */
+    protected $site;
+
+    /**
+     * Array of content type labels. Key is CType, value is either a plain text
+     * label or an LLL:EXT:... reference to a specific label.
+     *
+     * @var array
+     */
+    protected $contentTypeLabels = [];
+
+    /**
+     * Labels for columns, in format of TCA select options. Numerically indexed
+     * array of numerically indexed value arrays, with each sub-array containing
+     * at least two values and one optional third value:
+     *
+     * - label (hardcoded or LLL:EXT:... reference. MANDATORY)
+     * - value (colPos of column. MANDATORY)
+     * - icon (icon name or file reference. OPTIONAL)
+     *
+     * @var array
+     */
+    protected $itemLabels = [];
+
+    public function __construct(array $pageRecord, BackendLayout $backendLayout)
+    {
+        $this->pageId = (int)$pageRecord['uid'];
+        try {
+            $this->site = GeneralUtility::makeInstance(SiteFinder::class)->getSiteByPageId($this->pageId);
+        } catch (SiteNotFoundException $e) {
+            $this->site = new NullSite();
+        }
+        // TODO: retrieve implementation class names from Site?
+        $this->pageRecord = $pageRecord;
+        $this->backendLayout = $backendLayout;
+        $this->drawingConfiguration = GeneralUtility::makeInstance(DrawingConfiguration::class);
+        $this->contentFetcher = GeneralUtility::makeInstance(ContentFetcher::class, $this);
+        $this->backendLayoutRenderer = GeneralUtility::makeInstance(BackendLayoutRenderer::class, $this);
+        $this->siteLanguages = $this->site->getAvailableLanguages($this->getBackendUser(), false, $this->pageId);
+        $this->siteLanguage = $this->site->getDefaultLanguage();
+    }
+
+    public function cloneForLanguage(SiteLanguage $language): self
+    {
+        $copy = clone $this;
+        $copy->setSiteLanguage($language);
+        return $copy;
+    }
+
+    /**
+     * @param SiteLanguage $siteLanguage
+     */
+    public function setSiteLanguage(SiteLanguage $siteLanguage): void
+    {
+        $this->siteLanguage = $siteLanguage;
+        $languageId = $siteLanguage->getLanguageId();
+        if ($languageId > 0) {
+            $pageLocalizationRecord = BackendUtility::getRecordLocalization(
+                'pages',
+                $this->getPageId(),
+                $languageId
+            );
+            $pageLocalizationRecord = reset($pageLocalizationRecord);
+            if (!empty($pageLocalizationRecord)) {
+                BackendUtility::workspaceOL('pages', $pageLocalizationRecord);
+                $this->localizedPageRecord = $pageLocalizationRecord ?: null;
+            }
+        }
+    }
+
+    public function getBackendLayout(): BackendLayout
+    {
+        return $this->backendLayout;
+    }
+
+    public function getDrawingConfiguration(): DrawingConfiguration
+    {
+        return $this->drawingConfiguration;
+    }
+
+    public function getBackendLayoutRenderer(): BackendLayoutRenderer
+    {
+        return $this->backendLayoutRenderer;
+    }
+
+    public function getBackendUser(): BackendUserAuthentication
+    {
+        return $GLOBALS['BE_USER'];
+    }
+
+    public function getPageRecord(): array
+    {
+        return $this->pageRecord;
+    }
+
+    public function getPageId(): int
+    {
+        return $this->pageId;
+    }
+
+    /**
+     * @return SiteLanguage[]
+     */
+    public function getSiteLanguages(): iterable
+    {
+        return $this->siteLanguages;
+    }
+
+    /**
+     * @return SiteLanguage[]
+     */
+    public function getLanguagesToShow(): iterable
+    {
+        $selectedLanguageId = $this->drawingConfiguration->getSelectedLanguageId();
+        if ($selectedLanguageId > 0) {
+            // A specific language is selected; compose a list of default language plus selected language
+            return [
+                $this->site->getDefaultLanguage(),
+                $this->site->getLanguageById($selectedLanguageId)
+            ];
+        }
+        return $this->getSiteLanguages();
+    }
+
+    public function getSiteLanguage(?int $languageId = null): SiteLanguage
+    {
+        if ($languageId === null) {
+            return $this->siteLanguage;
+        }
+        return $this->site->getLanguageById($languageId);
+    }
+
+    public function isPageEditable(): bool
+    {
+        // TODO: refactor to page permissions container
+        if ($this->getBackendUser()->isAdmin()) {
+            return true;
+        }
+        $pageRecord = $this->getPageRecord();
+        return !$pageRecord['editlock'] && $this->getBackendUser()->doesUserHaveAccess($pageRecord, Permission::PAGE_EDIT);
+    }
+
+    public function getAllowNewContent(): bool
+    {
+        $pageId = $this->getPageId();
+        $allowInconsistentLanguageHandling = (bool)(BackendUtility::getPagesTSconfig($pageId)['mod.']['web_layout.']['allowInconsistentLanguageHandling'] ?? false);
+        if (!$allowInconsistentLanguageHandling && $this->getLanguageModeIdentifier() === 'connected') {
+            return false;
+        }
+        return true;
+    }
+
+    public function getContentTypeLabels(): array
+    {
+        if (empty($this->contentTypeLabels)) {
+            foreach ($GLOBALS['TCA']['tt_content']['columns']['CType']['config']['items'] as $val) {
+                $this->contentTypeLabels[$val[1]] = $this->getLanguageService()->sL($val[0]);
+            }
+        }
+        return $this->contentTypeLabels;
+    }
+
+    public function getItemLabels(): array
+    {
+        if (empty($this->itemLabels)) {
+            foreach ($GLOBALS['TCA']['tt_content']['columns'] as $name => $val) {
+                $this->itemLabels[$name] = $this->getLanguageService()->sL($val['label']);
+            }
+        }
+        return $this->itemLabels;
+    }
+
+    public function getLanguageModeLabelClass(): string
+    {
+        $languageId = $this->siteLanguage->getLanguageId();
+        $contentRecordsPerColumn = $this->contentFetcher->getFlatContentRecords($languageId);
+        $translationData = $this->contentFetcher->getTranslationData($contentRecordsPerColumn, $languageId);
+        return $translationData['mode'] === 'mixed' ? 'danger' : 'info';
+    }
+
+    public function getLanguageMode(): string
+    {
+        switch ($this->getLanguageModeIdentifier()) {
+            case 'mixed':
+                $languageMode = $this->getLanguageService()->getLL('languageModeMixed');
+                break;
+            case 'connected':
+                $languageMode = $this->getLanguageService()->getLL('languageModeConnected');
+                break;
+            case 'free':
+                $languageMode = $this->getLanguageService()->getLL('languageModeFree');
+                break;
+            default:
+                $languageMode = '';
+        }
+        return $languageMode;
+    }
+
+    public function getLanguageModeIdentifier(): string
+    {
+        $contentRecordsPerColumn = $this->contentFetcher->getContentRecordsPerColumn(null, $this->siteLanguage->getLanguageId());
+        $contentRecords = empty($contentRecordsPerColumn) ? [] : array_merge(...$contentRecordsPerColumn);
+        $translationData = $this->contentFetcher->getTranslationData($contentRecords, $this->siteLanguage->getLanguageId());
+        return $translationData['mode'] ?? '';
+    }
+
+    public function getNewLanguageOptions(): array
+    {
+        if (!$this->getBackendUser()->check('tables_modify', 'pages')) {
+            return [];
+        }
+        $id = $this->getPageId();
+
+        // First, select all languages that are available for the current user
+        $availableTranslations = [];
+        foreach ($this->getSiteLanguages() as $language) {
+            if ($language->getLanguageId() === 0) {
+                continue;
+            }
+            $availableTranslations[$language->getLanguageId()] = $language->getTitle();
+        }
+
+        // Then, subtract the languages which are already on the page:
+        $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('pages');
+        $queryBuilder->getRestrictions()->removeAll()
+            ->add(GeneralUtility::makeInstance(DeletedRestriction::class))
+            ->add(GeneralUtility::makeInstance(WorkspaceRestriction::class, (int)$this->getBackendUser()->workspace));
+        $queryBuilder->select('uid', $GLOBALS['TCA']['pages']['ctrl']['languageField'])
+            ->from('pages')
+            ->where(
+                $queryBuilder->expr()->eq(
+                    $GLOBALS['TCA']['pages']['ctrl']['transOrigPointerField'],
+                    $queryBuilder->createNamedParameter($id, \PDO::PARAM_INT)
+                )
+            );
+        $statement = $queryBuilder->execute();
+        while ($row = $statement->fetch()) {
+            unset($availableTranslations[(int)$row[$GLOBALS['TCA']['pages']['ctrl']['languageField']]]);
+        }
+        // If any languages are left, make selector:
+        $options = [];
+        if (!empty($availableTranslations)) {
+            $options[] = $this->getLanguageService()->getLL('new_language');
+            foreach ($availableTranslations as $languageUid => $languageTitle) {
+                // Build localize command URL to DataHandler (tce_db)
+                // which redirects to FormEngine (record_edit)
+                // which, when finished editing should return back to the current page (returnUrl)
+                $parameters = [
+                    'justLocalized' => 'pages:' . $id . ':' . $languageUid,
+                    'returnUrl' => GeneralUtility::getIndpEnv('REQUEST_URI')
+                ];
+                $uriBuilder = GeneralUtility::makeInstance(UriBuilder::class);
+                $redirectUrl = (string)$uriBuilder->buildUriFromRoute('record_edit', $parameters);
+                $targetUrl = BackendUtility::getLinkToDataHandlerAction(
+                    '&cmd[pages][' . $id . '][localize]=' . $languageUid,
+                    $redirectUrl
+                );
+
+                $options[$targetUrl] = $languageTitle;
+            }
+        }
+        return $options;
+    }
+
+    public function getLocalizedPageTitle(): string
+    {
+        return $this->getLocalizedPageRecord()['title'] ?? $this->getPageRecord()['title'];
+    }
+
+    public function getLocalizedPageRecord(): ?array
+    {
+        return $this->localizedPageRecord;
+    }
+
+    protected function getLanguageService(): LanguageService
+    {
+        return $GLOBALS['LANG'];
+    }
+}
diff --git a/typo3/sysext/backend/Classes/View/PageLayoutView.php b/typo3/sysext/backend/Classes/View/PageLayoutView.php
index 2a55b74894c6b972cd5d403601d592477030244a..55609547a7ccadcd831ea01eb898597ef89752d4 100644
--- a/typo3/sysext/backend/Classes/View/PageLayoutView.php
+++ b/typo3/sysext/backend/Classes/View/PageLayoutView.php
@@ -23,7 +23,6 @@ use TYPO3\CMS\Backend\Clipboard\Clipboard;
 use TYPO3\CMS\Backend\Controller\Page\LocalizationController;
 use TYPO3\CMS\Backend\Routing\UriBuilder;
 use TYPO3\CMS\Backend\Utility\BackendUtility;
-use TYPO3\CMS\Backend\View\Drawing\DrawingConfiguration;
 use TYPO3\CMS\Backend\View\Event\AfterSectionMarkupGeneratedEvent;
 use TYPO3\CMS\Backend\View\Event\BeforeSectionMarkupGeneratedEvent;
 use TYPO3\CMS\Core\Authentication\BackendUserAuthentication;
@@ -207,31 +206,33 @@ class PageLayoutView implements LoggerAwareInterface
     }
 
     /**
-     * @param DrawingConfiguration $drawingConfiguration
+     * @param PageLayoutContext $context
      * @return PageLayoutView
      * @internal
      */
-    public static function createFromDrawingConfiguration(DrawingConfiguration $drawingConfiguration): PageLayoutView
+    public static function createFromPageLayoutContext(PageLayoutContext $context): PageLayoutView
     {
+        $drawingConfiguration = $context->getDrawingConfiguration();
+        $languageId = $drawingConfiguration->getSelectedLanguageId();
         /** @var PageLayoutView $pageLayoutView */
         $pageLayoutView = GeneralUtility::makeInstance(self::class);
-        $pageLayoutView->id = $drawingConfiguration->getPageId();
+        $pageLayoutView->id = $context->getPageId();
         $pageLayoutView->pageinfo = BackendUtility::readPageAccess($pageLayoutView->id, '');
-        $pageLayoutView->pageRecord = $drawingConfiguration->getPageRecord();
+        $pageLayoutView->pageRecord = $context->getPageRecord();
         $pageLayoutView->option_newWizard = $drawingConfiguration->getShowNewContentWizard();
         $pageLayoutView->defLangBinding = $drawingConfiguration->getDefaultLanguageBinding();
         $pageLayoutView->tt_contentConfig['cols'] = implode(',', $drawingConfiguration->getActiveColumns());
         $pageLayoutView->tt_contentConfig['activeCols'] = implode(',', $drawingConfiguration->getActiveColumns());
         $pageLayoutView->tt_contentConfig['showHidden'] = $drawingConfiguration->getShowHidden();
-        $pageLayoutView->tt_contentConfig['sys_language_uid'] = $drawingConfiguration->getLanguageColumnsPointer();
+        $pageLayoutView->tt_contentConfig['sys_language_uid'] = $languageId;
         if ($drawingConfiguration->getLanguageMode()) {
             $pageLayoutView->tt_contentConfig['languageMode'] = 1;
             $pageLayoutView->tt_contentConfig['languageCols'] = $drawingConfiguration->getLanguageColumns();
-            $pageLayoutView->tt_contentConfig['languageColsPointer'] = $drawingConfiguration->getLanguageColumnsPointer();
+            $pageLayoutView->tt_contentConfig['languageColsPointer'] = $languageId;
         }
-        $pageLayoutView->doEdit = $pageLayoutView->isContentEditable($drawingConfiguration->getLanguageColumnsPointer());
-        $pageLayoutView->CType_labels = $drawingConfiguration->getContentTypeLabels();
-        $pageLayoutView->itemLabels = $drawingConfiguration->getItemLabels();
+        $pageLayoutView->doEdit = $pageLayoutView->isContentEditable($languageId);
+        $pageLayoutView->CType_labels = $context->getContentTypeLabels();
+        $pageLayoutView->itemLabels = $context->getItemLabels();
         return $pageLayoutView;
     }
 
diff --git a/typo3/sysext/backend/Resources/Private/Partials/PageLayout/Grid/Column.html b/typo3/sysext/backend/Resources/Private/Partials/PageLayout/Grid/Column.html
index eaf0d5e6010ed2365fa8868262492baf1ee31b34..dff2b542656280075581b96dc001745a71d4baf0 100644
--- a/typo3/sysext/backend/Resources/Private/Partials/PageLayout/Grid/Column.html
+++ b/typo3/sysext/backend/Resources/Private/Partials/PageLayout/Grid/Column.html
@@ -25,9 +25,9 @@
             </f:else>
         </f:if>
     </div>
-    <f:if condition="{allowEditContent} && {column.contentEditable} && {grid.allowNewContent}">
-        <div class="t3-page-ce t3js-page-ce" data-page="{pageLayoutConfiguration.pageId}" id="{column.uniqueId}">
-            <div class="t3js-page-new-ce t3-page-ce-wrapper-new-ce" id="colpos-{column.columnNumber}-page-{pageLayoutConfiguration.pageId}-{column.uniqueId}">
+    <f:if condition="{allowEditContent} && {column.contentEditable} && {column.context.allowNewContent}">
+        <div class="t3-page-ce t3js-page-ce" data-page="{column.context.pageId}" id="{column.uniqueId}">
+            <div class="t3js-page-new-ce t3-page-ce-wrapper-new-ce" id="colpos-{column.columnNumber}-page-{column.context.pageId}-{column.uniqueId}">
                 <a href="{column.newContentUrl}" title="{newContentTitle}" data-title="{newContentTitle}"
                     class="btn btn-default btn-sm t3js-toggle-new-content-element-wizard">
                     <core:icon identifier="actions-add" />
diff --git a/typo3/sysext/backend/Resources/Private/Partials/PageLayout/LanguageColumns.html b/typo3/sysext/backend/Resources/Private/Partials/PageLayout/LanguageColumns.html
index e3cf8f2ba8b85fc3e814cf3da30bb02e32063d46..172d073b07bb5ed4dbb098aade23da40ac8681c6 100644
--- a/typo3/sysext/backend/Resources/Private/Partials/PageLayout/LanguageColumns.html
+++ b/typo3/sysext/backend/Resources/Private/Partials/PageLayout/LanguageColumns.html
@@ -1,8 +1,8 @@
-<f:if condition="{pageLayoutConfiguration.newLanguageOptions}">
+<f:if condition="{context.newLanguageOptions}">
     <div class="form-inline form-inline-spaced">
         <div class="form-group">
             <select class="form-control input-sm" name="createNewLanguage" onchange="window.location.href=this.options[this.selectedIndex].value">'
-                <f:for each="{pageLayoutConfiguration.newLanguageOptions}" as="languageName" key="url">
+                <f:for each="{context.newLanguageOptions}" as="languageName" key="url">
                     <option value="{url}">{languageName}</option>
                 </f:for>
             </select>
@@ -12,22 +12,22 @@
 <div class="t3-grid-container">
     <table cellpadding="0" cellspacing="0" class="t3-page-columns t3-grid-table t3js-page-columns">
         <tr>
-            <f:for each="{backendLayout.languageColumns}" as="languageColumn">
+            <f:for each="{languageColumns}" as="languageColumn">
                 <td valign="top"
                     class="t3-page-column t3-page-column-lang-name"
-                    data-language-uid="{languageColumn.siteLanguage.languageId}"
-                    data-language-title="{languageColumn.siteLanguage.title}"
-                    data-flag-identifier="{languageColumn.siteLanguage.flagIdentifier}"
+                    data-language-uid="{languageColumn.context.siteLanguage.languageId}"
+                    data-language-title="{languageColumn.context.siteLanguage.title}"
+                    data-flag-identifier="{languageColumn.context.siteLanguage.flagIdentifier}"
                 >
-                    <h2>{languageColumn.siteLanguage.title}</h2>
-                    <f:if condition="{languageColumn.languageMode}">
-                        <span class="label label-{languageColumn.languageModeLabelClass}">{languageColumn.languageMode}</span>
+                    <h2>{languageColumn.context.siteLanguage.title}</h2>
+                    <f:if condition="{languageColumn.context.languageMode}">
+                        <span class="label label-{languageColumn.context.languageModeLabelClass}">{languageColumn.context.languageMode}</span>
                     </f:if>
                 </td>
             </f:for>
         </tr>
         <tr>
-            <f:for each="{backendLayout.languageColumns}" as="languageColumn">
+            <f:for each="{languageColumns}" as="languageColumn">
                 <td class="t3-page-column t3-page-lang-label nowrap">
                     <div class="btn-group">
                         <f:if condition="{languageColumn.allowViewPage}">
@@ -40,30 +40,30 @@
                                 <core:icon identifier="actions-open" />
                             </a>
                         </f:if>
-                        <f:if condition="{allowEditContent} && {languageColumn.siteLanguage.languageId} && {languageColumn.translationData.untranslatedRecordUids}">
+                        <f:if condition="{allowEditContent} && {languageColumn.context.siteLanguage.languageId} && {languageColumn.translationData.untranslatedRecordUids}">
                             <a href="#" class="btn btn-default btn-sm t3js-localize disabled"
-                                title="{languageColumn.translatePageTitle}"
-                                data-page="{languageColumn.localizedPageRecord.title}"
+                                title="{languageColumn.context.translatePageTitle}"
+                                data-page="{languageColumn.context.localizedPageRecord.title}"
                                 data-has-elements="{languageColumn.translationData.hasTranslations as integer}"
                                 data-allow-copy="{languageColumn.allowTranslateCopy as integer}"
                                 data-allow-translate="{languageColumn.allowTranslate as integer}"
                                 data-table="tt_content"
-                                data-page-id="{backendLayout.drawingConfiguration.pageId}"
-                                data-language-id="{languageColumn.siteLanguage.languageId}"
-                                data-language-name="{languageColumn.siteLanguage.title}">
+                                data-page-id="{context.pageId}"
+                                data-language-id="{languageColumn.context.siteLanguage.languageId}"
+                                data-language-name="{languageColumn.context.siteLanguage.title}">
                                 <core:icon identifier="actions-localize" />
                                 {languageColumn.translatePageTitle}
                             </a>
                         </f:if>
                     </div>
                     {languageColumn.pageIcon -> f:format.raw()}
-                    {languageColumn.localizedPageRecord.title}
+                    {languageColumn.context.localizedPageTitle}
                 </td>
             </f:for>
         </tr>
-        <f:for each="{backendLayout.drawingConfiguration.activeColumns}" as="columnNumber">
+        <f:for each="{context.drawingConfiguration.activeColumns}" as="columnNumber">
             <tr>
-                <f:for each="{backendLayout.languageColumns}" as="languageColumn">
+                <f:for each="{languageColumns}" as="languageColumn">
                     <f:variable name="grid" value="{languageColumn.grid}" />
                     <f:variable name="column" value="{be:languageColumn(languageColumn: languageColumn, columnNumber: columnNumber)}" />
                     <f:render partial="PageLayout/Grid/Column" arguments="{_all}" />
diff --git a/typo3/sysext/backend/Resources/Private/Partials/PageLayout/Record.html b/typo3/sysext/backend/Resources/Private/Partials/PageLayout/Record.html
index 2b1351039838197537b6fc819f01da558f7946cc..e4d25412d48b5af0d8ce689c287a36a74d645860 100644
--- a/typo3/sysext/backend/Resources/Private/Partials/PageLayout/Record.html
+++ b/typo3/sysext/backend/Resources/Private/Partials/PageLayout/Record.html
@@ -1,4 +1,4 @@
-{f:if(condition: '{item.disabled} && {item.backendLayout.drawingConfiguration.showHidden} == 0', then: 'display: none;') -> f:variable(name: 'style')}
+{f:if(condition: '{item.disabled} && {item.context.drawingConfiguration.showHidden} == 0', then: 'display: none;') -> f:variable(name: 'style')}
 <div class="t3-page-ce {item.wrapperClassName} t3js-page-ce t3js-page-ce-sortable" id="element-tt_content-{item.record.uid}" data-table="tt_content" data-uid="{item.record.uid}" style="{style}">
     <div class="t3-page-ce-dragitem" id="{item.uniqueId}">
         <f:render partial="PageLayout/Record/{item.record.CType}/Header" arguments="{_all}" optional="1">
@@ -15,8 +15,8 @@
             </f:render>
         </div>
     </div>
-    <f:if condition="{allowEditContent} && {item.column.contentEditable} && {grid.allowNewContent}">
-        <div class="t3js-page-new-ce t3-page-ce-wrapper-new-ce" id="colpos-{item.column.columnNumber}-page-{pageLayoutConfiguration.pageId}-{item.column.uniqueId}">
+    <f:if condition="{allowEditContent} && {item.column.contentEditable} && {item.column.context.allowNewContent}">
+        <div class="t3js-page-new-ce t3-page-ce-wrapper-new-ce" id="colpos-{item.column.columnNumber}-page-{item.context.pageId}-{item.column.uniqueId}">
             <a href="{item.newContentAfterUrl}" title="{item.newContentAfterLinkTitle}" data-title="{item.newContentAfterLinkTitle}" class="btn btn-default btn-sm t3js-toggle-new-content-element-wizard">
                 <core:icon identifier="actions-add" />
                 {item.newContentAfterTitle}
diff --git a/typo3/sysext/backend/Resources/Private/Templates/PageLayout/PageLayout.html b/typo3/sysext/backend/Resources/Private/Templates/PageLayout/PageLayout.html
index 8dbb79770e950f7bf873592d0286123b3c34676f..2de35153b6e4faadf151d6f9cb30d7b3eba1b18b 100644
--- a/typo3/sysext/backend/Resources/Private/Templates/PageLayout/PageLayout.html
+++ b/typo3/sysext/backend/Resources/Private/Templates/PageLayout/PageLayout.html
@@ -1,5 +1,5 @@
 {namespace be=TYPO3\CMS\Backend\ViewHelpers}
-<f:if condition="{pageLayoutConfiguration.languageMode}">
+<f:if condition="{context.drawingConfiguration.languageMode}">
     <f:then>
         <f:render partial="PageLayout/LanguageColumns" arguments="{_all}" />
     </f:then>
diff --git a/typo3/sysext/backend/Resources/Private/Templates/PageLayout/UnusedRecords.html b/typo3/sysext/backend/Resources/Private/Templates/PageLayout/UnusedRecords.html
index 62c91436d71fb156078364d9cef1fd067bc0f33a..2831ac9f5700fd52dca7f589dcd9994730249dd3 100644
--- a/typo3/sysext/backend/Resources/Private/Templates/PageLayout/UnusedRecords.html
+++ b/typo3/sysext/backend/Resources/Private/Templates/PageLayout/UnusedRecords.html
@@ -1 +1 @@
-<f:render partial="PageLayout/Grid" arguments="{grid: unusedGrid, backendLayout: backendLayout}" />
+<f:render partial="PageLayout/Grid" arguments="{_all}" />