Localization in external class libraries in ASP.NET Core

12,474

Solution 1

This is how I solved it. Thanks to Popa Andrei answer for directing me to the right place.

Class Library

Solution -> right click -> Add -> New Project ... -> .Net standard -> Class Library -> I used the name ResourceLibrary

ResourceLibrary
|- Resources
|----- SharedResource.resx
|----- SharedResource.he.resx
|- SharedResource.cs

SharedResource.cs code:

using Microsoft.Extensions.Localization;

namespace ResourceLibrary
{
    public interface ISharedResource
    {
    }
    public class SharedResource : ISharedResource
    {
        private readonly IStringLocalizer _localizer;

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

        public string this[string index]
        {
            get
            {
                return _localizer[index];
            }
        }
    }
}

web application

Right click on webapp project -> Add -> Reference ... -> Check Resource Library

In your webapp startup.cs:

using ResourceLibrary;
...

public void ConfigureServices(IServiceCollection services) {
    ...
    services.AddLocalization(o => { o.ResourcesPath = "Resources"; });

    services.Configure<RequestLocalizationOptions>(options =>
            {
                CultureInfo[] supportedCultures = new[]
                {
                    new CultureInfo("en"),
                    new CultureInfo("he")
                };

                options.DefaultRequestCulture = new RequestCulture("en");
                options.SupportedCultures = supportedCultures;
                options.SupportedUICultures = supportedCultures;
             });
     ...
     }

     public void Configure(IApplicationBuilder app, IHostingEnvironment env)
        {
        ...
        app.UseRequestLocalization(); //before app.UseMvc()
        ...
        }

Example use in controller:

 using ResourceLibrary;
 ...

 public class ExampleController : Controller
    {
    private readonly IStringLocalizer<SharedResource> _sharedLocalizer;
    public EmailsController(IStringLocalizer<SharedResource> sharedLocalizer)
    {
        _sharedLocalizer = sharedLocalizer;
    }

    [HttpGet]
    public string Get()
    {
        return _sharedLocalizer["StringToTranslate"];
    }

View example:

@using Microsoft.AspNetCore.Mvc.Localization
@inject IHtmlLocalizer<ResourceLibrary.SharedResource> SharedLocalizer

<p>@SharedLocalizer["StringToTranslate"]</p>

Solution 2

You can store the .resx files on MyServices project and create a method for retrieving the resources based on keys. In order to access the IStringLocalizer from MyServices you have to install Microsoft.Extensions.Localization.Abstractions nuget.

Basically localization configurations have to remain on MyWebApp (Startup class), but on MyServices you have to add that nuget for using IStringLocalizer and create a method like GetResourceValueByKey(key). This method can be called from wherever MyServices project will be referenced.

using Microsoft.Extensions.Localization;

namespace GlobalizationLibrary { public class SharedResource:ISharedResource { private readonly IStringLocalizer _localizer;

public SharedResource(IStringLocalizer<SharedResources> localizer) { _localizer = localizer; } public string GetResourceValueByKey(string resourceKey) { return _localizer[resourceKey]; } }}

Solution 3

One typical solution is for your MyServices assembly to return resource keys (instead of returning the actual resources to be displayed on screen). You can have the .resx file as part of MyWebApp and have resource values for each resource key. This way, your MyService can be utilized by various UI apps each of which have their own resource representations.

Another approach would be to keep the .resx file as part of MyService itself. MyWebApp can load the other assembly and read the resource file from that.

Yet another option would be to keep the resources as a new assembly, and again load it from MyWebApp.

Check the following SO answers to get more details about how to do access .resx files from another assembly -

How can I read embedded .resx in different assembly

Access strings resources from embedded .resx in dll?

How to access another assembly's .resx?

Share:
12,474

Related videos on Youtube

Yurii N.
Author by

Yurii N.

Updated on September 15, 2022

Comments

  • Yurii N.
    Yurii N. over 1 year

    I have two projects:

    • MyWebApp - ASP.NET Core Web API
    • MyServices - .NET Core class library, which contains helpful services for project above

    How can I add localization with IStringLocalizer to MyServices? Where must be .resx files located?

  • Yurii N.
    Yurii N. almost 7 years
    Am I right, that putting .resx files in the root of the MyServices would be enough? What do you mean by returning resource keys?
  • ArunGeorge
    ArunGeorge almost 7 years
    Yes, that is right. If you check the Build Action of resource file, it will be is Embedded Resource by default. So it will be available whenever the dll loads.
  • ArunGeorge
    ArunGeorge almost 7 years
    By returning resource keys, I meant the following -> When you want to return an error message from MyServices, instead of returning the full message "An error occurred in feature x, situation y happened..", you just return a key (Something like Error1001 or ErrorFeatureXSituationY) from the MyServices assembly. Do not have any resource file attached within it. In MyWebApp, have a resource file which has a key Error1001 with the proper error message. This way, your resource file will only be in your MyWebApp.
  • Yurii N.
    Yurii N. almost 7 years
    Seems interesting, but I need .resx files to be included in MyServices, so I will try variant with files in a root!
  • Jenan
    Jenan almost 6 years
    Why did you use ISharedResource?
  • Shiran Dror
    Shiran Dror almost 6 years
    @Jenan this is the standard pattern for dependency injections docs.microsoft.com/en-us/aspnet/core/fundamentals/…
  • ibubi
    ibubi over 5 years
    what about attribute based localizations? (data annotations on viewmodels or enums)
  • Soufien Hajji
    Soufien Hajji over 5 years
    Great answer. I tried it and it worked with embedded resource build action, however it doesn't work with content build action. Can you give me an alternative to make this method work with content build action type ?
  • Stef Heyenrath
    Stef Heyenrath over 5 years
    This solution and the listed links are not for DotNet Core.
  • user989988
    user989988 over 5 years
    Is it possible to get ResourcePath inside :services.Configure<RequestLocalizationOptions>(options => { CultureInfo[] supportedCultures = new[] { new CultureInfo("en"), new CultureInfo("he") }; options.DefaultRequestCulture = new RequestCulture("en"); options.SupportedCultures = supportedCultures; options.SupportedUICultures = supportedCultures; }); ... }
  • c-sharp-and-swiftui-devni
    c-sharp-and-swiftui-devni almost 4 years
    @SoufienHajji I tried this it refuses to work in 3.1 unless the resources our in the main assemlby any ideas.
  • Metehan Mutlu
    Metehan Mutlu almost 3 years
    @csharpdudeni77 Same Here. Any updates on this?
  • c-sharp-and-swiftui-devni
    c-sharp-and-swiftui-devni almost 3 years
    @MetehanMutlu why asking me i was not the orginal op
  • Benjamin Martin
    Benjamin Martin over 2 years
    How can i use this in a separate Assembly for DTOs with DataAnnotations?