Many bugs have been submitted to the Magento 2 Github page, and whilst lots have been fixed, there are many waiting to be fixed and included in upcoming versions. None more so than the Magento 2 knockout translation bug.
This bug is fairly easy to replicate in a blank install of Magento 2, and can be reproduced on the current version, 2.2.1.
The store’s locale in this example is set to en_GB
and when using a custom theme, attempts to translate You have no items in your shopping cart.
to You have no items in your shopping basket.
.
This is entered within the en_GB.csv
file in the theme’s i18n
directory.
"You have no items in your shopping cart.", "You have no items in your shopping basket."
After refreshing the cache and rebuilding static content, the text is successfully changed within the cart page’s template file, but not within the minicart.
This is due to the js-translation.json
file within your theme’s directory in the pub/static
directory not rebuilding properly.
The bug can be traced back to the vendor/magento/module-translation/Model/Json/PreProcessor.php
file, within the process()
method.
public function process(Chain $chain) { if ($this->isDictionaryPath($chain->getTargetAssetPath())) { $context = $chain->getAsset()->getContext(); $themePath = '*/*'; $areaCode = \Magento\Backend\App\Area\FrontNameResolver::AREA_CODE; if ($context instanceof FallbackContext) { $themePath = $context->getThemePath(); $areaCode = $context->getAreaCode(); $this->translate->setLocale($context->getLocale()); } $area = $this->areaList->getArea($areaCode); $area->load(\Magento\Framework\App\Area::PART_TRANSLATE); $chain->setContent(json_encode($this->dataProvider->getData($themePath))); $chain->setContentType('json'); } }
Magento does not load the design part when using area->load()
.
This can be fixed by replacing the following lines.
$area = $this->areaList->getArea($areaCode); $area->load(\Magento\Framework\App\Area::PART_TRANSLATE);
With the below.
$area = $this->areaList->getArea($areaCode); $area->load(\Magento\Framework\App\Area::PART_DESIGN); $area->load(\Magento\Framework\App\Area::PART_TRANSLATE);
To achieve the above modifications without directly modifying the code code, you can create a custom module and write a before plugin on the process()
method.
Assuming you have already set up a registration.php
and module.xml
, proceed by defining the plugin in di.xml
.
<?xml version="1.0"?> <config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd"> <type name="Magento\Translation\Model\Json\PreProcessor"> <plugin name="plugin_translate_json_preprocessor" type="[Vendor]\[Module]\Plugin\Translate\Json\PreProcessor" sortOrder="10" /> </type> </config>
Add the plugin class that will include the $area->load(\Magento\Framework\App\Area::PART_DESIGN);
line.
<?php namespace [Vendor]\[Module]\Plugin\Translate\Json; use Magento\Framework\App\AreaList; use Magento\Framework\TranslateInterface; use Magento\Framework\View\Asset\File\FallbackContext; use Magento\Framework\View\Asset\PreProcessor\Chain; use Magento\Translation\Model\Js\Config; use Magento\Translation\Model\Js\DataProviderInterface; class PreProcessor { /** * Js translation configuration * * @var Config */ protected $config; /** * Translation data provider * * @var DataProviderInterface */ protected $dataProvider; /** * @var AreaList */ protected $areaList; /** * @var TranslateInterface */ protected $translate; /** * PreProcessor constructor. * * @param Config $config * @param DataProviderInterface $dataProvider * @param AreaList $areaList * @param TranslateInterface $translate */ public function __construct( Config $config, DataProviderInterface $dataProvider, AreaList $areaList, TranslateInterface $translate ) { $this->config = $config; $this->dataProvider = $dataProvider; $this->areaList = $areaList; $this->translate = $translate; } /** * Transform content and/or content type for the specified preprocessing chain object * * @param Chain $chain * @return void */ public function beforeProcess(\Magento\Translation\Model\Json\PreProcessor $processor, Chain $chain) { if ($this->isDictionaryPath($chain->getTargetAssetPath())) { $context = $chain->getAsset()->getContext(); $areaCode = \Magento\Backend\App\Area\FrontNameResolver::AREA_CODE; if ($context instanceof FallbackContext) { $areaCode = $context->getAreaCode(); $this->translate->setLocale($context->getLocale()); } $area = $this->areaList->getArea($areaCode); $area->load(\Magento\Framework\App\Area::PART_DESIGN); } } /** * Is provided path the path to translation dictionary * * @param string $path * @return bool */ protected function isDictionaryPath($path) { return (strpos($path, $this->config->getDictionaryFileName()) !== false); } }
Note that the isDictionaryPath()
method is also included here, as it is a protected method used in process()
.
After adding the above, delete the existing js-translation.json
file in the pub/static
directory, refresh the translation cache and redeploying static content, the next time you load the cart page, the minicart text will successfully translate.
You should also notice that the js-translation.json
file has rebuilt containing the original and translated text added in the theme’s i18n/en_GB.csv
file.
Note: This article is based on Magento Open Source version 2.2.