aspnet / Mvc

[Archived] ASP.NET Core MVC is a model view controller framework for building dynamic web sites with clean separation of concerns, including the merged MVC, Web API, and Web Pages w/ Razor. Project moved to https://github.com/aspnet/AspNetCore
Apache License 2.0
5.62k stars 2.14k forks source link

Support localization resources in a separate assembly #8739

Closed fabercs closed 5 years ago

fabercs commented 5 years ago

Is this a Bug or Feature request?:

It is a feature, but not sure if it exists or not

Description of the problem:

I am trying to move the localization resources(MyProject.Web.Resources) in MyProject.Web asp.net core mvc project to another separate MyProject.Resources project. I guess it is only doable for a shared resource, however, by doing this, I still want to make use of the IStringLocalizer work in my views and controllers. It seems it does not right now.

Version of Microsoft.AspNetCore.Mvc

mkArtakMSFT commented 5 years ago

Hi. It looks like this is a question about how to use ASP.NET Core. While we do our best to look through all the issues filed here, to get a faster response we suggest posting your questions to StackOverflow using the asp.net-core-mvc tag.

mkArtakMSFT commented 5 years ago

@ryanbrandenburg, can you please answer this question when you get time? Thanks!

hishamco commented 5 years ago

You can use ResourceLocationAttribute

fabercs commented 5 years ago

@mkArtakMSFT There is a post on this subject at stackoverflow, however there is not a real answer, check the link

@ryanbrandenburg , @hishamco I did lots of thing but I couldn't get it work. Is there any real world application that works like this way? I know resources and pages or classes follow namespace convention, but I couldn't understand how using an assemblyInfo solves this.

Here what I did;

Do we need any other configuration in Startup.cs?

And project structure is as follows;

|--MyProject.Infrastructure
|--MyProject.Core
|--MyProject.Web
    |--Controllers
    |--ViewModels
    |--Views
       |--Customer
          |--Index.cshtml
|--MyProject.Resources
    |--Resources
       |--Controllers
       |--ViewModels
       |--Views
          |--Customer
             |--Index.en-US.resx
             |--Index.tr-TR.resx
       |--SharedResource.cs
       |--SharedResource.en-US.resx
       |--SharedResource.tr-TR.resx   

SharedResources are the only working part in project right now btw. I suspect AssemblyInfo should be placed in Web project, maybe?

hishamco commented 5 years ago

SharedResources are the only working part in project right now btw. I suspect AssemblyInfo should be placed in Web project, maybe?

Nope, it should be on MyProject.Resources

@fabercs could you please share with us a minimal repo to reproduce your issue?

fabercs commented 5 years ago

@hishamco please find the minimal repo solution linked

hishamco commented 5 years ago

Sure, I will investigate on this ..

hishamco commented 5 years ago

I notice there 're many thing missing such as: Suffix views with culture code Index.tr-TR.resx, AddViewLocalization() extension method .. etc. Also there's a confusion on middleware order, please refer to Localization.StarterWeb

fabercs commented 5 years ago

I also realized about Suffix option missing middleware and commited it. I added AddMvcLocalization() instead AddViewLocalization(), it also covers the data annotation localization, anyway I changed it to AddViewLocalization(). So after these still no effects.

hishamco commented 5 years ago

Again AddLocalization() should become before AddMvc(), anyhow please make sure that your app reading the resources from within the same assembly, after that we will figure out what's the wrong with the separated assembly

fabercs commented 5 years ago

Ok, I have deleted the solution and added a new one with the Resources folder included in web project and localization works. The class library project also included, you can play with unload/reload.

https://github.com/fabercs/Issue8739

hishamco commented 5 years ago

@ryanbrandenburg how ViewLocalizer at this line https://github.com/aspnet/Mvc/blob/master/src/Microsoft.AspNetCore.Mvc.Localization/ViewLocalizer.cs#L110 will aware about the ResourceAttribute while we pass the view execution path as base name to the localizer factory?!!

fabercs commented 5 years ago

@hishamco, as IViewLocalizerFactory is derived from IStringLocalizerFactory, it calls the same Create logic of its base. However, for view localization, because of this line

https://github.com/aspnet/Mvc/blob/a2c8537dd86474a1cb5bb3ea12ada4ecabd6ee4c/src/Microsoft.AspNetCore.Mvc.Localization/ViewLocalizer.cs#L44

you always pass the executing assembly to the factory Create logic.

https://github.com/aspnet/Localization/blob/60a3d57a3e8b8b6d69232815a9596b5a495a7d0b/src/Microsoft.Extensions.Localization/ResourceManagerStringLocalizerFactory.cs#L181

So it crates the ResourceManager based on that assembly. I have it worked by implementing my own IViewLocalizer class and overriding _applicationName for now.

hishamco commented 5 years ago

There's no IViewLocalizerFactory!! the ViewLocalizer using IHtmlLocalizer which is construct from IHtmlLocalizerFactory

So it crates the ResourceManager based on that assembly. I have it worked by implementing my own IViewLocalizer class and overriding _applicationName for now.

Cool, but still I'm not sure why we need to subclass if the localizer aware about ResourceLocationAttribute, @ryanbrandenburg is there an easy way to achieve this without subclass ViewLocalizer?

fabercs commented 5 years ago

@hishamco my mistake, I just meant to IViewLocalizerFactory, however, at the end, all make use of IStringLocalizerFactory :)

https://github.com/aspnet/Mvc/blob/a2c8537dd86474a1cb5bb3ea12ada4ecabd6ee4c/src/Microsoft.AspNetCore.Mvc.Localization/HtmlLocalizerFactory.cs#L15

ryanbrandenburg commented 5 years ago

@fabercs it's unclear to me if you're sorted now. If you're sorted we'll close this out. If your not could you re-state your current problem?

fabercs commented 5 years ago

@ryanbrandenburg indeed I was expecting all will work properly when moving all my working (conventional) localization system from Web project to a separate project, however adding only a ResourceLocation attribute didn't do the trick. While keeping the ResourceLocation attribute, as I said above, I had to implement my own IViewLocalizer for views' localization. For data annotation localization, I had to quit namespace convention and create a shared resource which is working fine. If you say, that's what we meant to be done in our samples for localization, it is ok, you may close the issue. I have my all project localized.

ryanbrandenburg commented 5 years ago

For your ViewLocalizer issue refer to this issue. It boils down to this being an abstraction issue that would force us to make assumptions about the contents of a different assembly.

For your DataAnnotations issue, could you file a new issue (now against the aspnet/AspNetCore repo since we're moving everything) so that we can keep its context clean?