Runtime: Provide localization for default error messages in System.ComponentModel.Annotations

Created on 8 Nov 2017  Â·  37Comments  Â·  Source: dotnet/runtime

Currently, using attributes like [Required] or [Range(1, 20)] in ASP.NET Core only gives you english error messages, no matter what culture you set. That is because .NET Core currently only has one (english) resource file. In this issue , @ryanbrandenburg suggested to create a issue here instead of aspnet/Localization to see if this could get resolved, so this is what I'm doing.

I wish I could just write, for example, [Required] and get localized error messages, without the need to write [Required(ErrorMessage = "bla bla bla")] all the time, or creating a lot of resource files, or creating a single big resource file for _every_ annotation... All of these options introduce a lot of hassle for anyone developing applications in any language other than english. It's especially frustrating when all the Annotations you use are the default ones.

area-System.ComponentModel.DataAnnotations enhancement

Most helpful comment

@ajcvickers Do you have any update on that matter? It seems to effectively be a special case here, but an important one IMO. The validation messages are always (almost) displayed to the end users, not being able to provide localized ones is kind of a road blocker here.

Sure there are other options such as inheriting the attribute and customizing the error message, but it's not as clean and efficient.

All 37 comments

@krwq @tarekgh do you have any advice from general .NET Core localization point of view?

@karelz I believe the request here is to get the net core assemblies localized. neither me nor @krwq familiar or owning that. would be better to get the owner take a look.

CC @danmosemsft as he was involved in similar discussions before.

@tarekgh does it mean .NET Core assemblies are not localized at all? (that would be a bit surprising to me)

I don't think we localize the net core assemblies. I believe the exception is Microsoft.CSharp dotnet/corefx#2713

@karelz @danmosemsft I don't think there is anything to do here from the area owner perspective. If the assembly resources are localized as part of a wider effort, then this would just start working. Beyond that I don't think we will do anything special to make this happen. Is there a general issue tracking this localization--#2713 seems to be specifically about Microsoft.CSharp.

@ajcvickers There is no plan for BCL-wide localization. Most texts don't need it as they are not exposed to end-customers (e.g. exception texts, etc.).
System.ComponentModel.Annotations and Microsoft.CSharp are likely the only exceptions to that rule.

If you think it is valuable scenario for developers to enable localization of Annotations, then we should start the discussion how to make it happen.

Thanks @karelz. I agree with not localizing in general--I'm very happy that we have got there. However, maybe data annotations is special since these messages are intended for customers. I will talk to @divega about it.

@ajcvickers Do you have any update on that matter? It seems to effectively be a special case here, but an important one IMO. The validation messages are always (almost) displayed to the end users, not being able to provide localized ones is kind of a road blocker here.

Sure there are other options such as inheriting the attribute and customizing the error message, but it's not as clean and efficient.

cc: @terrajobst

It's too painful that I cannot localize the Required, EmailAddress etc annotations in the global scope. The validation messages are displayed to customer directly. How these going on?

@cycbluesky We discussed this again recently and at least for now we're not going to do localization here. Localization of the default strings only helps those using the default strings, and it is common to instead use custom strings that are more domain-specific and therefore more helpful.

We are not sure how feasible it is, but we would consider a PR that brings existing localized strings for data annotations from .NET Framework to .NET Core, in a similar fashion to how https://github.com/dotnet/corefx/pull/2713 did it for Microsoft.CSharp.

I believe those translations are not available as reference source, but if there is anyone willing to try this we can figure out next steps.

@ajcvickers It is not common to use custom strings. For basic things like Field xxx is required the message is evident enough. And in most cases is used just as is. So for all the people not living in English speaking nations or working on multilanguage products there should be an option for translation. I am actually sad to see issues dating back 2 years to fix this and nothing has been done in this time.

@divega Whatever you do please make that behaviour optional. Translating technical messages like exceptions or model validation errors is awful for developers that have to support users across the globe and prefer analysing error logs without Hungarian or Chinese messages intermixed.

A good UI shouldn't show these messages to the user anyhow.

@divega Whatever you do please make that behaviour optional. Translating technical messages like exceptions or model validation errors is awful for developers that have to support users across the globe and prefer analysing error logs without Hungarian or Chinese messages intermixed.

A good UI shouldn't show these messages to the user anyhow.

Well, apparently that has already begun. I was the one to open this issue and I hope I haven't created a monster. As @os1r1s110 said:

The validation messages are always (almost) displayed to the end users, not being able to provide localized ones is kind of a road blocker here.

And that is true.

However, I've noticed that since ASP.NET Core 2.2, kestrel messages seems to be translated as well (they appear translated on the console when debugging), which is _awful_.

Let's be very clear here: validation messages which are displayed to the final UI being translated is one thing; logging, exception and just _everything else_ is another thing entirely. In fact, I think that if you keep going on this route, you should not only make it optional, but more specifically make it _opt in_.

Translated technical messages never really help no one. Even beginners. In fact, I think it may make their life harder, since obviously there's _way_ more content in English than any other language. When I started programming, I always had to first search for the exception message in english and _then_ search about the exception itself. It's not a very pleasant experience. There _are_ times when two exceptions had similar texts and I ended up losing time just searching for their english equivalent. And no, it's not just as easy as translating back, because of course a sentence can be translated in various different ways. And to make it worse, much of the time the messages aren't simply translated - they're localized, which makes it even harder to translate back.

Some people want translated exceptions because they _do_ want to show them to users. For example, many MSBuild messages contain verbatim .NET exception strings. Something like "The Copy task failed. {0}" where "{0}" is something like "Could not copy file 'abc'. File not found". In that situation they want the whole string translated or not at all. It is not easy to supply their own messages, because firstly there are many many possible messages, and secondly the .NET exceptions often provide key information only in the message string- for example, the file path. This will help a little, and only for IO.

Anyway - that is a much broader conversation - and at this time there is no effort planned to localize messages as we did in .NET Framework. I just wanted to point out that it is a valid debate to have.

Yea, sure, I think that saying they help _no one_ was an exaggeration.

I do completely agree that it is a valid debate though; all I said is that I think it should be _opt in_. I really think english messages helps way more people than translated ones do.

I think it would be nice if this could be done programmatically - like through an API to get the translated message from a specific Culture. I didn't give much thought to this though and I don't how feasible is that.

@danmosemsft Having one global issue where we could voice concerns about localising developer facing strings would be great.

Because as seen here if someone provided a PR with translations there's a good chance this would be included without bigger input by the community.

If people have valid use cases for translating these messages I'm certainly not against it. But as someone who has to deal with translated exception messages when analysing bugs I want a programmatic, offline ability to get the English exception messages or model validation errors. The full framework approach simply doesn't work very well for those of us that have global user bases.

Considering that virtually no other language translates their exceptions should also hint that the value of doing so is far from universally recognised.

@danstur I hear you. Feel free to open such an issue if there isn't one. As mentioned above we aren't doing anything here for 3.0, at least

@danstur @danmosemsft Note that this issue is not about localization of general exception messages from this code. This is instead specifically about providing localization for the error messages that come from the validation system, such as "'Foo' is a required value.". The way validation works makes it much more likely that these will be exposed to a non-technical end-user than is the case for more framework exception messages.

I am actually strongly opposed to localization of exception messages in general, for basically the same reason as @danstur states. The first thing many developers do with a message is google for it. Localized exception messages are horrible for that, so localizing the messages makes things more difficult for developers, which is their primary reason for existence.

This is instead specifically about providing localization for the error messages that come from the validation system, such as "'Foo' is a required value.".

That's why I suggested a new issue 😺

At a wild guess, if we ever decided it was important to offer localized exception messages (and again there is no plan), we would offer some way to opt-in or out. That's just a guess.

@ajcvickers is that a good choice to unseal some validation attribute class such as EmailAddress?
Give users the opportunity to localize the messages.

@cycbluesky We aren't going to unseal attributes, as explained on the other issue you were commenting on.

@ajcvickers Oh I understand that it's not about general exceptions, but about the model validation messages (although I should've been clearer on this in my second post!)

But I find the same still applies to a lesser degree: Is it really useful to show the user "'Foo.Bar[0]' is a required value"? For most the message will be way too technical and since such a message is caused by a programming error it's not as if the user could do much about it either. I don't think I've ever seen a full framework ASP.NET UI that displayed these messages intentionally to their user as part of the UI.

But then that's just my own experience and I'm sure lots of people will disagree. Would still be nice to have the option to opt-out. Although given the limited number of model validation annotations, it's not that big a deal anyhow.

It really makes big sense to allow Data annotations messages to be localized.
Honestly, what is the purpose to create an error handling layer for "validation messages" while there's already a validation layer on classes ?

When I write this

[Required]
public string Name { get; set; }

It is expected that the validation message is poped up for the user with localization.

In my opinion most answers are from a very ignorant and arrogant point of view. "America first", so it is enough that validation messages are in english, who cares for the rest of the world?
Is it really that difficult to specify a different resource file? Like ".AddDataAnnotationsLocalization(loc => loc.UseThisFile(...))". All messages are already inside a resource file, so it should be easy to replace it during runtime.

At a wild guess, if we ever decided it was important to offer localized exception messages (and again there is no plan), we would offer some way to opt-in or out. That's just a guess.

@danmosemsft Today I saw a SockectException thrown due to cancellation that had its message localized:

System.Threading.Tasks.TaskCanceledException: The operation was canceled. ---> System.IO.IOException: Unable to read data from the transport connection: A operação de E/S foi anulada devido a uma saída de thread ou a uma requisição de aplicativo. ---> System.Net.Sockets.SocketException: A operação de E/S foi anulada devido a uma saída de thread ou a uma requisição de aplicativo

Repro code:

var x = new HttpClient() {  Timeout = new TimeSpan(0,0,5) };
try
{
    // some endpoint that takes more than 5s to answer
    // note that setting the timeout too low (something like 200ms)
    // changes the exception that is thrown, but I'm not sure why
    await x.GetAsync("http://localhost:45789");
}
catch (Exception ex)
{
    Console.WriteLine(ex);
}

Is this being done now? I would really hope not. I find it weird though that only the SocketException really seems to be localized. The parent IOException seems to be only copying its message. Does that exception gets some special handling (no pun intended 😛 )?

@danstur Did you ever open that issue? If not, I'll be creating one to track this.

@andre-ss6

Today I saw a SockectException thrown due to cancellation that had its message localized:

My guess is that the localized part came from the OS, eg., on Windows that would be from FormatMessage or similar in Unix. We include those strings in the exception string when the OS has given us an error code that we don't specifically specially have a string for.

[edit] Yes this is Windows - ERROR_OPERATION_ABORTED 995

In such cases, I hope the developer doing diagnostics has the "ToString()" output of whatever the exception is, and that should include the error number or HResult of the exception (995 here), which gives all the information in that string since it's what we used to get it.

Hello,

I tried many things in order to translate common validation messages and finnaly I got a good solution (which is working in Dot.Net Core 2.2 and 3).
I want to share my solution. Addittionally I want that any one check my code if I broke any internals or doing bad things by mistake.

I forked the official ASPNetCore Movie project and added my solution on branch localize-dataannotations.

Commit #2fd8907 was my first try which I used the solution from @audacity76 (see: https://github.com/aspnet/Localization/issues/286#issuecomment-257828296 ).

But that was the wrong way because Internal components (from MS) was used. In Dot.Net 3 the code is no longer working because the adapter class's are sealed and cannot be inherited.

With commit #ee12381 and #238bfe1 I found a solution wich works.

There I deleted the class's which has been inherited from the sealed one's (LocalizedRequiredAttributeAdapter and LocalizedStringLengthAttributeAdapter).

For debugging I used the form "~/Movies/Edit/1" and the field "Genre".


By the way I want to explain why I have to avoid the recommended workaround by manually touch each attribute and set the resource key + file in each attribute.

We want to build a new plattform for internal applications. The new framework should be an improvement of the current one. One of the most important requirements is a very good maintainability.

My current role is to survey the Dot.Net Core environment for this purposes. I'm a big fan of C# and Dot.Net Core but other in the team have doubts.

Now my problem is that I cannot go to my collegues and tell them that we should use Dot.Net Core when basic things like localization of validation messages are not working in an easy way. They will (and have already) ask me why MS did not add localization in version 3.0. I cannot explain it too.

The recommended workaround from you is not good because our most important requirement "maintainability" is decreased a lot. On the top it will increase mistakes by careless.
Models which are generated and decoreated with dataannotations (like from the ef-core scaffold) must be touched manually.

I realy want to use DotNetCore. So an easy to use solution is high priority.

Just for the record, this breaks the validation story of UI frameworks like WPF and WinForms, which rely on the exception messages to be readable to the end user.

That's a fair point. FYI: We're probably localizing the BCL.

FYI: We're probably localizing the BCL.

@terrajobst So the exceptions are going to be localized in the end? :( Are there any plans to do something like what was suggested here? Maybe programmatic or opt-in/out?

We have no plans to add additional functionality to data annotations.

@ajcvickers So basically, the built-in validation attributes are useless. Don't use them! Ever! Instead, create your own attributes that provide a decent feature set, like localisation of the messages. Either do it in your own project or build, share and use a NuGet package that replaces the entirely broken validation attributes. They're just wasted space in a project deployment. I've tried several things but wasn't able to get localised messages working. I can set a message programmatically – either once and the same for all subsequent requests, or as static property with no access to the current request's language. This is a very frustrating situation. The documentation should really contain a huge warning that says that the BCL validation attributes are a dumb stub and should never used for real applications because they cannot support multilingual UIs.

PS: I'm not interested in prelocalised texts from Microsoft. The default texts are bad already. For example they include the model property name, a technical term defined by a programmer (which isn't even necessary because the message will appear directly under the relevant input field anyway, that proximity is much better than making the user search and compare strings across the page), and that's quoted in typewriter marks (Americans won't see much of a difference), pretty ugly to look at. These default messages just cannot be presented to a user, so I have to provide my own messages. I'm happy to do that, but there's not even an interface to allow that. That's the issue. The entire API does not allow per-request localisation.

Even worse, I believe the entire API of System.ComponentModel.DataAnnotations is non-localisable by design. While I can create my own ValidationAttribute that can do its own validation and provide its own error message, there's nothing that can tell it what language the message is needed in. The only relevant overridable method FormatErrorMessage(string name) is only given the field name (useless) but no environment object, HttpContext or service provider of any kind. I don't see where the current request language should be regarded. Static data obviously isn't appropriate in a multi-threaded web server. The attribute's constructor is executed only twice (once for EF and once for ModelBinding) and never again, so it can't theoretically be used for per-request dependency injection either. There are no other base properties that might be useful.

This lets me question the complete data validation story of ASP.NET (Core) and WPF. It doesn't seem to exist. But it doesn't seem to be needed either. IIRC, EF6 did validate data before sending it off to the database but EF Core doesn't seem to do that anymore. So actually I don't need the concept of validation attributes at all anymore. Instead, I just validate all form data explicitly in each controller method, and if invalid, generate the necessary error validation message for the user. Just like any other model error message.

Oh, I haven't even started to explore the localisation of automatically generated model binding conversion error messages, like when the user enters text into a field where the model type is a number. That's even harder because I can't normally just do that myself in the controller action – the model binder has already done that before. I'll have to find out where and how, and overwrite those default messages, too.

ASP.NET (Core) and WPF just work best when the user only enters all required and valid data. It fails quickly otherwise.

(I know I could and should add client-side validation in ASP.NET, but that's not there yet and that certainly doesn't free the server-side validation from working properly.)

Was this page helpful?
0 / 5 - 0 ratings

Related issues

jchannon picture jchannon  Â·  3Comments

bencz picture bencz  Â·  3Comments

noahfalk picture noahfalk  Â·  3Comments

btecu picture btecu  Â·  3Comments

yahorsi picture yahorsi  Â·  3Comments