SyliusPayPalPlugin version affected: v1.2.2
Description
If the locale code passed to the LocalProcessors::process() method is in a ISO 639-1 format Sylius converts that locale in the first ISO 15897 format available (see Symfony\Component\Intl\Locales
).
For example IT is converted into it_CH instead of it_IT, so PayPal returns an "Unexpected locale" error during the checkout process.
Moreover, due to the following JS code you can find in vendor/sylius/paypal-plugin/src/Resources/views/payFromCartPage.html.twig
, vendor/sylius/paypal-plugin/src/Resources/views/payFromPaymentPage.html.twig
and vendor/sylius/paypal-plugin/src/Resources/views/payFromProductPage.html.twig
, the page keeps on reloading endlessly.
onError: function (error) {
return fetch(errorPayPalPaymentUrl, {
method: 'post',
headers: {},
body: error
}).then(window.location.reload());
},
Steps to reproduce
- Setup a store with IT localization.
- Enable Sylius PayPal Plugin
- Go to a product / cart / checkout page
Possible Solution
Due to lack of time, we've not checked if PayPal provides an API endpoint to fetch available locale codes (if they provide it, it would be nice to have a weekly cron that updates a dedicated DB table).
As a temporary (ugly) patch, we've solved this issue in this way:
LocaleProcessor.php
<?php
declare(strict_types=1);
namespace App\VendorExtension\PayPalPlugin\Processor;
use Sylius\PayPalPlugin\Processor\LocaleProcessorInterface;
use Symfony\Component\Intl\Locales;
final class LocaleProcessor implements LocaleProcessorInterface
{
const DEFAULT_LOCALE = 'en_US';
private $locales;
public function __construct()
{
$this->locales = json_decode(file_get_contents(dirname(__FILE__, 2) . '/Resources/data/locales.json'));
}
public function process(string $locale): string
{
if ($this->isValidLocale($locale)) {
return $locale;
}
foreach($this->locales as $refLocale) {
if (substr($locale, 0, 2) === substr($refLocale->localeCode, 0, 2) && 0 === (int) $refLocale->priority) {
return $refLocale->localeCode;
}
}
return self::DEFAULT_LOCALE;
}
private function isValidLocale(string $locale): bool
{
foreach($this->locales as $refLocale) {
if ($locale === $refLocale->localeCode) {
return true;
}
}
return false;
}
}
JS snippet used to generate locales.json
/**
* INSTRUCTIONS:
* - Visit https://developer.paypal.com/docs/api/reference/locale-codes/
* - Open the inspector
* - Copy the snippet below insided console and run it
* - Open locales.json
* - Simply type CTRL+V (Linux and Win) or CMD+V (macOS)
*/
/* eslint-disable no-undef */
const collection = [];
document.querySelectorAll('.ppvx_table.ppvx_table-responsive-sm tr').forEach((el) => {
const td = el.querySelectorAll('td');
if (td.length) {
collection.push({
region: td[0].textContent,
regionCode: td[1].textContent.toLowerCase(),
localeCode: td[3].textContent,
restApiCode: td[4].textContent,
priority: parseInt(td[2].textContent, 10),
});
}
});
copy(collection);