17

I am trying to migrate my existing ASP.NET MVC 5 project to MVC 6 vNext project , while I have been able to get through and resolve most of the issues , I cant seem to find any documentation on how to use the RESX resource files for localization in MVC 6

My ViewModels are using statements like

 [Required(ErrorMessageResourceType = typeof(Resources.MyProj.Messages), ErrorMessageResourceName = "FieldRequired")]

This worked fine in MVC 5 as long as the RESX was included properly and the access modifiers were set correctly , but it doesnt seem to work in a vNext project Does anyone know how RESX can be used in MVC 6 vNext projects ?

I saw a few posts here and on the GIT hub site which say that the localization story for ASP.NET 5 / MVC 6 is complete but I cant find any decent sample where the resource strings have been used.

Using the code above gives me a error

Error CS0246 The type or namespace name 'Resources' could not be found (are you missing a using directive or an assembly reference?)

Edit : Changed text to clarify that I am looking for implementation of localization in vNext ( MVC 6 )projects , I am able to make it work in MVC 5.

Edit 2 : Got the localization bit working after implementing the answer from Mohammed but I am stuck at a new error now.

Once I Include

  "Microsoft.AspNet.Localization": "1.0.0-beta7-10364",
    "Microsoft.Framework.Localization": "1.0.0-beta7-10364",

packages and add the following line in ConfigureServices in the Startup.cs

   services.AddMvcLocalization();

I get a new error when the following code is getting executed.

  public class HomeController : Controller
    {
        private readonly IHtmlLocalizer _localizer;

        public HomeController(IHtmlLocalizer<HomeController> localizer)
        {
            _localizer = localizer;
        }
          ....

Error :

An unhandled exception occurred while processing the request.

InvalidOperationException: Unable to resolve service for type 'Microsoft.Framework.Runtime.IApplicationEnvironment' while attempting to activate 'Microsoft.Framework.Localization.ResourceManagerStringLocalizerFactory'. Microsoft.Framework.DependencyInjection.ServiceLookup.Service.CreateCallSite(ServiceProvider provider, ISet`1 callSiteChain)

Cant figure out if its a dependency i am missing or there is a issue in the code

Edit 3 :

To anyone still looking for a solution. At this point in time , you can use the code in the answer by Muhammad Rehan Saee to get localization support in your CSHTML. However the story for enabling localization in validation attributes is not yet done( at the time of this edit : 08/Sep/2015) Have a look at the issue on the GITHUB site for mvc below :

https://github.com/aspnet/Mvc/issues/2766#issuecomment-137192942

PS : To fix the InvalidOperationException I did the following

Taking all dependencies as the beta7-* and clearing all the contents of my C:\Users\.dnx\packages got rid of the error.

Details on the issue I raised :

https://github.com/aspnet/Mvc/issues/2893#issuecomment-127164729

Edit : 25 / Dec /2015

This is finally working in MVC 6 now.

Wrote a quick blog post here : http://pratikvasani.github.io/archive/2015/12/25/MVC-6-localization-how-to/

Pratik
  • 868
  • 1
  • 9
  • 24
  • 1
    @Coulton : I am able to use RESX in my existing MVC 5 project like you mentioned in the link above , my problem is that doesnt work in MVC 6 with the new vNext projects . I am looking for a way to work with the existing Resx files in MVC 6 – Pratik Jul 30 '15 at 10:39

2 Answers2

4

You can take a look at a full sample on the ASP.NET MVC GitHub project here. At the time of writing this is all very new code and subject to change. You need to add the following into your startup:

public class Startup
{
    // Set up application services
    public void ConfigureServices(IServiceCollection services)
    {
        // Add MVC services to the services container
        services.AddMvc();
        services.AddMvcLocalization();

        // Adding TestStringLocalizerFactory since ResourceStringLocalizerFactory uses ResourceManager. DNX does
        // not support getting non-enu resources from ResourceManager yet.
        services.AddSingleton<IStringLocalizerFactory, TestStringLocalizerFactory>();
    }

    public void Configure(IApplicationBuilder app)
    {
        app.UseCultureReplacer();

        app.UseRequestLocalization();

        // Add MVC to the request pipeline
        app.UseMvcWithDefaultRoute();
    }
}

The IStringLocalizerFactory seems to be used to create instances of IStringLocalizer from resx types. You can then use the IStringLocalizer to get your localized strings. Here is the full interface (LocalizedString is just a name value pair):

/// <summary>
/// Represents a service that provides localized strings.
/// </summary>
public interface IStringLocalizer
{
    /// <summary>
    /// Gets the string resource with the given name.
    /// </summary>
    /// <param name="name">The name of the string resource.</param>
    /// <returns>The string resource as a <see cref="LocalizedString"/>.</returns>
    LocalizedString this[string name] { get; }

    /// <summary>
    /// Gets the string resource with the given name and formatted with the supplied arguments.
    /// </summary>
    /// <param name="name">The name of the string resource.</param>
    /// <param name="arguments">The values to format the string with.</param>
    /// <returns>The formatted string resource as a <see cref="LocalizedString"/>.</returns>
    LocalizedString this[string name, params object[] arguments] { get; }

    /// <summary>
    /// Gets all string resources.
    /// </summary>
    /// <param name="includeAncestorCultures">
    /// A <see cref="System.Boolean"/> indicating whether to include
    /// strings from ancestor cultures.
    /// </param>
    /// <returns>The strings.</returns>
    IEnumerable<LocalizedString> GetAllStrings(bool includeAncestorCultures);

    /// <summary>
    /// Creates a new <see cref="ResourceManagerStringLocalizer"/> for a specific <see cref="CultureInfo"/>.
    /// </summary>
    /// <param name="culture">The <see cref="CultureInfo"/> to use.</param>
    /// <returns>A culture-specific <see cref="IStringLocalizer"/>.</returns>
    IStringLocalizer WithCulture(CultureInfo culture);
}

Finally you can inject the IStringLocalizer into your Controller like so (Note that IHtmlLocalizer<HomeController> inherits from IStringLocalizer):

public class HomeController : Controller
{
    private readonly IHtmlLocalizer _localizer;

    public HomeController(IHtmlLocalizer<HomeController> localizer)
    {
        _localizer = localizer;
    }

    public IActionResult Index()
    {
        return View();
    }

    public IActionResult Locpage()
    {
        ViewData["Message"] = _localizer["Learn More"];
        return View();
    }
}
Muhammad Rehan Saeed
  • 35,627
  • 39
  • 202
  • 311
  • 1
    Thanks for the info , i now understand what they are trying to do with resource handling , unfortunately I have run into another issue . It seems the packages have conflicts in them As soon as I add "Microsoft.Framework.Localization": "1.0.0-beta7-10364", as a dependency , i start to get the error : **Method not found: 'Boolean Microsoft.Framework.DependencyInjection.ServiceCollectionExtensions.TryAdd** Any chance you have seen this error before ? – Pratik Jul 30 '15 at 13:03
  • Are you using all Beta 7 bits? I must admit, I have not had a chance to try the localization bits yet. – Muhammad Rehan Saeed Jul 30 '15 at 13:04
  • 1
    I am using beta7 where I can . Actually i also tried with the beta5 version of Microsoft.Framework.Localization. That doesnt seem to work either :( Its surprising how so many basic features are missing with MVC 6. I was hoping they would have flushed out some of this before the RTM – Pratik Jul 30 '15 at 13:16
  • 1
    It's best to stick to one version of all packages. I think Localization was introduced in Beta 6 or 7. MVC 6 will be complete in November, still a long way to go. – Muhammad Rehan Saeed Jul 30 '15 at 13:29
  • 1
    is there any update on this? I thought localization was supposed to be ready in beta7 which is now released but it still seems very lacking. also vs2015 doesn't have an option to add .resx files even with the latest tooling update. I want to be able to use a class library for resx files and to be able to reference those from controllers as well as from within views using syntax like @MyResources.FooLabel in razor. Is that going to be possible? When will localization really be ready to use? – Joe Audette Sep 06 '15 at 18:08
  • @JoeAudette Yes I believe you are right. I've only just upgraded and will take a deeper look soon. I will be adding localization to [ASP.NET MVC Boilerplate](https://visualstudiogallery.msdn.microsoft.com/6cf50a48-fc1e-4eaf-9e82-0b2a6705ca7d) eventually. – Muhammad Rehan Saeed Sep 06 '15 at 19:36
  • @JoeAudette It doesn't seem ready yet. The comment in [this](https://github.com/aspnet/Mvc/blob/dev/test/WebSites/LocalizationWebSite/Startup.cs) sample still says `DNX does not support getting non-enu resources from ResourceManager yet.`. Also the localization [package](https://github.com/aspnet/Mvc/tree/dev/src/Microsoft.AspNet.Mvc.Localization) has not been updated often. – Muhammad Rehan Saeed Sep 07 '15 at 15:11
  • 1
    @JoeAudette : The localization stories are still being done. while now you can compile the localization resources as mentioned by Muhammad but you still cant use the localization strings in the validation attributes . Have a look at this https://github.com/aspnet/Mvc/issues/2766#issuecomment-137192942 – Pratik Sep 08 '15 at 13:40
3

Things have been changed in mvc 6.0.0-rc1-final. After going through many other forums, below configuration will work if anyone planning to work with latest changes in localization feature.

In startup.cs configure

public void ConfigureServices(IServiceCollection services)
    {           
        services.AddMvc();           
        services.AddMvc().AddViewLocalization().AddDataAnnotationsLocalization();
        services.AddSingleton<IStringLocalizerFactory, CustomStringLocalizerFactory>();
    }

    public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
    {           
        var requestLocalizationOptions = new RequestLocalizationOptions
        {                
            SupportedCultures = new List<CultureInfo>{
                new CultureInfo("en-US"),    
                new CultureInfo("fr-CH")
            },
            SupportedUICultures = new List<CultureInfo>
            {
                new CultureInfo("en-US"),                    
                new CultureInfo("fr-CH")                    
            }
        };
        app.UseRequestLocalization(requestLocalizationOptions, new RequestCulture(new CultureInfo("en-US")));           
    }

and you can start using IHtmlLocalizer in controller.

and you can test with querystring http://localhost:5000/Home/Contact?culture=fr-CH or change the culture in chrome by adding preferred language under "Language and Input Setting"

Pylyp Lebediev
  • 1,991
  • 4
  • 26
  • 44
Nishank
  • 159
  • 1
  • 11
  • 4
    Why posting incomplete code? Since when skipping a `CustomStringLocalizerFactory` is considered to be unrelevant? – Cristian E. Jan 01 '16 at 20:09