Sanjay Kumar
Feb 1, 2021
  2757
(6 votes)

Multilingual cart validation message

The purpose of this blog to display the cart validation messages market's language specific and make it user-friendly to the customer for the better understanding. 

About the Market in Episerver Commerce?
Market is a central of Episerver Commerce. A single site can have multiple markets, each with its own product catalog, language, currency, and promotions. Classes in this topic are available in the Mediachase.Commerce or Mediachase.Commerce.Markets namespaces.

Problem:
In one of my site, I have implemented multi-market functionality and managed the content accordingly but there is no feature to display the cart validation message in readable format to the customer for market language specific.

e.g.

  • United State (en) : Display the cart validation message in English language.
  • France (fr) : Display the cart validation message in French language.

Solution:

Episerver provides a class method OrderValidationService.ValidateOrder(cart) to validate your cart before to save, using IOrderRepository.Save(cart) method. With the help of this method we make sure the cart has enough quantity, prices are correct and up-to-date, and any promotions are applied correctly.

The ValidateOrder(cart) method returns IDictionary<ILineItem, IList<ValidationIssue>> validation issue per ILineItem but  ValidationIssue is an enum type that returns validation message in below formats which are not user-friendly and market language specific.

  • CannotProcessDueToMissingOrderStatus
  • RemovedDueToCodeMissing
  • RemovedDueToNotAvailableInMarket
  • RemovedDueToUnavailableCatalog
  • ...

So let’s make cart validation message user-friendly in the simple way.

Step 1: Create an XML file language specific and place the all possible cart validation message like below and placed into the lang folder under the site root.

<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<languages>
  <language name="English" id="en">
    <cart>
      <validation>
        <CannotProcessDueToMissingOrderStatus>Cannot process due to missing order status.</CannotProcessDueToMissingOrderStatus>
        <RemovedDueToCodeMissing>The catalog entry code that maps to the line item has been removed or changed.</RemovedDueToCodeMissing>
        <RemovedDueToNotAvailableInMarket>Item has been removed from the cart because it is not available in your market.</RemovedDueToNotAvailableInMarket>
        <RemovedDueToUnavailableCatalog>Item has been removed from the cart because the catalog of this entry is not available.</RemovedDueToUnavailableCatalog>
        <RemovedDueToUnavailableItem>Item has been removed from the cart because it is not available at this time.</RemovedDueToUnavailableItem>
        <RemovedDueToInsufficientQuantityInInventory>Item has been removed from the cart because there is not enough available quantity.</RemovedDueToInsufficientQuantityInInventory>
        <RemovedDueToInactiveWarehouse>Item has been removed from the cart because the selected warehouse is inactive.</RemovedDueToInactiveWarehouse>
        <RemovedDueToMissingInventoryInformation>Item has been removed due to missing inventory information.</RemovedDueToMissingInventoryInformation>
        <RemovedDueToInvalidPrice>Item has been removed due to an invalid price.</RemovedDueToInvalidPrice>
        <RemovedDueToInvalidMaxQuantitySetting>Item has been removed due to an invalid setting for maximum quantity.</RemovedDueToInvalidMaxQuantitySetting>
        <AdjustedQuantityByMinQuantity>Item quantity has been adjusted due to the minimum quantity threshold.</AdjustedQuantityByMinQuantity>
        <AdjustedQuantityByMaxQuantity>Item quantity has been adjusted due to the maximum quantity threshold.</AdjustedQuantityByMaxQuantity>
        <AdjustedQuantityByBackorderQuantity>Item quantity has been adjusted due to backorder quantity threshold.</AdjustedQuantityByBackorderQuantity>
        <AdjustedQuantityByPreorderQuantity>Item quantity has been adjusted due to the preorder quantity threshold.</AdjustedQuantityByPreorderQuantity>
        <AdjustedQuantityByAvailableQuantity>Item quantity has been adjusted due to the available quantity threshold.</AdjustedQuantityByAvailableQuantity>
        <PlacedPricedChanged>This item's price has changed since it was added to your cart.</PlacedPricedChanged>
        <RemovedGiftDueToInsufficientQuantityInInventory>Gift item has been removed from the cart because there is not enough available quantity.</RemovedGiftDueToInsufficientQuantityInInventory>
        <RejectedInventoryRequestDueToInsufficientQuantity>The inventory request for item has been rejected because there is not enough available quantity.</RejectedInventoryRequestDueToInsufficientQuantity>
      </validation>
    </cart>
  </language>
  <language name="French" id="fr">
    <cart>
      <validation>
        <CannotProcessDueToMissingOrderStatus>Il ne peut pas être traité en raison d'un statut de commande manquant.</CannotProcessDueToMissingOrderStatus>
        <RemovedDueToCodeMissing>Le code d'entrée de catalogue qui correspond à l'élément de campagne a été supprimé ou modifié.</RemovedDueToCodeMissing>
        <RemovedDueToNotAvailableInMarket>L'article a été retiré du panier car il n'est pas disponible sur votre marché.</RemovedDueToNotAvailableInMarket>
        <RemovedDueToUnavailableCatalog>L'article a été retiré du panier car le catalogue de cette entrée n'est pas disponible.</RemovedDueToUnavailableCatalog>
        <RemovedDueToUnavailableItem>L'article a été retiré du panier car il n'est pas disponible pour le moment.</RemovedDueToUnavailableItem>
        <RemovedDueToInsufficientQuantityInInventory>L'article a été retiré du panier car la quantité disponible est insuffisante.</RemovedDueToInsufficientQuantityInInventory>
        <RemovedDueToInactiveWarehouse>L'article a été retiré du panier car l'entrepôt sélectionné est inactif.</RemovedDueToInactiveWarehouse>
        <RemovedDueToMissingInventoryInformation>L'article a été supprimé en raison d'informations d'inventaire manquantes.</RemovedDueToMissingInventoryInformation>
        <RemovedDueToInvalidPrice>L'article a été supprimé en raison d'un prix non valide.</RemovedDueToInvalidPrice>
        <RemovedDueToInvalidMaxQuantitySetting>L'article a été supprimé en raison d'un paramètre non valide pour la quantité maximale.</RemovedDueToInvalidMaxQuantitySetting>
        <AdjustedQuantityByMinQuantity>La quantité d'articles a été ajustée en raison du seuil de quantité minimale.</AdjustedQuantityByMinQuantity>
        <AdjustedQuantityByMaxQuantity>La quantité d'articles a été ajustée en raison du seuil de quantité maximale.</AdjustedQuantityByMaxQuantity>
        <AdjustedQuantityByBackorderQuantity>La quantité d'articles a été ajustée en raison du seuil de quantité de commandes en souffrance.</AdjustedQuantityByBackorderQuantity>
        <AdjustedQuantityByPreorderQuantity>La quantité d'articles a été ajustée en raison du seuil de quantité de précommande.</AdjustedQuantityByPreorderQuantity>
        <AdjustedQuantityByAvailableQuantity>La quantité d'articles a été ajustée en raison du seuil de quantité disponible.</AdjustedQuantityByAvailableQuantity>
        <PlacedPricedChanged>Le prix de cet article a changé depuis qu'il a été ajouté à vos favoris.</PlacedPricedChanged>
        <RemovedGiftDueToInsufficientQuantityInInventory>L'article cadeau a été retiré du panier car la quantité disponible est insuffisante.</RemovedGiftDueToInsufficientQuantityInInventory>
        <RejectedInventoryRequestDueToInsufficientQuantity>La demande d'inventaire pour l'article a été rejetée car la quantité disponible n'est pas suffisante.</RejectedInventoryRequestDueToInsufficientQuantity>
      </validation>
    </cart>
  </language>
</languages>

Step 2: Create a model class that will hold the error message and variant code.

public class CartValidationIssue
{
        public string Message { get; set; }
 
        public string Code{ get; set; }

        public bool IsBlank => string.IsNullOrWhiteSpace(this.Message);
       
        public static CartValidationIssue Make(string message, string code)
        {
            return new CartValidationIssue
            {
                Message = message,
                Code = code,
            };
        }
 }

Step 3: Create described methods where you are validating your cart and returns the validation messages in the list format after reading from XML file and show on the cart page or mini-cart area.

  1. Use ICurrentMarket interface and get the current market culture
  2. Make sure you have selected correct default language for the current market in commerce manager for e.g. France choose default language francais

 

public List<CartValidationIssue> ValidateCart(ICart cart)
{

            var validationResult = _orderValidationService.ValidateOrder(cart);

            var errors =
                validationResult
                    ?.Select(lineItemIssueEntry => new
                    {
                        LineItemIssues =
                            lineItemIssueEntry.Value
                                .Select(validationIssue => new
                                {
                                    ValidationIssueMessage = this.GetCartValidationMessage(validationIssue),
                                    LineItemCode = lineItemIssueEntry.Key.Code,
                                })
                                .ToList(),
                    })
                    .SelectMany(lineItemIssueGroup => lineItemIssueGroup.LineItemIssues)
                    .Select(x => CartValidationIssue.Make(x.ValidationIssueMessage, x.LineItemCode))
                    .Where(x => !x.IsBlank)
                    .ToList() ?? new List<CartValidationIssue>();

            return errors;
 }
 private string GetCartValidationMessage(ValidationIssue issue)
 {
            var market = _currentMarket.GetCurrentMarket();
            var cultureInfo = market.DefaultLanguage;

            switch (issue)
            {
                default:
                case ValidationIssue.None:
                    return null;

                case ValidationIssue.CannotProcessDueToMissingOrderStatus:
                    return LocalizationService.Current.GetStringByCulture("/cart/validation/CannotProcessDueToMissingOrderStatus", "It cannot process due to missing order status.", cultureInfo);

                case ValidationIssue.RemovedDueToCodeMissing:
                    return LocalizationService.Current.GetStringByCulture("/cart/validation/RemovedDueToCodeMissing", "The catalog entry code that maps to the line item has been removed or changed.", cultureInfo);

                case ValidationIssue.RemovedDueToNotAvailableInMarket:
                    return LocalizationService.Current.GetStringByCulture("/cart/validation/RemovedDueToNotAvailableInMarket", "The catalog entry code that maps to the line item has been removed or changed.", cultureInfo);

                case ValidationIssue.RemovedDueToUnavailableCatalog:
                    return LocalizationService.Current.GetStringByCulture("/cart/validation/RemovedDueToUnavailableCatalog", "The catalog entry code that maps to the line item has been removed or changed.", cultureInfo);

                case ValidationIssue.RemovedDueToUnavailableItem:
                    return LocalizationService.Current.GetStringByCulture("/cart/validation/RemovedDueToUnavailableItem", "Item has been removed from the cart because it is not available at this time.", cultureInfo);

                case ValidationIssue.RemovedDueToInsufficientQuantityInInventory:
                    return LocalizationService.Current.GetStringByCulture("/cart/validation/RemovedDueToInsufficientQuantityInInventory", "Item has been removed from the cart because there is not enough available quantity.", cultureInfo);

                case ValidationIssue.RemovedDueToInactiveWarehouse:
                    return LocalizationService.Current.GetStringByCulture("/cart/validation/RemovedDueToInactiveWarehouse", "Item has been removed from the cart because the selected warehouse is inactive.", cultureInfo);

                case ValidationIssue.RemovedDueToMissingInventoryInformation:
                    return LocalizationService.Current.GetStringByCulture("/cart/validation/RemovedDueToMissingInventoryInformation", "Item has been removed due to missing inventory information.", cultureInfo);

                case ValidationIssue.RemovedDueToInvalidPrice:
                    return LocalizationService.Current.GetStringByCulture("/cart/validation/RemovedDueToInvalidPrice", "Item has been removed due to an invalid price.", cultureInfo);

                case ValidationIssue.RemovedDueToInvalidMaxQuantitySetting:
                    return LocalizationService.Current.GetStringByCulture("/cart/validation/RemovedDueToInvalidMaxQuantitySetting", "Item has been removed due to an invalid setting for maximum quantity.", cultureInfo);

                case ValidationIssue.AdjustedQuantityByMinQuantity:
                    return LocalizationService.Current.GetStringByCulture("/cart/validation/AdjustedQuantityByMinQuantity", "Item quantity has been adjusted due to the minimum quantity threshold", cultureInfo);

                case ValidationIssue.AdjustedQuantityByMaxQuantity:
                    return LocalizationService.Current.GetStringByCulture("/cart/validation/AdjustedQuantityByMaxQuantity", "Item quantity has been adjusted due to the maximum quantity threshold.", cultureInfo);

                case ValidationIssue.AdjustedQuantityByBackorderQuantity:
                    return LocalizationService.Current.GetStringByCulture("/cart/validation/AdjustedQuantityByBackorderQuantity", "Item quantity has been adjusted due to backorder quantity threshold.", cultureInfo);

                case ValidationIssue.AdjustedQuantityByPreorderQuantity:
                    return LocalizationService.Current.GetStringByCulture("/cart/validation/AdjustedQuantityByPreorderQuantity", "Item quantity has been adjusted due to the preorder quantity threshold.", cultureInfo);

                case ValidationIssue.AdjustedQuantityByAvailableQuantity:
                    return LocalizationService.Current.GetStringByCulture("/cart/validation/AdjustedQuantityByAvailableQuantity", "Item quantity has been adjusted due to the available quantity threshold.", cultureInfo);

                case ValidationIssue.PlacedPricedChanged:
                    return LocalizationService.Current.GetStringByCulture("/cart/validation/PlacedPricedChanged", "This item's price has changed since it was added to your favorites.", cultureInfo);

                case ValidationIssue.RemovedGiftDueToInsufficientQuantityInInventory:
                    return LocalizationService.Current.GetStringByCulture("/cart/validation/RemovedGiftDueToInsufficientQuantityInInventory", "Gift item has been removed from the cart because there is not enough available quantity.", cultureInfo);

                case ValidationIssue.RejectedInventoryRequestDueToInsufficientQuantity:
                    return LocalizationService.Current.GetStringByCulture("/cart/validation/RejectedInventoryRequestDueToInsufficientQuantity", "The inventory request for item has been rejected because there is not enough available quantity.", cultureInfo);
            }
 }

Result:

e.g. The validation message display for France(fr) market in the French language.

Enjoy the coding and share your thoughts 😊

Thanks for your visit!

Feb 01, 2021

Comments

Please login to comment.
Latest blogs
CMS 13: The New Core Element of Your AI-First Optimizely Platform

CMS 13 is out and already brings solid AI-first foundations. With impressive features already shipped and an exciting roadmap ahead, this is the...

Michał Mitas | Apr 11, 2026 |

Deploying to Linux in SaaS (Configured) Commerce

With Optimizely SaaS (Configured) Commere now suporting net8.0 extensions dll, you will need to make a small tweak to how you distribute you...

Mark Hall | Apr 10, 2026 |

Optimizely CMS 13 and the Alloy demo site

The Alloy demo site now runs on Optimizely CMS 13. Here’s a quick guide to getting it up and running locally.

Tomas Hensrud Gulla | Apr 10, 2026 |

A day in the life of an Optimizely OMVP: Getting Up to Speed with Optimizely CMS 13 — A Free Learning Path

If you're working with Optimizely and haven't started exploring CMS 13 yet, now's the time. I've put together a dedicated CMS 13 course within the...

Graham Carr | Apr 10, 2026