Allowing dynamic SupportedCultures in RequestLocalizationOptions

Allowing dynamic SupportedCultures in RequestLocalizationOptions

The documented usage of RequestLocalizationOptions in ASP.NET 5/Core is to assign a static list of SupportedCultures since ASP.NET is assuming you’ll know up-front what cultures your app is supporting. But what if you are creating a CMS or another web app that allows users to include cultures dynamically?

This isn’t documented anywhere but it’s certainly possible. RequestLocalizationOptions.SupportedCultures is a mutable IList which means that values can be added/removed at runtime if you really want.

Create a custom RequestCultureProvider

First thing you need is a custom RequestCultureProvider. The trick is to pass in the RequestLocalizationOptions into it’s ctor so you can dynamically modify the SupportedCultures when required.

public class MyCultureProvider : RequestCultureProvider
{
    private readonly RequestLocalizationOptions _localizationOptions;
    private readonly object _locker = new object();

    // ctor with reference to the RequestLocalizationOptions
    public MyCultureProvider(RequestLocalizationOptions localizationOptions)
        => _localizationOptions = localizationOptions;

    public override Task<ProviderCultureResult> DetermineProviderCultureResult(HttpContext httpContext)
    {
        // TODO: Implement GetCulture() to get a culture for the current request
        CultureInfo culture = GetCulture(); 

        if (culture is null)
        {
            return NullProviderCultureResult;
        }

        lock (_locker)
        {
            // check if this culture is already supported
            var cultureExists = _localizationOptions.SupportedCultures.Contains(culture);

            if (!cultureExists)
            {
                // If not, add this as a supporting culture
                _localizationOptions.SupportedCultures.Add(culture);
                _localizationOptions.SupportedUICultures.Add(culture);
            } 
        }

        return Task.FromResult(new ProviderCultureResult(culture.Name));
    }
}

Add your custom culture provider

You can configure RequestLocalizationOptions in a few different ways, this example registers a custom implementation of IConfigureOptions<RequestLocalizationOptions> into DI

public class MyRequestLocalizationOptions : IConfigureOptions<RequestLocalizationOptions>
{
    public void Configure(RequestLocalizationOptions options)
    {
        // TODO: Configure other options parameters

        // Add the custom provider,
        // in many cases you'll want this to execute before the defaults
        options.RequestCultureProviders.Insert(0, new MyCultureProvider(options));
    }
}

Then just register these options: Services.ConfigureOptions<MyRequestLocalizationOptions>();

That’s it, now you can have dynamic SupportedCultures in your app!

Author

Shannon Thompson

I'm a Senior Software Engineer working full time at Microsoft. Previously, I was working at Umbraco HQ for about 10 years. I maintain several open source projects (many related to Umbraco) such as Articulate, Examine and Smidge, and I also have a commercial software offering called ExamineX. Welcome to my blog :)

comments powered by Disqus