Take the community feedback survey now.

sanjay.kumar
Feb 1, 2021
  2490
(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
Optimizely Opal : Reimagining A Utility Sector Use Case

  Introduction Customer engagement through timely and personalized push notifications plays a crucial role in todays Digital First landscape. In th...

Ratish | Sep 12, 2025 |

A day in the life of an Optimizely OMVP - AEO & GEO: The Future of Digital Visibility with Optimizely

The way people discover content online is undergoing a seismic shift. Traditional SEO is no longer enough. With AI-powered tools like ChatGPT,...

Graham Carr | Sep 12, 2025

Building Optimizely OCP Apps Faster with AI and Coding Assistants

Developing Optimizely Connect Platform (OCP) apps can be a rewarding but complex process—especially when integrating with external APIs. Over the...

Pawel Zieba | Sep 11, 2025

New Opal Certifications Are Live and Free!

We’ve got some exciting news to share: two brand-new Opal certifications are now available and they’re completely free. Whether you’re already...

Satata Satez | Sep 10, 2025