Skip to content

Localization

Add multi-language support to your nopCommerce plugins.

The recommended approach is to use XML resource files located in Localization/ folder:

File Structure

Localization/
└── pluginResources.en-us.xml

XML File Format

xml
<?xml version="1.0" encoding="utf-8"?>
<Language Name="English" Supported="true">
  <LocaleResource Name="Plugins.Misc.PluginTemplate.Title">
    <Value>My Plugin</Value>
  </LocaleResource>
  <LocaleResource Name="Plugins.Misc.PluginTemplate.Settings.Enabled">
    <Value>Enable plugin</Value>
  </LocaleResource>
  <LocaleResource Name="Plugins.Misc.PluginTemplate.Settings.Enabled.Hint">
    <Value>Check to enable the plugin functionality</Value>
  </LocaleResource>
  <LocaleResource Name="Plugins.Misc.PluginTemplate.Settings.ApiKey">
    <Value>API Key</Value>
  </LocaleResource>
</Language>

Loading XML Resources in Plugin.cs

csharp
// Plugin.cs
using System.Text;
using Nop.Core.Infrastructure;
using Nop.Services.Localization;

public class Plugin : BasePlugin, IMiscPlugin
{
    #region Fields

    private readonly ILanguageService _languageService;
    private readonly ILocalizationService _localizationService;
    private readonly ILogger _logger;

    #endregion

    #region Ctor

    public Plugin(
        ILanguageService languageService,
        ILocalizationService localizationService,
        ILogger logger)
    {
        _languageService = languageService;
        _localizationService = localizationService;
        _logger = logger;
    }

    #endregion

    #region Methods

    public override async Task InstallAsync()
    {
        await InstallLocalResourcesFromXmlFileAsync();
        await base.InstallAsync();
    }

    public override async Task UpdateAsync(string currentVersion, string targetVersion)
    {
        if (!currentVersion.Equals(targetVersion))
            await InstallLocalResourcesFromXmlFileAsync();

        await base.UpdateAsync(currentVersion, targetVersion);
    }

    #endregion

    #region Utilities

    private Language GetDefaultEnglishLanguage()
    {
        return _languageService.GetAllLanguages()
            .FirstOrDefault(x => x.UniqueSeoCode
                .Equals("en", StringComparison.InvariantCultureIgnoreCase));
    }

    private async Task InstallLocalResourcesFromXmlFileAsync()
    {
        var language = GetDefaultEnglishLanguage();
        if (language == null)
        {
            _logger.Error("Can't add resource strings. Required language not found!");
            return;
        }

        try
        {
            var fileProvider = EngineContext.Current.Resolve<INopFileProvider>();
            var path = fileProvider.MapPath(PluginDefaults.XmlResourceStringFilePath);
            using var sr = new StreamReader(path, Encoding.UTF8);
            await _localizationService.ImportResourcesFromXmlAsync(language, sr);
        }
        catch (Exception ex)
        {
            _logger.Error("Error processing resource string XML file.", ex);
        }
    }

    #endregion
}

PluginDefaults.cs

csharp
namespace NopStation.Plugin.Misc.PluginTemplate;

public class PluginDefaults
{
    public static string XmlResourceStringFilePath => 
        "~/Plugins/NopStation.Plugin.Misc.PluginTemplate/Localization/pluginResources.en-us.xml";
    
    public static string PluginSystemName => "NopStation.Plugin.Misc.PluginTemplate";
}

Programmatic Approach

For simpler plugins, add resources directly:

csharp
public override async Task InstallAsync()
{
    var localizationService = EngineContext.Current.Resolve<ILocalizationService>();

    await localizationService.AddOrUpdateLocaleResourceAsync(new Dictionary<string, string>
    {
        ["Plugins.Widgets.MyPlugin.Title"] = "My Plugin",
        ["Plugins.Widgets.MyPlugin.Settings.Enabled"] = "Enable plugin",
        ["Plugins.Widgets.MyPlugin.Settings.ApiKey"] = "API Key",
    });

    await base.InstallAsync();
}

public override async Task UninstallAsync()
{
    var localizationService = EngineContext.Current.Resolve<ILocalizationService>();
    await localizationService.DeleteLocaleResourcesAsync("Plugins.Widgets.MyPlugin");
    await base.UninstallAsync();
}

Using Localized Strings

In Controllers

csharp
var title = await _localizationService.GetResourceAsync("Plugins.Misc.PluginTemplate.Title");

In Views

html
@inherits Nop.Web.Framework.Mvc.Razor.NopRazorPage<TModel>
<h1>@T("Plugins.Misc.PluginTemplate.Title")</h1>

Best Practices

  1. Use XML files - Easier to manage and update across versions
  2. Use consistent naming - Follow Plugins.{Type}.{Name}.{Key} pattern
  3. Provide hints - Add .Hint resources for complex fields
  4. Update on plugin update - Reload resources when version changes
  5. Clean up on uninstall - Delete resources when uninstalling

Released under the nopCommerce Public License.