DataAnnotations with localized text

Jan 27, 2011 at 1:23 PM
Edited Jan 27, 2011 at 1:29 PM

DataAnnotations are added on Compile time.. but ofcourse i want them at runtime.
The real question:

if i do:
[Required, DisplayName("Customer name:"]
public string Name { get; set; }

will it be localizeable?


Else:
Looking at unobtrusive clientside validation i think we need to use DataAnnotations and that AddModelError isn't sufficient.

Creating custom validations and using only them might be a solution, where i can use the Orchard Localizer in the base.
http://carrarini.blogspot.com/2010/08/localize-aspnet-mvc-2-dataannotations.html

Might i be wrong?
How would others use DataAnnotations?

Jan 28, 2011 at 11:15 AM

After playing with the Localizer, or better to say "DefaultLocalizedStringManager" i'm afraid that it really needs to be:
- a new LocalizedString("myMsgIdString") in code 
- @T("myMsgIdString") as html helper
- T("myMsgIdString") within a htmlhelper extension

Will unobtrusive clientside validation work without DataAnnotations?
Is there a need to use DataAnnotations?

I'm thinking about making a custom DataAnnotation foreach DataAnnotation available with the "Third Approach" from the link above.

Any idea's, anybody?

Jan 28, 2011 at 12:21 PM
Edited Jan 28, 2011 at 12:21 PM

ok, i just created a custom DataAnnotation.. just feels like a hack thru, i needed to get the localizer from the workcontext or IComponentContext
I just have no idea where to get the scope from

public class LocalizedDisplayNameAttribute : DisplayNameAttribute 
{
    public LocalizedDisplayNameAttribute(string displayNameKey) 
        : base(displayNameKey) 
    {
    }
    
    public override string DisplayName 
    { 
        get 
        {
            var localizer = LocalizationUtilities.Resolve(HttpContext.Current.Request.RequestContext.GetWorkContext(), "");///* AppRelativeVirtualPath */);
            return localizer(base.DisplayName, new object[] {} ).Text;
        } 
    } 
}
Jan 29, 2011 at 5:28 PM

Anyone from the team thinks this is an hack as well?

I could hack a bit more using the stacktrace to find the namespace of the view or class :)
Is it otherwise possible inside the attribute to find which method it belongs to?

Jan 31, 2011 at 2:36 PM

ok it's a hack! at least i think it's...

When u see attributes as MetaData i think the attribute validators should ask the localizer for the real errormessage. The errormessage in the annotation is then just a identifier for the localizer.

            DataAnnotationsModelValidatorProvider.RegisterAdapter(typeof(RequiredAttribute), typeof(LocalizedRequiredValidator));

 

Apr 19, 2011 at 1:08 PM

Can we use this approach for localized display name attribute?

Apr 19, 2011 at 1:37 PM

The last post yes..

Remove the DefaultAdapter and register a new Adapter c.q. Validator.
Just search on the internet for "DataAnnotationsModelValidatorProvider.RegisterAdapter" and u'll find lots of information about implimenting one.
It shouldn't be difficult to replace the default DisplayName adaptervalidator by a custom one which uses the Localizer.

PS: Vote on the workitem i created for this.
http://orchard.codeplex.workitem/17277

Apr 19, 2011 at 2:50 PM

I have reviewed some codes about RegisterAdapter on the Internet but I don't know if these kind of methods would brake the Orchard localization system.

An example would be great!

By the way I checked the builtin comments module and there are some custom annotations implemented for localization. Like:

 

    public class CommentRequiredAttribute : System.ComponentModel.DataAnnotations.RequiredAttribute {
        public CommentRequiredAttribute() {
            T = NullLocalizer.Instance;
        }

        public Localizer T { get; set; }

        public override string FormatErrorMessage(string name) {
            return T("You must provide a Comment.", name).Text;
        }
    }

Coordinator
Apr 19, 2011 at 5:45 PM

Good catch. I checked the code you pointed at, and it seems to be working just fine. I checked with Nathan (dev team) and it has been implemented lately. So yes, you should use the same technique. And I will open a bug so that we convert all current data annotation usages to use localized versions. Before we tended to validate the models in the controllers for localization matters, but it's obvious we have to use annotation if they support localization.

http://orchard.codeplex.com/workitem/17754

Apr 19, 2011 at 9:42 PM

Below are my implementations for DisplayName, Required and Range

    public class DisplayNameAttribute : System.ComponentModel.DisplayNameAttribute
    {

        public DisplayNameAttribute(string displayName)
            : base(displayName)
        {
            T = NullLocalizer.Instance;
        }

        public Localizer T { get; set; }

        public override string DisplayName
        {
            get
            {
                return T(base.DisplayName).Text;
            }
        }

    }

    public class RequiredFieldAttribute : System.ComponentModel.DataAnnotations.RequiredAttribute {
        public RequiredFieldAttribute()
        {
            T = NullLocalizer.Instance;
        }

        public Localizer T { get; set; }

        public override string FormatErrorMessage(string name) {
            return T("The {0} field is required.", name).Text;
        }
    }

    public class RangeAttribute : System.ComponentModel.DataAnnotations.RangeAttribute
    {
        public RangeAttribute(int minimum, int maximum)
            : base(minimum, maximum)
        {
            T = NullLocalizer.Instance;
        }

        public RangeAttribute(double minimum, double maximum)
            : base(minimum, maximum)
        {
            T = NullLocalizer.Instance;
        }

        public RangeAttribute(Type type, string minimum, string maximum)
            : base(type, minimum, maximum)
        {
            T = NullLocalizer.Instance;
        }

        public Localizer T { get; set; }

        public override string FormatErrorMessage(string name)
        {
            return T("You must provide a value between " + base.Minimum.ToString() + " and " + base.Maximum.ToString() + " for {0}.", name).Text;            
        }
    }

Apr 20, 2011 at 6:27 AM

By the way, for the RangeAttribute I tried to use parameters {1} and {2} for the error message rather than base.Minimum.ToString() and base.Maximum.ToString() but then the page did not display these validation messages and their associated fields. No errors or something but they didn't rendered.

Appearantly, in this current format, the localization will not work properly.

Jun 10, 2011 at 7:46 AM
Edited Jun 10, 2011 at 7:55 AM

On the nuget site (running on Orchard hehe) is a package available for more MVC3 extensions.
If the team goes for localizable DataAnnotations, plz make them localizable them as well

http://nuget.org/List/Packages/DataAnnotationsExtensions.MVC3