The problem
My Magento 2 (v2.4.5-p5
) admin is unable to display the entries in the “Layout” dropdown with their correct translations, despite the correct translations being present.
The layouts are defined in vendor/magento/module-theme/view/frontend/layouts.xml
and additionally in vendor/magento/module-page-builder/view/frontend/layouts.xml
, when you are using the PageBuilder module.
<?xml version="1.0" encoding="UTF-8"?>
<!--
/**
* Copyright © 2015 Magento. All rights reserved.
* See COPYING.txt for license details.
*/
-->
<page_layouts xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../../../../lib/internal/Magento/Framework/View/PageLayout/etc/layouts.xsd">
<layout id="1column">
<label translate="true">1 column</label>
</layout>
<layout id="2columns-left">
<label translate="true">2 columns with left bar</label>
</layout>
<layout id="2columns-right">
<label translate="true">2 columns with right bar</label>
</layout>
<layout id="3columns">
<label translate="true">3 columns</label>
</layout>
</page_layouts>
<?xml version="1.0" encoding="UTF-8"?>
<!--
/**
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
-->
<page_layouts xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:View/PageLayout/etc/layouts.xsd">
<layout id="cms-full-width">
<label translate="true">Page -- Full Width</label>
</layout>
<layout id="category-full-width">
<label translate="true">Category -- Full Width</label>
</layout>
<layout id="product-full-width">
<label translate="true">Product -- Full Width</label>
</layout>
</page_layouts>
After tracking down the values from KnockoutJS downwards using xdebug, I came across the culprit: The PageLayout Config.php
file of the Magento framework. So as deep down in the core as it basically gets.
The method in question is called _extractData()
. This method is supplied with the layout files XML DOM and returns the values (the names) of all the specified layouts. However, there is one problem with this logic: It completely ignores the translate="true"
flag for each label tag.
/**
* Extract configuration data from the DOM structure
*
* @param \DOMDocument $dom
* @return array
*/
protected function _extractData(\DOMDocument $dom)
{
$result = [];
/** @var \DOMElement $layout */
foreach ($dom->getElementsByTagName('layout') as $layout) {
$result[$layout->getAttribute('id')] = $layout->nodeValue !== null ? trim($layout->nodeValue) : '';
}
return $result;
}
The solution
To fix this behaviour, you simply have to override the _extractData()
method with a corrected version, which respects the translation.
Set up your own custom module with the following structure:
app/
└── code/
└── <YOUR-VENDOR-NAME>/
└── <YOUR-MODULE-NAME>/
├── registration.php
├── etc/
│ ├── module.xml
│ └── di.xml
└── Overrides/
└── PageLayoutConfig.php
<?php
\Magento\Framework\Component\ComponentRegistrar::register(
\Magento\Framework\Component\ComponentRegistrar::MODULE,
"<YOUR-VENDOR-NAME>_<YOUR-MODULE-NAME>",
__DIR__
);
<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Module/etc/module.xsd">
<module name="<YOUR-VENDOR-NAME>_<YOUR-MODULE-NAME>" setup_version="1.0.0">
</module>
</config>
<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">
<preference for="Magento\Framework\View\PageLayout\Config" type="<YOUR-VENDOR-NAME>\<YOUR-MODULE-NAME>\Overrides\PageLayoutConfig" />
</config>
<?php
namespace <YOUR-VENDOR-NAME>\<YOUR-MODULE-NAME>\Overrides;
class PageLayoutConfig extends \Magento\Framework\View\PageLayout\Config {
protected function _extractData(\DOMDocument $dom) {
$result = [];
foreach ($dom->getElementsByTagName('layout') as $layout) {
$label = trim($layout->nodeValue);
if ('true' === (string)simplexml_import_dom($layout)->{'label'}['translate']) {
$label = __($label);
}
$result[$layout->getAttribute('id')] = $label;
}
return $result;
}
}
After you deployed your module to your Magento installation, make sure to activate it.
php bin/magento module:enable <YOUR-VENDOR-NAME>_<YOUR-MODULE-NAME>
php bin/magento setup:upgrade
Refresh your page and there you have it: The translations are working now.
You’re welcome.