Show a sale price and discount percentage in Commerce 2
Easiest way for me was to create my own FieldFormatter for the price and make it extend Drupal\commerce_order\Plugin\Field\FieldFormatter\PriceCalculatedFormatter.

Once you did that, flush the cache of your website, go to the manage display of your Product variation type, select "My Custom price calculated formatter" for Price field and in the parameters, check "Apply promotions to the calculated price". And voilà!

Here is an example code for the custom FieldFormatter:

&lt;?php

namespace Drupal\my_custom_module\Plugin\Field\FieldFormatter;

use CommerceGuys\Intl\Formatter\CurrencyFormatterInterface;
use Drupal\commerce\Context;
use Drupal\commerce\PurchasableEntityInterface;
use Drupal\commerce_order\AdjustmentTypeManager;
use Drupal\commerce_order\PriceCalculatorInterface;
use Drupal\commerce_price\Plugin\Field\FieldFormatter\PriceDefaultFormatter;
use Drupal\commerce_store\CurrentStoreInterface;
use Drupal\Core\Cache\Cache;
use Drupal\Core\Field\FieldDefinitionInterface;
use Drupal\Core\Field\FieldItemListInterface;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Language\LanguageInterface;
use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
use Drupal\Core\Session\AccountInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Drupal\commerce_order\Plugin\Field\FieldFormatter\PriceCalculatedFormatter; // This is the FieldFormatter we want to extend

/**
 * Plugin implementation of the 'my_custom_price_calculated_formatter' formatter.
 *
 * @FieldFormatter(
 *   id = "my_custom_price_calculated_formatter",
 *   label = @Translation("My Custom price calculated formatter"),
 *   field_types = {
 *     "commerce_price"
 *   }
 * )
 */
class MyCustomPriceCalculatedFormatter extends PriceCalculatedFormatter implements ContainerFactoryPluginInterface {

  /**
   * {@inheritdoc}
   * This is the function we want to extend
   */
  public function viewElements(FieldItemListInterface $items, $langcode) {
    $elements = [];
    if (!$items-&gt;isEmpty()) {
      $context = new Context($this-&gt;currentUser, $this-&gt;currentStore-&gt;getStore(), NULL, [
        'field_name' =&gt; $items-&gt;getName(),
      ]);
      /** @var \Drupal\commerce\PurchasableEntityInterface $purchasable_entity */
      $purchasable_entity = $items-&gt;getEntity();
      $adjustment_types = array_filter($this-&gt;getSetting('adjustment_types'));
      $result = $this-&gt;priceCalculator-&gt;calculate($purchasable_entity, 1, $context, $adjustment_types);
      $calculated_price = $result-&gt;getCalculatedPrice();
      $number = $calculated_price-&gt;getNumber();
      $currency_code = $calculated_price-&gt;getCurrencyCode();
      $options = $this-&gt;getFormattingOptions();

      // Check if there is any adjustment for the price
      // If so, get the BasePrice (without adjustment) and format it
      if(!empty($result-&gt;getAdjustments())) {
        $adjustments = $result-&gt;getAdjustments();
        foreach($adjustments as $single_adjustement) {
          // Get the discount percentage off
          // NB: there could be many other discounts applied but this example catches percentage discounts only
          if($single_adjustement-&gt;getType() == "promotion" &amp;&amp; $single_adjustement-&gt;getPercentage() !== NULL) {
            $discount = $this-&gt;t('@discount off', ['@discount' =&gt; $single_adjustement-&gt;getPercentage() * 100 . '%']);
          }
        }
        $base_price = $result-&gt;getBasePrice();
        $base_price_number = $base_price-&gt;getNumber();
        $base_price_currency_code = $base_price-&gt;getCurrencyCode();
        $base_price_formatted = $this-&gt;currencyFormatter-&gt;format($base_price_number, $base_price_currency_code, $options);
      }

      // This is our calculated price with the promotion
      $price_display = $this-&gt;currencyFormatter-&gt;format($number, $currency_code, $options);
      if(isset($base_price_formatted)) {
        // Set the base price (old-price), the percentage off and the calculated price within $price_display
        $price_display = '&lt;div class="old-price"&gt;' . $base_price_formatted . '&lt;/div&gt;&lt;div class="percentage-off"&gt;' . $discount . '&lt;/div&gt;&lt;div class="new-price"&gt;' . $price_display . '&lt;/div&gt;';
      }

      $elements[0] = [
        '#markup' =&gt; $price_display,
        '#cache' =&gt; [
          'tags' =&gt; $purchasable_entity-&gt;getCacheTags(),
          'contexts' =&gt; Cache::mergeContexts($purchasable_entity-&gt;getCacheContexts(), [
            'languages:' . LanguageInterface::TYPE_INTERFACE,
            'country',
          ]),
        ],
      ];
    }

    return $elements;
  }

}