8

Currently the price shows like $2.999,00

I want the price to show like $2,999.00 for locale es_MX (spanish, Mexico) in product pages, anywhere else the currency format is correct.

I've tried all solutions in stackexchange but no one works.

File app/code/Jsp/Currency/etc/di.xml

<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">
    <preference for="Magento\Framework\Locale\Format" type="Jsp\Currency\Model\Format"/>
</config>

File app/code/Jsp/Currency/Model/Format.php

<?php
namespace Jsp\Currency\Model;

use Magento\Framework\Locale\Bundle\DataBundle;

class Format extends \Magento\Framework\Locale\Format
{
    private static $defaultNumberSet = 'latn';

    public function getPriceFormat($localeCode = null, $currencyCode = null)
    {
        $localeCode = $localeCode ?: $this->_localeResolver->getLocale();
        if ($currencyCode) {
            $currency = $this->currencyFactory->create()->load($currencyCode);
        } else {
            $currency = $this->_scopeResolver->getScope()->getCurrentCurrency();
        }

        $localeData = (new DataBundle())->get($localeCode);
        $defaultSet = $localeData['NumberElements']['default'] ?: self::$defaultNumberSet;

        $format = $localeData['NumberElements'][$defaultSet]['patterns']['currencyFormat']
            ?: ($localeData['NumberElements'][self::$defaultNumberSet]['patterns']['currencyFormat']
                ?: explode(';', $localeData['NumberPatterns'][1])[0]);

        //your main changes are gone here.....
        if($localeCode == 'es_MX'){
            $decimalSymbol = '.';
            $groupSymbol = ',';
        }else{
            $decimalSymbol = $localeData['NumberElements'][$defaultSet]['symbols']['decimal']
                ?: ($localeData['NumberElements'][self::$defaultNumberSet]['symbols']['decimal']
                    ?: $localeData['NumberElements'][0]);

            $groupSymbol = $localeData['NumberElements'][$defaultSet]['symbols']['group']
                ?: ($localeData['NumberElements'][self::$defaultNumberSet]['symbols']['group']
                    ?: $localeData['NumberElements'][1]);
        }

        $pos = strpos($format, ';');
        if ($pos !== false) {
            $format = substr($format, 0, $pos);
        }
        $format = preg_replace("/[^0\#\.,]/", "", $format);
        $totalPrecision = 0;
        $decimalPoint = strpos($format, '.');
        if ($decimalPoint !== false) {
            $totalPrecision = strlen($format) - (strrpos($format, '.') + 1);
        } else {
            $decimalPoint = strlen($format);
        }
        $requiredPrecision = $totalPrecision;
        $t = substr($format, $decimalPoint);
        $pos = strpos($t, '#');
        if ($pos !== false) {
            $requiredPrecision = strlen($t) - $pos - $totalPrecision;
        }

        if (strrpos($format, ',') !== false) {
            $group = $decimalPoint - strrpos($format, ',') - 1;
        } else {
            $group = strrpos($format, '.');
        }
        $integerRequired = strpos($format, '.') - strpos($format, '0');

        $result = [
            //TODO: change interface
            'pattern' => $currency->getOutputFormat(),
            'precision' => $totalPrecision,
            'requiredPrecision' => $requiredPrecision,
            'decimalSymbol' => $decimalSymbol,
            'groupSymbol' => $groupSymbol,
            'groupLength' => $group,
            'integerRequired' => $integerRequired,
        ];       
        return $result;
    }
}

File vendor/magento/framework/Locale/Format.php

<?php
/**
 * Copyright © 2016 Magento. All rights reserved.
 * See COPYING.txt for license details.
 */
namespace Magento\Framework\Locale;

use Magento\Framework\Locale\Bundle\DataBundle;

class Format implements \Magento\Framework\Locale\FormatInterface
{
    /**
     * @var string
     */
    private static $defaultNumberSet = 'latn';

    /**
     * @var \Magento\Framework\App\ScopeResolverInterface
     */
    protected $_scopeResolver;

    /**
     * @var \Magento\Framework\Locale\ResolverInterface
     */
    protected $_localeResolver;

    /**
     * @var \Magento\Directory\Model\CurrencyFactory
     */
    protected $currencyFactory;

    /**
     * @param \Magento\Framework\App\ScopeResolverInterface $scopeResolver
     * @param ResolverInterface $localeResolver
     * @param \Magento\Directory\Model\CurrencyFactory $currencyFactory
     */
    public function __construct(
        \Magento\Framework\App\ScopeResolverInterface $scopeResolver,
        \Magento\Framework\Locale\ResolverInterface $localeResolver,
        \Magento\Directory\Model\CurrencyFactory $currencyFactory
    ) {
        $this->_scopeResolver = $scopeResolver;
        $this->_localeResolver = $localeResolver;
        $this->currencyFactory = $currencyFactory;
    }

    /**
     * Returns the first found number from an string
     * Parsing depends on given locale (grouping and decimal)
     *
     * Examples for input:
     * '  2345.4356,1234' = 23455456.1234
     * '+23,3452.123' = 233452.123
     * ' 12343 ' = 12343
     * '-9456km' = -9456
     * '0' = 0
     * '2 054,10' = 2054.1
     * '2'054.52' = 2054.52
     * '2,46 GB' = 2.46
     *
     * @param string|float|int $value
     * @return float|null
     */
    public function getNumber($value)
    {
        if ($value === null) {
            return null;
        }

        if (!is_string($value)) {
            return floatval($value);
        }

        //trim spaces and apostrophes
        $value = str_replace(['\'', ' '], '', $value);

        $separatorComa = strpos($value, ',');
        $separatorDot = strpos($value, '.');

        if ($separatorComa !== false && $separatorDot !== false) {
            if ($separatorComa > $separatorDot) {
                $value = str_replace('.', '', $value);
                $value = str_replace(',', '.', $value);
            } else {
                $value = str_replace(',', '', $value);
            }
        } elseif ($separatorComa !== false) {
            $value = str_replace(',', '.', $value);
        }

        return floatval($value);
    }

    /**
     * Functions returns array with price formatting info
     *
     * @param string $localeCode Locale code.
     * @param string $currencyCode Currency code.
     * @return array
     * @SuppressWarnings(PHPMD.NPathComplexity)
     * @SuppressWarnings(PHPMD.CyclomaticComplexity)
     */
    public function getPriceFormat($localeCode = null, $currencyCode = null)
    {
        $localeCode = $localeCode ?: $this->_localeResolver->getLocale();
        if ($currencyCode) {
            $currency = $this->currencyFactory->create()->load($currencyCode);
        } else {
            $currency = $this->_scopeResolver->getScope()->getCurrentCurrency();
        }
        $localeData = (new DataBundle())->get($localeCode);
        $defaultSet = $localeData['NumberElements']['default'] ?: self::$defaultNumberSet;
        $format = $localeData['NumberElements'][$defaultSet]['patterns']['currencyFormat']
            ?: ($localeData['NumberElements'][self::$defaultNumberSet]['patterns']['currencyFormat']
                ?: explode(';', $localeData['NumberPatterns'][1])[0]);

        $decimalSymbol = $localeData['NumberElements'][$defaultSet]['symbols']['decimal']
            ?: ($localeData['NumberElements'][self::$defaultNumberSet]['symbols']['decimal']
                ?: $localeData['NumberElements'][0]);

        $groupSymbol = $localeData['NumberElements'][$defaultSet]['symbols']['group']
            ?: ($localeData['NumberElements'][self::$defaultNumberSet]['symbols']['group']
                ?: $localeData['NumberElements'][1]);

        $pos = strpos($format, ';');
        if ($pos !== false) {
            $format = substr($format, 0, $pos);
        }
        $format = preg_replace("/[^0\#\.,]/", "", $format);
        $totalPrecision = 0;
        $decimalPoint = strpos($format, '.');
        if ($decimalPoint !== false) {
            $totalPrecision = strlen($format) - (strrpos($format, '.') + 1);
        } else {
            $decimalPoint = strlen($format);
        }
        $requiredPrecision = $totalPrecision;
        $t = substr($format, $decimalPoint);
        $pos = strpos($t, '#');
        if ($pos !== false) {
            $requiredPrecision = strlen($t) - $pos - $totalPrecision;
        }

        if (strrpos($format, ',') !== false) {
            $group = $decimalPoint - strrpos($format, ',') - 1;
        } else {
            $group = strrpos($format, '.');
        }
        $integerRequired = strpos($format, '.') - strpos($format, '0');

        $result = [
            //TODO: change interface
            'pattern' => $currency->getOutputFormat(),
            'precision' => $totalPrecision,
            'requiredPrecision' => $requiredPrecision,
            'decimalSymbol' => $decimalSymbol,
            'groupSymbol' => $groupSymbol,
            'groupLength' => $group,
            'integerRequired' => $integerRequired,
        ];

        return $result;
    }
}
  • Please check updated answer and if you have any problem let me know, This is working code for your issue. I have same issue coming for spanish site and solved using below code. Thanks. – Rakesh Jesadiya Jan 2 '17 at 10:10
  • Remove conditions in your code and just keep $decimalSymbol = '.' And $groupSymbol = ',' remove var and check. For more info i have keep updated code. Please check it. – Rakesh Jesadiya Jan 2 '17 at 17:47
  • Please check your custom module function is called or not, you can debug above function if your code is coming in getPriceFormat function or not. Cause code is working for me for same type of issue faced with me. – Rakesh Jesadiya Jan 2 '17 at 17:51
  • I noticed the Format.php file your provided is a little bit different from the one you provided. Can this be the issue? In regards to debuging the function, can you explain in more detail how can I debug it? – Luis Garcia Jan 2 '17 at 18:11
  • Do I need to add a registration.php file inside my module folder? – Luis Garcia Jan 2 '17 at 18:15
15
+50

create just simple module and overrider default *Format.php** file,

app/code/Package/Modulename/etc/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">
    <preference for="Magento\Framework\Locale\Format" type="Vendor\Currency\Model\Format" />
</config>

create model file, app/code/Package/Modulename/Model/Format.php

<?php
namespace Package\Modulename\Model;

use Magento\Framework\Locale\Bundle\DataBundle;

class Format extends \Magento\Framework\Locale\Format
{
    private static $defaultNumberSet = 'latn';

    public function getPriceFormat($localeCode = null, $currencyCode = null)
    {
        $localeCode = $localeCode ?: $this->_localeResolver->getLocale();
        if ($currencyCode) {
            $currency = $this->currencyFactory->create()->load($currencyCode);
        } else {
            $currency = $this->_scopeResolver->getScope()->getCurrentCurrency();
        }

        $localeData = (new DataBundle())->get($localeCode);
        $defaultSet = $localeData['NumberElements']['default'] ?: self::$defaultNumberSet;

        $format = $localeData['NumberElements'][$defaultSet]['patterns']['currencyFormat']
            ?: ($localeData['NumberElements'][self::$defaultNumberSet]['patterns']['currencyFormat']
                ?: explode(';', $localeData['NumberPatterns'][1])[0]);

        //your main changes are gone here.....
        $decimalSymbol = '.';
        $groupSymbol = ',';

        $pos = strpos($format, ';');
        if ($pos !== false) {
            $format = substr($format, 0, $pos);
        }
        $format = preg_replace("/[^0\#\.,]/", "", $format);
        $totalPrecision = 0;
        $decimalPoint = strpos($format, '.');
        if ($decimalPoint !== false) {
            $totalPrecision = strlen($format) - (strrpos($format, '.') + 1);
        } else {
            $decimalPoint = strlen($format);
        }
        $requiredPrecision = $totalPrecision;
        $t = substr($format, $decimalPoint);
        $pos = strpos($t, '#');
        if ($pos !== false) {
            $requiredPrecision = strlen($t) - $pos - $totalPrecision;
        }

        if (strrpos($format, ',') !== false) {
            $group = $decimalPoint - strrpos($format, ',') - 1;
        } else {
            $group = strrpos($format, '.');
        }
        $integerRequired = strpos($format, '.') - strpos($format, '0');

        $result = [
            //TODO: change interface
            'pattern' => $currency->getOutputFormat(),
            'precision' => $totalPrecision,
            'requiredPrecision' => $requiredPrecision,
            'decimalSymbol' => $decimalSymbol,
            'groupSymbol' => $groupSymbol,
            'groupLength' => $group,
            'integerRequired' => $integerRequired,
        ];       
        return $result;
    }
}

Thanks.

  • I tried your solution but did not work. I updated my answer with the di.xml code I created. I also created the model file changing Package and Module name to match my folders names – Luis Garcia Dec 30 '16 at 23:09
  • I've updated my question with Format.php code. Thanks – Luis Garcia Jan 2 '17 at 17:02
  • I tried above, it works for product page but not category page, wondering!!! – Zinat Jun 22 '17 at 5:41
  • its working for entire site. please check may be you have some issue; – Rakesh Jesadiya Jun 22 '17 at 5:43
  • @RakeshJesadiya, Its working for product detail page only and other prices like Totals , Cart etc. but its not working on listing page , mini cart , cart item price – Codrain Technolabs Pvt Ltd Mar 15 '18 at 9:25
2

Use below code:

$objectManager = \Magento\Framework\App\ObjectManager::getInstance();
$objectManager->create('\Magento\Framework\Pricing\PriceCurrencyInterface')->format('999,00',true,0);

Format function as below:

public function format(
        $amount,
        $includeContainer = true,
        $precision = self::DEFAULT_PRECISION,
        $scope = null,
        $currency = null
    );

If $includeContainer = true then price will show with span container

<span class="price">$999</span>

$precision = self::DEFAULT_PRECISION It will display two decimal point. Using 0 it will not display decimal point.

  • In which file should I add this code? I'm new to Magento – Luis Garcia May 17 '16 at 19:26
  • In which file should I add this code? – Luis Garcia Jul 28 '16 at 22:38
2

By default of Magento 2, price format is a little strange for some currencies so we need to change it. Here’s the way to change price format.

Here’s the example for the case of Vietnamese dong. Default displayed format was 100.000,00. Then I changed it into 100,000 (separated by comma without decimal point).

# vendor/magento/zendframework1/library/Zend/Locale/Data/vi.xml
<symbols numbersystem="latn">
 <decimal>.</decimal>
 <group>,</group>
</symbols>

# vendor/magento/framework/Pricing/PriceCurrencyInterface.php
const DEFAULT_PRECISION = 0

# vendor/magento/module-directory/Model/Currency.php
return $this->formatPrecision($price, 0, $options, $includeContainer, $addBrackets);

# vendor/magento/module-sales/Model/Order.php
public function formatPrice($price, $addBrackets = false)
{
    return $this->formatPricePrecision($price, 0, $addBrackets);
}

Thanks Enjoy :)

  • tried it but does not work for es_MX – Luis Garcia Dec 26 '16 at 22:20
1
  1. Go from your root folder to vendor/magento/zendframework1/library/Zend/Locale/Data/es_MX.xml
  2. Look for <currencyFormat

You can set the format like this :

<currencyFormat type="standard">
    <pattern draft="contributed">¤#,##0.00</pattern>
</currencyFormat>
  • That format was already set like that – Luis Garcia Dec 27 '16 at 17:34
-1

Bad way to do it (but faster) is hardcoding vendor/magento/framework/Locale/Format.php

    $result = [
        //TODO: change interface
        'pattern' => $currency->getOutputFormat(),
        'precision' => $totalPrecision,
        'requiredPrecision' => $requiredPrecision,
        //'decimalSymbol' => $decimalSymbol,
        'decimalSymbol' =>'.',
        //'groupSymbol' => $groupSymbol,
        'groupSymbol' => ',',
        'groupLength' => $group,
        'integerRequired' => $integerRequired,
    ];
  • If it's a bad way, then why suggest it? We should never modify core or vendor. – Danny Nimmo Jul 6 '17 at 23:37
  • Thank you. I was looking for a quick dirty solution as I want to fix a dying website while I'm working on a new version of it. – Hassan Al-Jeshi Apr 22 at 5:43

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.