Search code examples
c#asp.netasp.net-mvcvalidationdata-annotations

Required Data Annotation is not being translated


We are facing with an strange error with localization of Required attribute.

We have the following code:

    public class AnswersGroupViewModel
    {
        public int IDAnswerGroup { get; set; }
        public int IDEvaluator { get; set; }
        public List<AnswersViewModel> Answers { get; set; }
    }

    public class AnswersViewModel
    {        
        public string Text{ get; set; }      
        [Required(ErrorMessageResourceName = "RequiredMessage", ErrorMessageResourceType = typeof(Resources.Language))]
        public int IDAnswer{ get; set; }
    }

The problem is that the right translation of "RequiredMessage" is not being picked up from resource file, although it is present (we have RequiredMessage on both spanish and russian resource files).

Attributes like Display are working and being translated, but seems to be a problem with the Required attribute.

Here is an example image:

Labels are translated to russian, but required message is in spanish

Error is shown with a @Html.ValidationMessage

Thanks in advance for your help.


Solution

  • I would start with setting the globalization element in web.config

    <system.web>
      <globalization enableClientBasedCulture="true" culture="auto" uiCulture="auto"/>
    

    Next I would check the culture you are getting in a Controller (log it in DB or pass to a view with @ViewBag

    culture = CultureInfo.InstalledUICulture.IetfLanguageTag;
    if (HttpContext.Current != null && HttpContext.Current.Request.UserLanguages != null)
    {
        culture = Request.UserLanguages[0];     
    }
    

    Confirm that the values you use to identify Culture are the values being used by headers


    Followup

    You are using globalization headers to check for user language, but are setting user language manually in browser.

    2 approaches to try:

    1) set user language in browser using Javascript:

    <script type="text/javascript"> 
         Globalize.culture("@ViewBag.Culture");
    </script>
    

    Or if culture is set in Javascript (vs C#)

    <script type="text/javascript"> 
         Globalize.culture(culturevariable);
    </script>
    

    2) ParameterisedRequiredAttribute

    public class ParameterisedRequiredAttribute : RequiredAttribute
    {
        private string[] _replacements { get; set; }
    
        public ParameterisedRequiredAttribute(params string[] replacements)
        {
            _replacements = replacements;
    
            ErrorMessageResourceName = ErrorMessagesErrors.SpecificFieldRequired;
            ErrorMessageResourceType = typeof(ErrorMessages);
        }
    
        public override string FormatErrorMessage(string name)
        {
            return string.Format(ErrorMessageString, (object[])_replacements);
        }
    }
    

    The first approach seems like a better solution if you are manually setting the language. Simply put, the annotation would have to be re-set everytime the user changes language modes.

    Another thing to consider is that the way you currently set language (through headers) is probably your best solution. While this is harder to test because you need a client with dedicated language, this is the way your users are best distinguished (by headers).