Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ASP.NET Core 3.1 : Shared Localization not working for version 3.1

I may be not doing the correct configurations in the Startup.cs file. I have created a demo application to make it working, but after trying various things it is not working. The demo repository is available at following link

https://github.com/gurpreet42/MyAppV3

Configurations of startup.cs files are

public void ConfigureServices(IServiceCollection services)
{
   services.AddSingleton<LocService>();
   services.AddLocalization(options => options.ResourcesPath = "Resources");

   services.Configure<RequestLocalizationOptions>(options =>
            {
                var supportedCultures = new List<CultureInfo>
                                            {
                                                new CultureInfo("en-US"),
                                                new CultureInfo("nl")
                                            };

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

   services.AddMvc()
           .AddViewLocalization()
           .AddDataAnnotationsLocalization(options =>
                {
                   options.DataAnnotationLocalizerProvider = (type, factory) =>
                   {
                       var assemblyName = new AssemblyName(typeof(SharedResource).GetTypeInfo().Assembly.FullName);
                       return factory.Create("SharedResource", assemblyName.Name);
                   };
               }).SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
}

public void Configure(IApplicationBuilder app,
                        IHostingEnvironment env,
                        ILoggerFactory loggerFactory)
{
    // Localisation
    var locOptions = app.ApplicationServices.GetService<IOptions<RequestLocalizationOptions>>();
    app.UseRequestLocalization(locOptions.Value);

    app.UseHttpsRedirection();
    app.UseStaticFiles();
    app.UseAuthentication();
    app.UseSession();

    app.UseSession();
    app.UseCookiePolicy();
}

The code in the LocService class is

public class LocService
{
    private readonly IStringLocalizer _localizer;

    public LocService(IStringLocalizerFactory factory)
    {
        var type = typeof(SharedResource);
        var assemblyName = new AssemblyName(type.GetTypeInfo().Assembly.FullName);
        _localizer = factory.Create("SharedResource", assemblyName.Name);
    }

    public LocalizedString GetLocalizedHtmlString(string key)
    {
        var value= _localizer[key];
        return value;
    }
}

Now on our controller, we can access the localized string as

localizerService.GetLocalizedHtmlString("my_string")

Under the "Resources" folder we have following files present

SharedResource.cs
SharedResource.en-US.resx
SharedResource.nl.resx

Please suggest where the configurations are wrong or do I need to add some extra package?

like image 296
Gurpreet Kailey Avatar asked Feb 01 '20 17:02

Gurpreet Kailey


2 Answers

I had similar issue during upgrade from 2.2 to 3.1.

In 2.2 my setup was:

        services.AddLocalization(options => options.ResourcesPath = "Resources");
        services.AddMvc(config =>
            {
               ... <omitted for brevity>
            })
            .AddViewLocalization(LanguageViewLocationExpanderFormat.Suffix)
            .SetCompatibilityVersion(CompatibilityVersion.Version_2_2);

All resources where in "Resources" folder. SharedResources.cs had recommended namespace of the project:

// *************************
// DO NOT CHANGE NAMESPACE
// *************************
// ReSharper disable once CheckNamespace
namespace MyProject
{
    // Dummy class to group shared resources
    public class SharedResources
    {
    }
}

And View Localizations were based on the path e.g.

Resources
   Pages
      Error.en-US.resx
      Error.ja-JP.resx

With 3.1, recommended setup was (with minimal changes):

        services.AddLocalization();
        services.AddRazorPages().AddRazorRuntimeCompilation();
        services.AddControllersWithViews(config =>
            {
               ... <omitted for brevity>
            })
            .AddViewLocalization(LanguageViewLocationExpanderFormat.Suffix)
            .SetCompatibilityVersion(CompatibilityVersion.Version_3_0);

At this point SharedResources was working fine but IViewLocalizer and view localizations were not working.

I found two ways to fix it based on above suggestions and this article:

  1. Opt out of the new naming convention, effectively going back to what was used in 2.2 by adding following to csproj file:

     <PropertyGroup>
         <EmbeddedResourceUseDependentUponConvention>false</EmbeddedResourceUseDependentUponConvention>
     </PropertyGroup>
    

And, adding options => options.ResourcesPath = "Resources" back to services.AddLocalization().

  1. Keep 3.1 setup and fix each view localization by adding dummy .cs file with namespace that is outside of resources folder, for example:

    Resources
       Pages
          Error.cs
          Error.en-US.resx
          Error.ja-JP.resx
    

Where Error.cs is:

// *************************
// DO NOT CHANGE NAMESPACE
// *************************
// ReSharper disable once CheckNamespace
namespace MyProject.Pages
{
    // Dummy class to group shared resources
    public class Error
    {
    }
}

So if you have lots of View Localizations like me, #1 option would probably be better, as it is configuration change only, leaving all existing view localization as they were.

like image 161
CrnaStena Avatar answered Oct 10 '22 08:10

CrnaStena


There is no need to create the LocService you can use IStringLocalizer.

"Resources" folder structure

SharedResource.cs
SharedResource.en-US.resx
SharedResource.nl.resx

At the class SharedResource, do not add "Resources" in the namespace. Like MyAppV3.Resources. Please keep it just MyAppV3.

namespace MyAppV3
{
    public class SharedResource
    {
    }
}

Add in your .csproj the following property

<PropertyGroup><EmbeddedResourceUseDependentUponConvention>false</EmbeddedResourceUseDependentUponConvention></PropertyGroup>

Add to startup.cs > ConfigureServices

    services.AddLocalization(options => options.ResourcesPath = "Resources");
    services.AddScoped<IStringLocalizer, StringLocalizer<SharedResource>>();

    services
        .Configure<RequestLocalizationOptions>(options =>
            {
                var cultures = new[]
                                   {
                                       new CultureInfo("en"),
                                       new CultureInfo("nl")
                                   };
                options.DefaultRequestCulture = new RequestCulture("en");
                options.SupportedCultures = cultures;
                options.SupportedUICultures = cultures;
            });

Startup.cs > Configure

   app.UseRequestLocalization(app.ApplicationServices
            .GetRequiredService<IOptions<RequestLocalizationOptions>>().Value);

Add to the controller the IStringLocalizer parameter.

   public MyTestController(IStringLocalizer localizer)
   {
        this.localizer = localizer;
   }

   public IActionResult Get()
   {          
        var value = this.localizer.GetString("RessourceName");
        return this.Ok(value);
   }
like image 38
André Mendonça Avatar answered Oct 10 '22 09:10

André Mendonça