NopCommerce Plugin Localization for Validation Errors and Properties

NopCommerce features strong support for Localization, and at some point you’ll want to add this feature into your plugins. Localization allows for all of the user facing text in your plugin to be content manageable – meaning it can either be edited to say something else or translated into another language through the Admin area.  NopCommerce localization is actually pretty easy and straight forward once you know how to set things up.

I recently released a plugin you can download here that assists you with tracking trial downloads.  This plugin features pretty strong localization support so I’ll be using code samples from it in this tutorial.

The trick with localization is to turn all user facing text into String Resources, which are basically small pieces of text that can be managed through the NopCommerce admin area.  Creating string resources couldn’t be easier. Inside your main plugin class you can simply create and delete new string resources inside of the Install and Uninstall methods.  These methods are defined in the BasePlugin class that your own plugin class should inherit from.

Let’s define a few string methods that we will use for the display names of our Model properties as well as the validation errors.

Here is an example of the install method:

public override void Install()
{
    _context.Install();
    //User Form
    this.AddOrUpdatePluginLocaleResource("Plugins.Widgets.TrialTracker.NameLabel""Your Name");
    this.AddOrUpdatePluginLocaleResource("Plugins.Widgets.TrialTracker.NameLabel.Hint""Please provide a name.");
    this.AddOrUpdatePluginLocaleResource("Plugins.Widgets.TrialTracker.NameRequired""Name is Required");
    this.AddOrUpdatePluginLocaleResource("Plugins.Widgets.TrialTracker.EmailLabel""Your Email");
    this.AddOrUpdatePluginLocaleResource("Plugins.Widgets.TrialTracker.EmailLabel.Hint""Please provide an email adddress.");
    this.AddOrUpdatePluginLocaleResource("Plugins.Widgets.TrialTracker.EmailRequired""Email Address is Required");
    this.AddOrUpdatePluginLocaleResource("Plugins.Widgets.TrialTracker.EmailFormat""Invalid Email Address");
    base.Install();
}

And the uninstall method:

public override void Uninstall()
        {
            _context.Uninstall();
            //User Form
            this.DeletePluginLocaleResource("Plugins.Widgets.TrialTracker.NameLabel");
            this.DeletePluginLocaleResource("Plugins.Widgets.TrialTracker.NameLabel.Hint");
            this.DeletePluginLocaleResource("Plugins.Widgets.TrialTracker.NameRequired");
            this.DeletePluginLocaleResource("Plugins.Widgets.TrialTracker.EmailLabel");
            this.DeletePluginLocaleResource("Plugins.Widgets.TrialTracker.EmailLabel.Hint");
            this.DeletePluginLocaleResource("Plugins.Widgets.TrialTracker.EmailRequired");
            this.DeletePluginLocaleResource("Plugins.Widgets.TrialTracker.EmailFormat");
            base.Uninstall();
        }

Using this technique you have to uninstall and reinstall your plugin to apply any updates to your string resources.  I also included a few “Hint” string resources as a side tip.  When writing your NopCommerce Plugin Views, you should always use the HTML Helper extension @NopLabelFor, which has the ability to print out Model Data Annotations that use string resources.  If you add a “.hint” string resource to go with the actual property display name, the helper will automatically generate a tool tip to go with it.

Now lets look at our Model, seen below:

[Validator(typeof(TrialTrackerValidator))]
    public class TrialTrackerRecord : BaseEntity
    {
        public int TrialTrackerId { getset; }
        [NopResourceDisplayName("Plugins.Widgets.TrialTracker.NameLabel")]
        public string CustomerName { getset; }
        [NopResourceDisplayName("Plugins.Widgets.TrialTracker.EmailLabel")]
        public string CustomerEmail { getset; }
        public string ProductName { getset; }
        public int Productid { getset; }
        public string DownloadDate { getset; }
        public bool OnMailingList { getset; }
    }

There are two important items to note here.  The first is that we are using the NopResourceDisplayName custom attribute, which accepts the system name of a string resource as a parameter.  You need to include a @Using statement for Nop.Web.Framework for this to work.  When you render these properties using @NopLabelFor, it will automatically pull the string resource value (and the related “.hint” resource) and display that to your users.  This makes all of your field display names content editable!

The second item of interest is the real meat of this topic.  NopCommerce uses Fluent Validation, so we need to add a reference to the FluentValidation DLL in our project and include it in our Model class with a @Using statement.  The Fluent Validation DLL can be found in the Packages folder of your NopCommerce source code, just browse to it in the Add Reference window and include it.  You now have access to the Validator class, which accepts a class that inherits from AbstractValidator<> as a parameter.  Here I am passing in a class called TrialTrackerValidator – lets open up this class and see how it works.

public class TrialTrackerValidator : AbstractValidator<TrialTrackerRecord>
    {
        public TrialTrackerValidator(ILocalizationService localizationService)
        {
            RuleFor(x => x.CustomerEmail)
                .NotEmpty().WithMessage(localizationService.GetResource("Plugins.Widgets.TrialTracker.EmailRequired"))
                .EmailAddress().WithMessage(localizationService.GetResource("Plugins.Widgets.TrialTracker.EmailFormat"));
 
            RuleFor(x => x.CustomerName)
                .NotEmpty().WithMessage(localizationService.GetResource("Plugins.Widgets.TrialTracker.NameRequired"));
        }
    }

Here you can see I have declared the TrialTrackerValidator class and am inheriting from AbstractValidator<TrialTrackerRecord>.  You need to pass in the domain model you are trying to validate as the Type Parameter to the Abstract Validator. In our case, that is the class we looked at first.

Inside the TrialTrackerValidator class constructor we simply need to declare our rules using lambdas and the property names of our model.  The “.WithMessage” method accepts a string parameter as the error message to display.  Here we can pass in any of our localized strings as a parameter.  Notice that I have passed in ILocalizationService as a parameter to the class constructor.  NopCommerce will see this parameter and use its dependency injection engine to provide us with an instance of the Localization Service.  We can use the GetResource method of the Localization Service to retrieve a string resource and pass it into the “.WithMessage” method.

Remember, inside your plugin views its important to use @NopLabelFor to show the Localized display name and tool tips.  You also need to use the standard MVC @Html.ValidationMessageFor helper or a similar helper to display the validation errors we customized in our Validation class.  An example of some razor code to get all this working can be seen below:

@model Nop.Plugin.Misc.TrialTracker.Domain.TrialTrackerRecord
@using System
@using Nop.Web.Framework
@using Nop.Web.Framework.UI
<!-- Button trigger modal -->
<div class="form-group">
    @Html.NopLabelFor(model => model.CustomerName)
    @Html.TextBoxFor(model => model.CustomerName)
    @Html.ValidationMessageFor(model => model.CustomerName)
</div>

That’s not too bad, right?  Below is an example of what this might look like to the user:

Localized Validation Errors NopCommerce

Another quick tip – this is pretty obvious if you’ve read any of the NopCommerce source code, but you can display a string resource anywhere in the HTML of your plugin views by using @T(“Your.String.Resource.Name.Here”).  Just make sure you declare them in your install method first!

Hope this helps!

No Comments

Comments Closed