3

I wonder if there is possibility to use IHtmlLocalizer from ASP.NET MVC6 directly with POCO classes? Currently I have few viewmodels that uses DisplayAttribute in order to display translated string in views and validator, but it requires to create additional static class with each static property defined (unfortunately the static indexers are not possible in C#). Is there any better way to get this done?

My current code:

[Display(Name = "TrackingDevice", ResourceType = typeof(TestResource))]
public string TrackingDevice { get; set; }

public class TestResource
{
    public static string TrackingDevice
    {
        get
        {
            //Here I call IHtmlLocalizer via IServiceLocator
            return "Field name";
        }
    }
}
4
  • You must take a look to this article: USING DATAANNOTATIONS AND LOCALIZATION IN ASP.NET 5 MVC 6 annotatiohttp://damienbod.com/2015/10/24/using-dataannotations-and-localization-in-asp-net-5-mvc-6/ Commented Nov 1, 2015 at 16:35
  • This example does not work for me on MVC Web application. Commented Feb 21, 2016 at 20:43
  • I have the same problem. I decided don't use DisplayAttribute. And I provide localization for label in View. Example: <label asp-for="DisplayName" class="col-md-2 control-label">@LocString["DisplayName"]</label> . Do not forget to inject LocString: @inject IViewLocalizer LocString Commented Feb 28, 2016 at 16:36
  • did you find my answer acceptable for you? Commented Oct 16, 2018 at 21:21

4 Answers 4

1

I have struggled a bit and finally succeeded in compiling a working solution to this question. Thanks to @Szymon Sasin for his answer, although it is not working against the latest version and his configuration is partial, it helped me build this solution.

First, configure localization at Startup.cs:

public class Startup
{
    public void ConfigureServices(IServiceCollection services)
    {
        //...
        services.AddLocalization(options => options.ResourcesPath = "Resources");
        services
            .AddMvc(mvcOptions =>
            {
                IServiceProvider provider = services.BuildServiceProvider();
                IStringLocalizer localizer = provider.GetService<IStringLocalizer<DisplayResources>>();
                mvcOptions.ModelMetadataDetailsProviders.Add(new DisplayAttributeLocalizationProvider(localizer));
            });
        //...
    }
}

Second, verify your folder structure against the configured ResourcePath. The important thing here is that the path to the custom resource type and the path to its resx files should be relative. Example:

<root_proj_dir>/Resources/Resources_Common/DisplayResources.en.resx
<root_proj_dir>/Resources/Resources_Common/DisplayResources.bg.resx
<root_proj_dir>/Resources_Common/DisplayResources.cs

Third, define your custom metadata provider:

public sealed class DisplayAttributeLocalizationProvider : IDisplayMetadataProvider
{
    private IStringLocalizer _localizer;

    public DisplayAttributeLocalizationProvider(IStringLocalizer localizer)
    {
        _localizer = localizer;
    }

    public void CreateDisplayMetadata(DisplayMetadataProviderContext context)
    {
        context.PropertyAttributes?
            .Where(attribute => attribute is DisplayAttribute)
            .Cast<DisplayAttribute>().ToList().ForEach(display =>
            {
                display.Name = _localizer[display.Name].Value;
            });
    }
}

Fourth, use all this in your view model just like this:

public class SomeViewModel
{
    [Display(Name = "Email")]
    public string Email { get; set; }
}

The "Email" value will be the key to look-up for in the DisplayResources.xx.resx files.

Hope that many others will find this info helpful!

Sign up to request clarification or add additional context in comments.

4 Comments

I just found out that this solution has a bug. The display attributes are initialized only once, then if the culture is changed their values are not changed. However, there is not an obvious fix for now... looking for it
Thank you very much. It seems OK, except that I don't find the solution to the bug I described above?
With some adjustments, workz like a charm. Thank you for this example.
Any indication what the "adjustments" are? It would be a really elegant solution if it didn't lock translations to the first locale requested when the app pool is initialized...
0

First of all in the latest version of ASP.NET 5 beta8 you can find new features and the newest one is localisation in DataAnnotations.

1.Enable it in your Setup class

services.AddMvc()  
   .AddViewLocalization()  
   .AddDataAnnotationsLocalization();

2.Mark your model with appropriate configured data annotation

using System.ComponentModel.DataAnnotations;
using AspNet5Localization.Resources;

namespace AspNet5Localization.Model
{
    public class Box
    {
        public long Id { get; set; }

        public double Height { get; set; }

        public double Width { get; set; }

        [Required(ErrorMessageResourceName = "BoxLengthRequired", ErrorMessageResourceType = typeof(AmazingResource))]
        [Range(1.0, 100.0, ErrorMessageResourceName = "BoxLengthRange", ErrorMessageResourceType = typeof(AmazingResource))]
        public double Length { get; set; }
    }
}

Data annotation example:

[Required(ErrorMessageResourceName = "SomeResourcePropertyName", ErrorMessageResourceType = typeof(SomeResourceType))]

3 Comments

Thank you, but what about Display attribute? I want to have translated field name in label rendered in view. Current aproach requires me to create Resource which is not supported in VS2015. Any ideas?
@Andrii Tsok, according to the ASP.NET documentation DisplayAttribute is not part of DataAnnotation localization, so your answer does not seem to be related to the question. See here: docs.asp.net/en/latest/fundamentals/…
Look at my response, this is a way to translate DisplayAttributes.
0

ASP.NET Core 1.0 does not support out-of-the-box localization based on the new introduced localization approach for the Display attribute. One way to go is to use the prior to ASP.NET Core 1.0 approach for localization with resource files. I have implemented a simple demo project which shows how to localize the display attribute here https://github.com/feradz/ASPNetCoreLocalization/wiki DataAnnotations.resx is used for localizing the Display attribute.

Comments

0

try to use something like that:

public sealed class DisplayAttributeLocalisationProvider : IDisplayMetadataProvider {
    private IHtmlLocalizer localiser;

    public DisplayAttributeLocalisationProvider(IHtmlLocalizer localiser) {
        this.localiser = localiser;
    }

    public void CreateDisplayMetadata(DisplayMetadataProviderContext context)
        => context
            .PropertyAttributes
            .Where(attribute => attribute is DisplayAttribute)
            .Cast<DisplayAttribute>()
            .ToList()
            .ForEach(x =>
                x.Name = this
                    .localiser
                    .Html(x?.Name)
                    .Value);

To add it to configuration use:

private void ConfigureMvcOptions(MvcOptions options)
    {
        options
            .ModelMetadataDetailsProviders
                .Add(new DisplayAttributeLocalisationProvider(this.localiser));

I am not sure how it will work with an errors but works fine with DisplayAttributes

Edited: updated to MVC6

2 Comments

In the current version of .Net Core (1.0.0) the GetDisplayMetadata seems to have been renamed to CreateDisplayMetadata. Also, the ExecuteAction is not defined for IEnumerable<DisplayAttribute>. Do you have a more up-to-date example?
The configuration method is only run once per application lifecycle, so in a multi-lingual application the attributes will be translated into the language of the first client to connect, and stay that way for all clients until the app pool is recycled.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.