Extending ILocalizationService

2025/09/16 5:38 PM

My understanding is that Resource strings are purely from files now, and that there's no longer an in-CMS set of localization strings.
I'd like to reimplement that, and I largely have it, except I'd like to override the built-in ILocalizationService - to use the built-in string first if it exists, but to access my secondary logic if it doesn't find a match in the files. The reason for overriding the ILocalizationService is so that I can use built-in logic like ResHelper.GetString to access those localized strings.

Is it possible to override ILocalizationService, or otherwise inject my logic in that pathway?


Environment

  • Xperience by Kentico version: 30.8.0
Tags:
Localization

Answers

2025/09/16 6:03 PM
Accepted answer

I wouldn't recommend going this route.

  1. What are your goals in offering dynamic (database) localizations of content? Are you localizing the administration UI or the website experience for visitors?
  2. Did you review our guide that covers using .NET's native IStringLocalizer?
  3. If you need something more dynamic for the website experience, have you thought about using a content item (or set of them) to define localized content?
2025/09/22 8:18 PM
  1. Localization of widgets and page template content.
  2. I did, but all of that talked about using a SharedResources resource file. It wasn't clear to me that IStringLocalizer could work with a database data source (though having reviewed the Microsoft docs it does look like it can) https://learn.microsoft.com/en-us/aspnet/core/fundamentals/localization/make-content-localizable?view=aspnetcore-8.0#istringlocalizer
  3. That would be fine - the bottleneck wasn't how to store it, but how to retrieve it in views / templates. If using IStringLocalizer/IHTMLLocalizer can work from a database source, that's sufficient.
2025/09/23 9:12 AM

We have implemented #3 using a small content item with key and value fields. Created a service to return these items and we inject that into a Tag Helper

[HtmlTargetElement("resource-string")]
public class ResourceStringTagHelper : TagHelper
{
    [HtmlAttributeName("baseKey")]
    public string BaseKey { get; set; }

    [HtmlAttributeName("key")]
    public string Key { get; set; }

    private readonly IApplicationLocalizationService _applicationLocalizationService;


    private readonly IWebsiteChannelContext _websiteChannelContext;

    public ResourceStringTagHelper(IApplicationLocalizationService applicationLocalizationService, 
        IWebsiteChannelContext websiteChannelContext)
    {
        _applicationLocalizationService = applicationLocalizationService;
        _websiteChannelContext = websiteChannelContext;
    }

    public async override Task ProcessAsync(TagHelperContext context, TagHelperOutput output)
    {
        output.TagName = string.Empty;

        var rs = await _applicationLocalizationService.GetLocalizedString($"{BaseKey}{Key}", _websiteChannelContext.WebsiteChannelName, echoBack:false);

        output.Content.SetHtmlContent(rs);
    }
}

You can then drop the tags into your views e.g.

<resource-string key="Default.SiteUI.Shipping.BackToCart" />

We also ensured that the keys are unique by checking the keys everytime an item of the reusable content item type was either created or updated

2025/09/23 2:34 PM

@cbass

IStringLocalizer and IHTMLLocalizer were not designed to be abstractions that encapsulate data retrieval. Neither has Task returning methods.

This means if you query the database inside your implementations of these you will be blocking on the thread that is retrieving from the database (if using "sync" database querying) or, even worse, using an additional thread if you make async calls to the database and then use .GetAwaiter().GetResult().

David's approach scales a lot better because it's asynchronous all the way.

To response this discussion, you have to login first.