genericuser
genericuser

Reputation: 1450

Localization in ASP.Net core MVC not working - unable to locate resource file

In trying to localize my application, I've followed the steps here: https://docs.asp.net/en/latest/fundamentals/localization.html

Here is my code:

Startup.cs

public List<IRequestCultureProvider> RequestCultureProviders { get; private set; }

// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
    services.AddLocalization(options => options.ResourcesPath = "Resources");

    services.AddMvc()
        .AddViewLocalization(options => options.ResourcesPath = "Resources")
        .AddDataAnnotationsLocalization();

    services.AddOptions();

    services.AddTransient<IViewRenderingService, ViewRenderingService>();

    services.AddTransient<IEmailSender, EmailSender>();
}

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

    app.UseStaticFiles();
    app.UseFileServer(new FileServerOptions()
    {
        FileProvider = new PhysicalFileProvider(
        Path.Combine(Directory.GetCurrentDirectory())),
        EnableDirectoryBrowsing = true
    });

    var supportedCultures = new[]
    {
        new CultureInfo("en-US"),
        new CultureInfo("fr"),
    };

    app.UseRequestLocalization(new RequestLocalizationOptions
    {
        DefaultRequestCulture = new RequestCulture("fr"),
        // Formatting numbers, dates, etc.
        SupportedCultures = supportedCultures,
        // UI strings that we have localized.
        SupportedUICultures = supportedCultures,
        RequestCultureProviders = new List<IRequestCultureProvider>
        {
           new QueryStringRequestCultureProvider
           {
               QueryStringKey = "culture",
               UIQueryStringKey = "ui-culture"
           }
        }
    });


}

MyController.cs

public class MyController : Controller
{
    private readonly IViewRenderingService _viewRenderingService;
    private IStringLocalizer<MyController> _localizer;
    private MyOptions _options;
    //Constructor for dependency injection principle
    public MyController(IViewRenderingService viewRenderingService, IStringLocalizer<MyController> localizer, IOptions<MyOptions> options)
    {
        _viewRenderingService = viewRenderingService;
        _localizer = localizer;
        _options = options.Value;
    }

    [HttpGet]
    public string Get()
    {
        // _localizer["Name"] 
        return _localizer["Product"];
    }
}

The *.resx file is stored in the Resources folder, with the name Controllers.MyController.fr.resx (which has an entry for "Product").

However, it's not able to find the resource file, and "Product" is never returned in French. I am using querystring, so here is the query string:

localhost:3333/my?culture=fr

Also in the View, @Localizer["Product"] returns "Product".

Can anyone please help me find whats missing?

EDIT:

After some investigation, I found that culture is getting changed, however it is unable to locate the Resource file. I am using VS2015. can anyone help?

Upvotes: 24

Views: 28376

Answers (16)

LockTar
LockTar

Reputation: 5465

I had the same problem with Visual Studio 17.11.2 and a Blazor Server project. The user interface has changed in VS 17.11.x. You can add a resource file (in Pages folder following the official docs) but the class is not generated so you can't use @inject IStringLocalizer<DashboardCulture> Loc.

I found the solution by opening the project properties, navigate to the "old" Resoures blade and select to create a resource file. Visual Studio then generates a Resources.resx file in the properties folder. When you hit the properties you see that a "tool" is filled. The tool is ResXFileCodeGenerator. Properties of resouce file

As soon I added the tool ResXFileCodeGenerator to my original resouce file, the class is generated and I could inject the class in my blazor page @inject IStringLocalizer<DashboardCulture> Loc.

After that, I just removed the generated resource file.

The project file has the following structure for me:

<ItemGroup>
  <Compile Update="Pages\DashboardCulture.Designer.cs">
    <DesignTime>True</DesignTime>
    <AutoGen>True</AutoGen>
    <DependentUpon>DashboardCulture.resx</DependentUpon>
  </Compile>
</ItemGroup>

<ItemGroup>
  <EmbeddedResource Update="Pages\DashboardCulture.resx">
    <Generator>ResXFileCodeGenerator</Generator>
    <LastGenOutput>DashboardCulture.Designer.cs</LastGenOutput>
  </EmbeddedResource>
</ItemGroup>

Upvotes: 0

Strydrath
Strydrath

Reputation: 1

For me it was "-" in project name - it got changed for "_" and localization couldn't find files

Upvotes: 0

Shivam Negi
Shivam Negi

Reputation: 413

I spent an hour trying to figure out the same and it turned out (in my case) I had not set the access modifier of my resource file to public. Worked fine once it made it public. enter image description here

Probably worth a shot to re-check it to make sure you don't end up debugging for an hour for nothing ;)

Upvotes: 3

Fatos
Fatos

Reputation: 7

My solution to this problem was to rename the generated resource code namespace from for example:

from

namespace ProjectName.Resources to namespace ProjectName

It works for me.

Upvotes: -2

nickwesselman
nickwesselman

Reputation: 6890

In my case, I was actually missing the explicit setting of the ResourcesPath:

services.AddLocalization(options => options.ResourcesPath = "Resources");

Upvotes: 1

Cesar
Cesar

Reputation: 2118

In my case, the problem was that I was specifying:

services.AddLocalization(options => options.ResourcesPath = "Resources");

and:

options.DataAnnotationLocalizerProvider = (type, factory) => 
    factory.Create(typeof(DataAnnotations));

where my DataAnnotations.resx resource file was also located under the "Resources" namespace. This was causing the localizer to search for strings in "MyApp.Resources.Resources.DataAnnotations" instead of "MyApp.Resources.DataAnnotations".

Changing the first line to:

services.AddLocalization();

helped solve the issue.

Upvotes: 5

Ashish Sharma
Ashish Sharma

Reputation: 416

You just need to add "Localization.AspNetCore.TagHelpers" NuGet package in your project by using the following command

Install-Package Localization.AspNetCore.TagHelpers -Version 0.6.0

I hope it will fix your issue

Upvotes: 0

Enrico
Enrico

Reputation: 3443

I solved it by setting the build action of the resx resource file to "embedded resource" enter image description here

Upvotes: 5

Mingo
Mingo

Reputation: 53

I am using VS 2017 targeting .NET Core 2.1 and in my case the project file (.csproj) contained a few strange ItemGroup tags, like these:

<ItemGroup>
    <EmbeddedResource Remove="Resources\Controllers.HomeController.sv.resx" />
    ...
</ItemGroup>
<ItemGroup>
    <None Include="Resources\Controllers.HomeController.sv.resx" />
    ...
</ItemGroup>

When I deleted the lines it started working.

I had been experimenting earlier with adding and removing the resource files so that might have caused the item groups to appear, but it's strange that Visual Studio inserted these lines at all. Seems like a bug.

Upvotes: 1

John Hogan
John Hogan

Reputation: 1036

If the root namespace of an assembly is different than the assembly name:

Localization does not work by default. Localization fails due to the way resources are searched for within the assembly. RootNamespace is a build-time value which is not available to the executing process.

If the RootNamespace is different from the AssemblyName, include the following in AssemblyInfo.cs (with parameter values replaced with the actual values):

using System.Reflection;
using Microsoft.Extensions.Localization;

[assembly: ResourceLocation("Resource Folder Name")]
[assembly: RootNamespace("App Root Namespace")]

More info here

Upvotes: 5

Greivin Marin
Greivin Marin

Reputation: 1

I had the same problem and I fixed it by removing the built-in providers in order to be able to use the default request culture. For do that you'll need to add this code to your services.Configure in the startup class:

    options.RequestCultureProviders = new List<IRequestCultureProvider>
    {
        new QueryStringRequestCultureProvider(),
        new CookieRequestCultureProvider()
    }; 

Please take a look to this other answer: ASP .NET Core default language is always English

Upvotes: 0

Richard Barat
Richard Barat

Reputation: 607

I had the same problem in .net core 2.2 i see in the debugger the properties SearchedLocation enter image description here

so, i created first the files Controllers.HomesController.rsx without language extension with access modifier "Public" to accces to the property enter image description here

and with localizer["Property] i found the goood value.

After i created the Controllers.HomeController.fr.resx and he found the good value with culture in url.

Upvotes: 7

kuken
kuken

Reputation: 59

For me it was a problem that the name of the project's folder was different than the root namespace! Core 3.0.

Upvotes: 2

Arulvel
Arulvel

Reputation: 79

By default, Visual studio IDE resolves the assembly references, but it requires the Microsoft.Extensions.Localization and Microsoft.Extensions.Localization.Abstractions NuGets. Once I added them to the project reference, the resource locator is able to find the resource files!

Upvotes: 3

Shervin Montajam
Shervin Montajam

Reputation: 118

You need to add these references from nuget:

Microsoft.Extensions.Localization

and also Localization.AspNetCore.TagHelpers can be a good tag helper instead of injecting the localization stuffs every time to the views

Upvotes: 2

user2389913
user2389913

Reputation: 288

I had similar problem. Than I figured out that the "Localization.AspNetCore.TagHelpers" nuget packag was missing from my project. It's look like it is a required package for the QueryStringRequestCultureProvider.

Upvotes: 29

Related Questions