7

I've been trying to implement localization for my asp .NET Core 1.0 RTM web app following microsofts documentation and I just can not get it to work. The problem I'm having is that it's always displaying strings from the english resource file no matter how I try setting the culture.

If anyone has 5 minutes of their time, I'd be really grateful for your input.

Here's my Startup.cs content that regards the localization:

public void ConfigureServices(IServiceCollection services)
{
  ...
  services.AddMvc()
    .AddViewLocalization(LanguageViewLocationExpanderFormat.SubFolder)
    .AddDataAnnotationsLocalization();
  services.AddScoped<LocalizationFilter>();
  services.AddLocalization(options => options.ResourcesPath = "Resources");

  var supportedCultures = new List<CultureInfo>{
     new CultureInfo("en-US"),
     new CultureInfo("sl-SI"),
     new CultureInfo("de-DE"),
     new CultureInfo("hr-HR")
  };
  services.Configure<RequestLocalizationOptions>(options =>
  {
     options.SupportedCultures = supportedCultures;
     options.SupportedUICultures = supportedCultures;
     options.DefaultRequestCulture = new RequestCulture(new CultureInfo("en-US"), 
        new CultureInfo("en-US"));
  });
}

public void Configure(IApplicationBuilder app, IHostingEnvironment env,
   ILoggerFactory loggerFactory)
{
      ...
      var supportedCultures = new List<CultureInfo>{
         new CultureInfo("en-US"),
         new CultureInfo("sl-SI"),
         new CultureInfo("de-DE"),
         new CultureInfo("hr-HR")
      };
      var requestLocalizationOptions = new RequestLocalizationOptions
      {
         SupportedCultures = supportedCultures,
         SupportedUICultures = supportedCultures,
         DefaultRequestCulture = new RequestCulture(new CultureInfo("en-US"), 
            new CultureInfo("en-US"))
       };
       app.UseRequestLocalization(requestLocalizationOptions);
}

And this is how I'm changing the culture inside OnActionExecuting in my ActionFilter

actionContext.HttpContext.Response.Cookies.Append(
    CookieRequestCultureProvider.DefaultCookieName,
    CookieRequestCultureProvider.MakeCookieValue(new RequestCulture(culture)),
    new CookieOptions { Expires = DateTimeOffset.UtcNow.AddYears(1) });
CultureInfo.CurrentCulture = culture;
CultureInfo.CurrentUICulture = culture;

I've also tried doing this on my controller with no luck.

Then in my views I'm using @inject IViewLocalizer Localizer to display localized strings with @Localizer["Name"].

My resoucres are located in the folder Resources/Views/ControllerName like so:

  • Resources/Views/ControllerName/ViewName.en.resx
  • Resources/Views/ControllerName/ViewName.sl.resx
  • ...

The displayed string is always from the .en resource file no matter how I try to thange the culture. Is there something I'm missing? Is there something more I'm supposed to do? It seems the problem I'm having is with setting the language. Based on the documentation you're just supposed to set the cookie with Response.Cookies.Append, but I've also tried with CultureInfo.CurrentCulture as Thread.CurrentThread.CurentCulture is not awailable anymore.

I really don't know what I'm missing. Any ideas at all?

Tseng
  • 52,202
  • 10
  • 166
  • 183
Biserka Zinreich
  • 209
  • 1
  • 10

3 Answers3

5

You are probably hitting the following : https://github.com/aspnet/Mvc/issues/4692

Mainly take a look at the comment: https://github.com/aspnet/Mvc/issues/4692#issuecomment-223671462

Summary: You can create a Resource filter in MVC to workaround the issue:

public class CultureSettingResourceFilter : IResourceFilter, IOrderedFilter
{
    public int Order
    {
        get
        {
            return int.MinValue;
        }
    }

    public void OnResourceExecuted(ResourceExecutedContext context)
    {
        // By this time the response would already have been started, so do not try to modify the response
    }

    public void OnResourceExecuting(ResourceExecutingContext context)
    {
        var culture = httpContext.GetRouteValue("your-culture-key-name")?.ToString();
        // set your culture here
        CultureInfo.CurrentCulture = culture;
        CultureInfo.CurrentUICulture = culture;
    }
}

services.AddMvc(o =>
{
    o.Filters.Add(new CultureSettingResourceFilter());
});
Kiran Challa
  • 53,599
  • 15
  • 167
  • 151
  • Thank you so much. Yes, my localization indeed starts working if I hardcode some localization in OnResourceExecuting. The problem I'm having with this now is getting the wanted culture. I'm trying to get the culture from the url like so http://localhost:5000/sl/otherStuff. Is there any way I can get it in OnResourceExecuting? – Biserka Zinreich Aug 09 '16 at 20:49
  • 1
    When using filters you will have access to current request's route data, so you can do `httpContext.GetRouteValue("culture-key-name")` (you would need to add `Microsoft.AspNetCore.Routing` namespace to see the `GetRouteValue` and `GetRouteData` extensions. – Kiran Challa Aug 09 '16 at 21:17
  • Thank you very much for your help. Now that I tested everything out, I confirm that it works. Thanks. – Biserka Zinreich Aug 11 '16 at 21:24
  • @KiranChalla I am trying the same thing, only difference is I am pulling resources from database and on login page I have dropdownlist from which I want to change the culture. So how can I do this ? – XamDev Aug 31 '16 at 07:21
1

I experimented with i18n and I got my translations to work when supported cultures matched with the cultures in resource file names

var supportedCultures = new List<CultureInfo>{
     new CultureInfo("en-US"),
     new CultureInfo("sl-SI"),
     new CultureInfo("de-DE"),
     new CultureInfo("hr-HR")
  };

Change your resource file names from

Resources/Views/ControllerName/ViewName.sl.resx

to specific language culture

Resources/Views/ControllerName/ViewName.sl-SI.resx

Siim Haas
  • 395
  • 1
  • 5
  • 13
1

Edit on @Siim Haas.
It's works good.
In my case: I using the LanguageViewLocationExpanderFormat.SubFolder

At ConfigureServices(IServiceCollection services)

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

    services.AddMvc()
        .AddViewLocalization(
            Microsoft.AspNetCore.Mvc.Razor.LanguageViewLocationExpanderFormat.SubFolder,
            opts => { opts.ResourcesPath = "Resources"; }
        )
        .AddDataAnnotationsLocalization();

    services.Configure<RequestLocalizationOptions>(opts =>
    {
        var supportedCultures = new[]
        {
            new CultureInfo("en-AU"),
            new CultureInfo("en-GB"),
            new CultureInfo("en-US"),
            new CultureInfo("en"),
            new CultureInfo("zh-cn"),
            new CultureInfo("zh"),
        };
        opts.DefaultRequestCulture = new Microsoft.AspNetCore.Localization.RequestCulture("en-US");
        opts.SupportedCultures = supportedCultures;
        opts.SupportedUICultures = supportedCultures;
    });
}

At Configure (IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)

public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
    app.UseRequestLocalization();

    app.UseMvc(routes =>
    {
        routes.MapRoute(name: "default", template: "{controller=Home}/{action=Index}");
    });
}

My Resources stucts Like:

{Your Project}/Resources/Views/{your controller}/ViewName.en-us.resx

Alex Zhang
  • 810
  • 9
  • 12