17

According to the documentation:

The runtime doesn’t look up localized strings for non-validation attributes. In the code above, “Email” (from [Display(Name = "Email")]) will not be localized.

I'm looking for a way to localize text in DisplayAttribute. Any suggestions to do it in a proper way(s)?

1
  • To concerned modern readers like me who happen to arrive here: this is not an issue in later versions of the framework. As Microsoft states, "In ASP.NET Core MVC 1.1.0 and higher, non-validation attributes are localized." Commented Oct 23, 2020 at 1:57

6 Answers 6

19

You can set the ResourceType on the DisplayAttribute which can be used to localize your text.

Add a resource .resx file to your project e.g. MyResources.resx, and add a resource for your field:

enter image description here

Then reference the name of the field and the MyResources type in your DisplayAttribute

[Display(Name = "RememberMe", ResourceType  = typeof(MyResources))]
public bool RememberMe { get; set; }

The localized resource will be pulled through automatically (see the text box)

enter image description here

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

4 Comments

It seems odd that non-validation attributes are not localized according to this new asp.net core localization mechanism. Do you think it is possible implement it for non-validation attributes too, or is there a reason that mvc guys skipped non-validation attributes?
I agree, it is a bit odd! I assume there must be a reason why they decided not to but I'm not sure off the top of my head. You could always ask on GitHub and see what they say.
I'm getting The type or namespace 'MyResources' could not be found. What am I missing?
Hello, I'm using .NET Core 1.0.0 and this implementation throws the following error: InvalidOperationException: Cannot retrieve property 'Name' because localization failed. Type '<full_typename>' is not public or does not contain a public static string property with the name 'RememberMe'. Does anybody have any experience with this error?
11

Having a Central location for all your localization whether in view or dataannotations is the best approach I can think of, and this how I got to work. In Startup.cs file after you installed nuget packages for localization add the following code

services.AddMvc().AddViewLocalization().AddDataAnnotationsLocalization(options => 
    options.DataAnnotationLocalizerProvider = (type, factory) => new StringLocalizer<Resources>(factory));

services.Configure<RequestLocalizationOptions>(options => {
   var cultures = new[]
   {
       new CultureInfo("en"),
       new CultureInfo("ar")
   };
   options.DefaultRequestCulture = new RequestCulture("en", "en");
   options.SupportedCultures = cultures;
   options.SupportedUICultures = cultures;
});

This way the DataAnnotationLocalizerProvider will be from the Resources.{culture}.rex -( The Resource file must have an access modifier of No code gen)- assuming that no resources will be needed for the default language, and to be able to access the resource file since no code will be generated and empty class with the same name must be created.

and in _ViewImports.cshtml file inject the following

@inject IHtmlLocalizer<Resources> Localizer

by doing this you now have a global variable Localizer to be used in any of the views for localization purposes.

This is how a Central Location for String Localization

you can find further information on Globalization and localization in ASP.NET Core

Comments

7

For those who struggle (@lucius, @vladislav) with error:

Cannot retrieve property 'Name' because localization failed. Type 'Xxxx.EmployeeResx' is not public or does not contain a public static string property with the name 'FirstName'.

It is caused by access modifier on .resx files which is by default set to Internal (in my case it was No code generation). Change it to public in Access Modifier dropdown in the resource file toolbar.

[https://i.imgur.com/q3BK8T5.png]

After that you should be able to see the properties from the resource type:

enter image description here

Also, consider not using special signs in field names as they are a basis for auto-generated C# property names. The field names are converted into C# friendly names and that is why you can end up with inconsistency between name of resource file field and name of auto-generated property. Best to avoid any hyphens - or dots . Underscores _ are fine. You can always look up how the auto-generated properties look like in resource_file_name.Designer.cs class under the related resource file.

enter image description here

Many thanks to Bala Murugan who wrote a good article concerning this topic on Code Digest.

Comments

3

Actually I found an simple solution for the followers. The display name in most of time is used in the label of an input field. So do this if you like:

<label asp-for="Email">@Localizer["Email"]</label>

of course, you can pass the property name by @Html.DisplayNameFor, but most of time, this one already works well.

3 Comments

Works as expected, thanks.. after many hours spend, i see your answer and it works like a charm !!
I'm looking for similar solution for even declaring Display. Because most of the time, the property name is display name, we should be able to declare <code> [Display] [EmailAddress] public string Email { get; set; } </code> This should automatically use the property name 'Email' to translate
The problem with this approach is that validation attributes cannot pick up and translate the field name. Add the [Required] attribute to your model property and its default message "{0} is required." fills in the technical name of the field rather than the translated name of the field.
2

I have just created a project which demonstrates localization including localization of Display attribute for class properties as well as enums.

The project can be found here https://github.com/feradz/ASPNetCoreLocalization/wiki

The Display attribute has to be localized using the approach prior to ASP.NET Core 1.0. Have a look at the DataAnnotations.resx file in the project.

The Name property of Display cannot contain empty spaces, and special characters.

[Display(Name = "NoSpacesAndSpecialChanractersHere", ResourceType = typeof(Resources.DataAnnotations))]
public string FirstName { get; set; }

ResourceType should be the fully qualified resource class name (i.e. including the name space).

1 Comment

After spending hundreds of hours, your solution help me a lot. The only thing I wanted to mention here is, I must have to create props in my SharedResources. Like public class SharedResource { public static string FieldEmail { get; set; } } And this use in model like public class LoginDTO { [Display(Name = "FieldEmail")] public required string Email { get; set; } } And create Localized value like SharedResources.en-US.resx FieldEmail = "Email" SharedResources.gu-IN.resx FieldEmail = "ઈમેઇલ" Hope this should help who is not getting any help from ChatGPT :)
1

In my asp.net core 7 Razor projects, I add this in program.cs to have Display attrib localized automatically:

builder.Services.AddMvc()
derFormat.Suffix)
.AddViewLocalization()
.AddDataAnnotationsLocalization(options =>
{
    options.DataAnnotationLocalizerProvider = (type, factory) =>
    {
        var assemblyName = new AssemblyName(typeof(SharedResource).GetTypeInfo().Assembly.FullName);
        return factory.Create("SharedResource", assemblyName.Name);
    };
});


[Display(Name = "RememberMe_QuestionMark")]
public bool RememberMe { get; set; }

1 Comment

This one worked for me in .NET 7.0. Had to use reflection like this to get it to work In my case, as we did some refactoring of code and moved Models to a different project (e.g. MyProject.Core), which resulted in Resources.resx files situated in MyProject.Presentation project would not be "connected". Previous code: options.DataAnnotationLocalizerProvider = (_, factory) => factory.Create(typeof(SharedResouce));

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.