Search code examples
c#.netasp.net-coreasp.net-core-localization

How to get resource strings in strongly typed way in asp.net core?


In the following program, in order to get resource strings i am using _localizer["About Title"] where "About Title" is a magic string. How to avoid using strings like this? Is there any strongly typed way?

using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Localization;

namespace Localization.StarterWeb.Controllers
{
    [Route("api/[controller]")]
    public class AboutController : Controller
    {
        private readonly IStringLocalizer<AboutController> _localizer;

        public AboutController(IStringLocalizer<AboutController> localizer)
        {
            _localizer = localizer;
        }

        [HttpGet]
        public string Get()
        {
            return _localizer["About Title"];
        }
    }
}

Solution

  • If you're trying to avoid using a hardcoded string (key) to lookup the localization conversion you could create a LocalizationKeys class that contains the lookup keys for you. You could then leverage the C# 6 nameof operator. This would help alleviate the concern of "magic strings".

    public static class LocalizationKeys
    {
        public const string AboutTitle = nameof(AboutTitle); // Note: this is "AboutTitle"
    
        // ... other keys here
    }
    

    Then you could consume it wherever. One of the benefits are that since this is a member of the class, if the key changes you can use common refactoring tools to safely replace all the references to it rather than trying to do a global string replace on the "magic string". Another benefit is you'd get to use intellisense when accessing the class. I suppose one could consider this "strongly typed".

    You'd consume it as such:

    [Route("api/[controller]")]
    public class AboutController : Controller
    {
        private readonly IStringLocalizer<AboutController> _localizer;
    
        public AboutController(IStringLocalizer<AboutController> localizer)
        {
            _localizer = localizer;
        }
    
        [HttpGet]
        public string Get()
        {
            return _localizer[LocalizationKeys.AboutTitle];
        }
    }
    

    If you really want to get fancy with C# 6 you can also utilize a static using. This will allow you to reference the members of the type you specify. Finally, for simple "single line" returns, we can make them expression bodies. For example:

    using Microsoft.AspNetCore.Mvc;
    using Microsoft.Extensions.Localization;
    using static Localization.StarterWeb.LocalizationKeys; // Note: static keyword
    
    namespace Localization.StarterWeb.Controllers
    {
        [Route("api/[controller]")]
        public class AboutController : Controller
        {
            private readonly IStringLocalizer<AboutController> _localizer;
    
            public AboutController(IStringLocalizer<AboutController> localizer)
            {
                _localizer = localizer;
            }
    
            [HttpGet]
            public string Get() => _localizer[AboutTitle]; // Note: omission of qualifier
        }
    }