Skip to content

FIX: Reversed Arabic letters in Invoice Pdfs #27306

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
162 changes: 162 additions & 0 deletions app/code/Magento/Sales/Model/Order/Pdf/AbstractPdf.php
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,13 @@ abstract class AbstractPdf extends \Magento\Framework\DataObject
*/
public $y;

/**
* Is RTL Country Order
*
* @var bool;
*/
public $isRTLCountry = FALSE;

/**
* Item renderers with render type key
* model => the model name
Expand Down Expand Up @@ -307,6 +314,126 @@ protected function insertLogo(&$page, $store = null)
}
}

/**
* Is RTL Characters
*
* @param string $locale
* @return bool
*/
protected function isRTLLocale($locale)
{
// from magento List of allowed locales
$rtlLocales = array(
'ar_DZ', /*Arabic (Algeria)*/
'ar_EG', /*Arabic (Egypt)*/
'ar_KW', /*Arabic (Kuwait)*/
'ar_MA', /*Arabic (Morocco)*/
'ar_SA', /*Arabic (Saudi Arabia)*/
'fa_IR', /*Persian (Iran)*/
'he_IL' /*Hebrew (Israel)*/
);

if (in_array($locale, $rtlLocales)) {
return TRUE;
}
return FALSE;
}

/**
* Is RTL Currencies
*
* @param string $currency
* @return bool
*/
protected function isRTLCurrency($currency)
{
// from magento List of allowed currencies
$rtlCurrencies = array(
'AFN', /*Afghani*/
'DZD', /*Algerian Dinar*/
'BHD', /*Bahraini Dinar*/
'DJF', /*Djibouti Franc*/
'EGP', /*Egyptian Pound*/
'IQD', /*Iraqi Dinar*/
'ILS', /*Israeli New Sheqel*/
'JOD', /*Jordanian Dinar*/
'KWD', /*Kuwaiti Dinar*/
'LBP', /*Lebanese Pound*/
'LYD', /*Libyan Dinar*/
'MRO', /*Mauritania Ouguiya*/
'MAD', /*Moroccan Dirham*/
'OMR', /*Oman Rial*/
'PKR', /*Pakistan Rupee*/
'QAR', /*Qatari Rial*/
'SOS', /*Somali Shilling*/
'SDG', /*Sudanese Pound*/
'SYP', /*Syrian Pound*/
'TND', /*Tunisian Dinar*/
'AED', /*United Arab Emirates Dirham*/
'YER' /*Yemeni Rial*/
);

if (in_array($currency, $rtlCurrencies)) {
return TRUE;
}
return FALSE;
}

/**
* Is Shipping Country uses RTL language
*
* @param string $country
* @return bool
*/
protected function isRTLCountry($country)
{
// from magento USPS countries
$rtlCountries = array(
'AE' => 'United Arab Emirates',
'AF' => 'Afghanistan',
'BH' => 'Bahrain',
'DJ' => 'Djibouti',
'EG' => 'Egypt',
'IL' => 'Israel',
'IQ' => 'Iraq',
'JO' => 'Jordan',
'KM' => 'Comoros',
'KW' => 'Kuwait',
'LB' => 'Lebanon',
'LY' => 'Libya',
'MA' => 'Morocco',
'MR' => 'Mauritania',
'OM' => 'Oman',
'PK' => 'Pakistan',
'QA' => 'Qatar',
'SA' => 'Saudi Arabia',
'SD' => 'Sudan',
'SO' => 'Somalia',
'SY' => 'Syrian Arab Republic',
'TD' => 'Chad',
'TN' => 'Tunisia',
'YE' => 'Yemen'
);

if (array_key_exists($country, $rtlCountries)) {
return TRUE;
}
return FALSE;
}

/**
* Reverse Characters on RTL Language
*
* @param string $sentense
* @return string $sentense
*/
protected function reverseRTLCharacters($sentense, $store = null)
{

$sentense = $this->string->revRTLSentense($sentense);
return $sentense;
}

/**
* Insert address to pdf page
*
Expand All @@ -329,9 +456,16 @@ protected function insertAddress(&$page, $store = null)
$store
)
);

foreach ($values as $value) {
if ($value !== '') {
$value = preg_replace('/<br[^>]*>/i', "\n", $value);
// Reverse Characters on ship to RTL Countries
/* is RTL Country */
if($this->isRTLCountry)
{
$value = $this->reverseRTLCharacters($value, $store);
}
foreach ($this->string->split($value, 45, true, true) as $_value) {
$page->drawText(
trim(strip_tags($_value)),
Expand Down Expand Up @@ -499,11 +633,17 @@ protected function insertOrder(&$page, $obj, $putOrderId = true)

foreach ($billingAddress as $value) {
if ($value !== '') {
if($this->isRTLCountry)
{
// Reverse Characters
$value = $this->reverseRTLCharacters($value);
}
$text = [];
foreach ($this->string->split($value, 45, true, true) as $_value) {
$text[] = $_value;
}
foreach ($text as $part) {

$page->drawText(strip_tags(ltrim($part)), 35, $this->y, 'UTF-8');
$this->y -= 15;
}
Expand All @@ -516,6 +656,11 @@ protected function insertOrder(&$page, $obj, $putOrderId = true)
$this->y = $addressesStartY;
foreach ($shippingAddress as $value) {
if ($value !== '') {
if($this->isRTLCountry)
{
// Reverse Characters
$value = $this->reverseRTLCharacters($value);
}
$text = [];
foreach ($this->string->split($value, 45, true, true) as $_value) {
$text[] = $_value;
Expand Down Expand Up @@ -558,6 +703,11 @@ protected function insertOrder(&$page, $obj, $putOrderId = true)
if (trim($value) != '') {
//Printing "Payment Method" lines
$value = preg_replace('/<br[^>]*>/i', "\n", $value);
if($this->isRTLCountry)
{
// Reverse Characters
$value = $this->reverseRTLCharacters($value);
}
foreach ($this->string->split($value, 45, true, true) as $_value) {
$page->drawText(strip_tags(trim($_value)), $paymentLeft, $yPayments, 'UTF-8');
$yPayments -= 15;
Expand All @@ -577,6 +727,12 @@ protected function insertOrder(&$page, $obj, $putOrderId = true)
$topMargin = 15;
$methodStartY = $this->y;
$this->y -= 15;

if($this->isRTLCountry)
{
// Reverse Characters
$shippingMethod = $this->reverseRTLCharacters($shippingMethod);
}

foreach ($this->string->split($shippingMethod, 45, true, true) as $_value) {
$page->drawText(strip_tags(trim($_value)), 285, $this->y, 'UTF-8');
Expand Down Expand Up @@ -616,6 +772,12 @@ protected function insertOrder(&$page, $obj, $putOrderId = true)
$maxTitleLen = 45;
$endOfTitle = strlen($track->getTitle()) > $maxTitleLen ? '...' : '';
$truncatedTitle = substr($track->getTitle(), 0, $maxTitleLen) . $endOfTitle;

if($this->isRTLCountry)
{
// Reverse Characters
$truncatedTitle = $this->reverseRTLCharacters($truncatedTitle);
}
$page->drawText($truncatedTitle, 292, $yShipments, 'UTF-8');
$page->drawText($track->getNumber(), 410, $yShipments, 'UTF-8');
$yShipments -= $topMargin - 5;
Expand Down
3 changes: 3 additions & 0 deletions app/code/Magento/Sales/Model/Order/Pdf/Creditmemo.php
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,9 @@ public function getPdf($creditmemos = [])
}
$page = $this->newPage();
$order = $creditmemo->getOrder();
/* Check Ship Country for RTL */
$shiptoCountry = $order->getShippingAddress()->getCountryId();
$this->isRTLCountry = $this->isRTLCountry($shiptoCountry);
/* Add image */
$this->insertLogo($page, $creditmemo->getStore());
/* Add address */
Expand Down
3 changes: 3 additions & 0 deletions app/code/Magento/Sales/Model/Order/Pdf/Invoice.php
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,9 @@ public function getPdf($invoices = [])
}
$page = $this->newPage();
$order = $invoice->getOrder();
/* Check Ship Country for RTL */
$shiptoCountry = $order->getShippingAddress()->getCountryId();
$this->isRTLCountry = $this->isRTLCountry($shiptoCountry);
/* Add image */
$this->insertLogo($page, $invoice->getStore());
/* Add address */
Expand Down
3 changes: 3 additions & 0 deletions app/code/Magento/Sales/Model/Order/Pdf/Shipment.php
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,9 @@ public function getPdf($shipments = [])
}
$page = $this->newPage();
$order = $shipment->getOrder();
/* Check Ship Country for RTL */
$shiptoCountry = $order->getShippingAddress()->getCountryId();
$this->isRTLCountry = $this->isRTLCountry($shiptoCountry);
/* Add image */
$this->insertLogo($page, $shipment->getStore());
/* Add address */
Expand Down
37 changes: 37 additions & 0 deletions lib/internal/Magento/Framework/Stdlib/StringUtils.php
Original file line number Diff line number Diff line change
Expand Up @@ -210,4 +210,41 @@ public function strpos($haystack, $needle, $offset = null)
{
return mb_strpos($haystack, $needle, $offset, self::ICONV_CHARSET);
}

/**
* Detect if a word are consists of RTL characters (Used in PDF Invoices)
*
* @param string $string
* @return int|float
*/
public function isRTLWord($string)
{
$rtl_chars_pattern = '/[\x{0590}-\x{083F}]|[\x{08A0}-\x{08FF}]|[\x{FB1D}-\x{FDFF}]|[\x{FE70}-\x{FEFF}]/u';
// $rtl_chars_pattern = '/[\x{0590}-\x{05ff}\x{0600}-\x{06ff}]/u';
preg_match_all($rtl_chars_pattern, $string, $matches);
$rtl_chars_count = count($matches[0]);

return $rtl_chars_count==0? 0:
$rtl_chars_count/$this->strlen($string);
}

/**
* Reverse characters of word with RTL characters only
*
* @param string $string
* @return string
*/
public function revRTLSentense($string)
{
$words = explode(' ', $string);
for ($i=0; $i<count($words); $i++) {
// for better results, it changes to find non-RTL character parts in a word
if($this->isRTLWord($words[$i]) > 0.8)
{
$words[$i] = $this->strrev($words[$i]);
}
}
return implode(" ", $words);
}

}