Integrating Data Annotations with the Localization Service

Vote:
 

The EPiServer Localization Service comes pre-integrated with the various Data Annotations supported by EPiServer for use with Content Properties. This enables Implementors to create, for example, Page Properties such as the one below:

        [Display(Name = "H1 Heading",
            GroupName = SystemTabNames.Content,
            Order = 10)]
        [CultureSpecific]
        [Required(AllowEmptyStrings = false, ErrorMessage = "/annotations/header/requirederror")]
        public virtual string Header { get; set; }

This all works straight out of the box whilst in Edit View mode; all is good and we are happy.

I would like to go further though and use Data Annotations on my Custom View Models that are requierd within my solutions and integrate those annotations with the EPiServer Localization Service so that EPiServer Content Mangement can be applied to the error/validation messages output by, say, MVC unobtrusive valdation; in a similar manner to the above Edit Mode scenario with my Content Model. For example, consider the following Custom View Model associated with a Login Page...

    public class LoginViewModel
    {
        [Required(AllowEmptyStrings = false, ErrorMessage = "/annotations/usernamerequired")]
        [EmailAddress(ErrorMessage = "/annotations/mustbeanemail")]
        public string Username { get; set; }
        [Required(AllowEmptyStrings = false, ErrorMessage = "/annotations/passwordrequired")]
        public string Password { get; set; }
    }

The out of the box behaviour is that Unobtrusive Validation outputs the Localization Key rather than the Localized String. What is the wiring that I need to undertake in order to have this work for me in Visitor Mode?

Any assistance on this would be most gratefully received.

#79493
Dec 18, 2013 17:09
Vote:
 

Hi Martin, 

 

we used approach described in http://world.episerver.com/Blogs/Lars-Woetmann-Pedersen/Dates/2013/7/MVC-ValidationAttribute-ErrorMessage-populated-at-runtime/

 

Unfortunately our own implementation is not a nuget package yet, but briefly we customized 2 things: DataAnnotationsModelMetadataProvider and DataAnnotationsModelValidatorProvider. Please let me know if it's enough for you to start or you'd like more detailed code samples. 

---

WBR, 

Vladimir Levchuk

#79515
Dec 19, 2013 9:53
Vote:
 

@Vladimir

that's great. more than I hoped for. thank you

#79541
Dec 19, 2013 17:06
Vote:
 

Hmm, using something based on CachedDataAnnotationsModelMetadataProvider to provide localised validation messages for ValidationAttributes on ViewModels whilst in Visitor Mode appears to work fine.

However, a whole world of pain ensues if your goal is to support a site with mutiple active language branches (only the first activated langauge branch can localise the message) or support editing of the messages (the value at first activation is always used) without restarting the AppPool.

Need to think again now.

#81809
Edited, Feb 26, 2014 18:49
Vote:
 

Martin: Same issue here. Did you find a working solution?

#139834
Oct 07, 2015 13:17
Vote:
 
#139856
Oct 07, 2015 19:31
Vote:
 

Thanks, yes actually I was already using your implementation from that article. But then I found out to have trouble with localizing the [Display] attribute which I am also using. In a typical view model I have this property:

[Display(Name = "/fields/username")]
[Required(ErrorMessage = "/validation/required")]
public string Username { get; set; }


Using your LocalizableModelMetadataProvider (that detects ErrorMessage starting with "/" and stores the value as a custom property in AdditionalValues), and registering a LocalizableRequiredAnnotationsAdapter that looks for this custom property and translates the value using LocalizationService, works very well. It also works if I change the current UI culture and so forth. I even implemented support for default localized validation messages if I use attributes without setting the ErrorMessage, i.e. just using [Required]. Also working like a charm!

The problem I have now is that the Display attribute is not localized, and I'm not sure where or how to do it. I tried the following code in method CreateMetadataPrototype (in our custom LocalizableModelMetadataProvider):

var displayAttr = attributes.OfType<DisplayAttribute>().SingleOrDefault(a => !string.IsNullOrWhiteSpace(a.Name) && a.Name.StartsWith("/"));
if (displayAttr != null)
{
    prototype.DisplayName = LocalizationService.Current.GetString(displayAttr.Name, propertyName);
}

But the DisplayName value set here doesn't seem to do any difference. I noticed that the above snippet actually works if I have my provider inheriting DataAnnotationsModelMetadataProvider (instead of the CachedDataAnnotationsModelMetadataProvider), but then the ErrorMessage logic gets broken...

How to do this? Do I have to subclass the old DisplayNameAttribute instead? (the newer DisplayAttribute class is sealed...) :O :X :(

#139863
Edited, Oct 08, 2015 9:24
This topic was created over six months ago and has been resolved. If you have a similar question, please create a new topic and refer to this one.