Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Validation messages are locked to the language the form is first loaded in #30

Open
eraserqueen opened this issue Oct 16, 2015 · 3 comments

Comments

@eraserqueen
Copy link

I am working on a multi lingual website using Umbraco 7.2.4. I have a form for each language nested under home nodes with their own culture:

  • Home (language selection)
    • nl-BE
      • some page
      • some other page
      • my form page
    • fr-BE
      • some page
      • some other page
      • my form page

Steps to reproduce

  • land on nl-BE/form
    • field labels are shown in dutch (nl-BE)
  • submit invalid form
    • validation messages are shown in dutch (nl-BE culture)
  • browse to fr-BE/form
    • field labels are shown in french (fr-BE)
  • submit invalid form
    • Expected behavior is: validation messages are shown in french (fr-BE culture)
    • Actual behavior is: messages are still shown in dutch (data-val-required attribute is in dutch in the source of the page)

This is not a browser cache issue, it is reproducible across separate browsers, even separate computers: whoever is generating the form for the first time will lock the validation message culture. The only way to change the language of the validation messages is to recycle the Application Pool.

I doubt that your helper class is the issue here but I'm out of ideas, so any insight is appreciated.

(update: I originally thought this issue was restricted to the javascript unobtrusive validation, but after testing with javascript disabled to hit the mvc validation directly I got the same issue.)

Source code

Model

    public class MyFormViewModel : RenderModel
    {
        public class PersonalDetails
        {
            [UmbracoDisplayName("FORMS_FIRST_NAME")]
            [UmbracoRequired("FORMS_FIELD_REQUIRED_ERROR")]
            public String FirstName { get; set; }
        }
}

View

    using (Html.BeginUmbracoForm<MyFormController>("SubmitMyForm", null, new {id = "my-form"}))
    { 
            <h3>@LanguageHelper.GetDictionaryItem("FORMS_HEADER_PERSONAL_DETAILS")</h3>
            <div class="field-wrapper">
                @Html.LabelFor(m => model.PersonalDetails.FirstName)
                <div class="input-wrapper">
                    @Html.TextBoxFor(m => model.PersonalDetails.FirstName)
                    @Html.ValidationMessageFor(m => model.PersonalDetails.FirstName)
                </div>
            </div>

note: I have used the native MVC Html.BeginForm method as well, same results.

Controller

    public ActionResult SubmitFranchiseApplication(FranchiseFormViewModel viewModel)
        {
            TempData["FormModel"] = viewModel;
            TempData["Success"] = ModelState.IsValid;
            if (!ModelState.IsValid)
            {
                TempData["Message"] = LanguageHelper.GetDictionaryItem("FORMS_VALIDATION_FAILED_MESSAGE");
                foreach (ModelState modelState in ViewData.ModelState.Values)
                {
                    foreach (ModelError error in modelState.Errors)
                    {
                        TempData["Message"] += "<br/>" + error.ErrorMessage;
                    }
                }

                return RedirectToCurrentUmbracoPage();
            }
    }

LanguageHelper

    public class LanguageHelper
    {
        public static string CurrentCulture
        {
            get
            {
                return UmbracoContext.Current.PublishedContentRequest.Culture.ToString();
                // I also tried using the thread culture
                return System.Threading.Thread.CurrentThread.CurrentCulture.ToString(); 
            }
        }
        public static string GetDictionaryItem(string key)
        {
            var value = library.GetDictionaryItem(key);
            return string.IsNullOrEmpty(value) ? key : value;
        }
}
@eraserqueen eraserqueen changed the title Javascript validation messages are locked to the language the form is first loaded in Validation messages are locked to the language the form is first loaded in Oct 16, 2015
@eraserqueen
Copy link
Author

So I finally found a workaround. In attempt to reduce my app to its simplest form and debug it, I ended up recreating the "UmbracoRequired" decoration attribute. The issue appeared when ErrorMessage was set in the Constructor rather than in the GetValidationRules method. It seems that MVC is caching the result of the constructor rather than invoking it again every time the form is loaded. Adding a dynamic property to the UmbracoRequired class for ErrorMessage also works.

Here's how my custom class looks like in the end.

[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Parameter,
        AllowMultiple = false)]
    internal class LocalisedRequiredAttribute : RequiredAttribute, IClientValidatable
    {
        private string _dictionaryKey;
        public LocalisedRequiredAttribute(string dictionaryKey)
        {
            _dictionaryKey = dictionaryKey;            
        }

        public IEnumerable<ModelClientValidationRule> GetClientValidationRules(
           ModelMetadata metadata, ControllerContext context)
        {
            ErrorMessage = LanguageHelper.GetDictionaryItem(_dictionaryKey); // this needs to be set here in order to refresh the translation every time
            yield return new ModelClientValidationRule
            {
                ErrorMessage = this.ErrorMessage, // if you invoke the LanguageHelper here, the result gets cached and you're locked to the current language
                ValidationType = "required"
            };
        }
    }

@warrenbuckley
Copy link
Owner

Hello @dominiquerolin
Is this something that should be added back to the project as a Pull Request?

@eraserqueen
Copy link
Author

Hi @warrenbuckley
as far as I can tell, that's already implemented properly in your code. Not sure why it didn't work with my application. The only difference between your code and my reduced implementation is that I dropped the UmbracoHelper and ignore Umbraco Context entirely, relying only on library.GetDictionaryItem to retrieve my values. If I have time to dig around some more I'll keep you posted.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants