Localization in ASP.NET MVC 4 using App_GlobalResources
Asked Answered
A

2

7

I am trying to accomplish two things:

  1. Localize the “built-in” error messages for “FieldMustBeDate” and "FieldMustBeNumeric".
  2. Localize some of the other error messages you would encounter, for example, "PropertyValueRequired".

By using http://forums.asp.net/t/1862672.aspx/1 for problem 1 and MVC 4 ignores DefaultModelBinder.ResourceClassKey for problem 2 I have managed to get both working locally.

However as soon as I publish to a website, the “built-in” error messages defaults back to English while the other error messages stay localized.

I have read several places that using the App_GlobalResources should be avoided, however I am unable to accomplish problem 1 without using this.

I have created a .resx file with the name “WebResources.resx”, set the Build Action to “Embedded”, set the Copy to Output Directory to “Do no Copy”, set the Custom Tool to “PublicResXFileCodeGenerator” and set the Custom Tool Namespace to “Resources”. The Project itself is set to only Publish files that are needed.

My Global.asax.cs contains the following (relevant) code:

  ClientDataTypeModelValidatorProvider.ResourceClassKey = "WebResources";  
  DataAnnotationsModelValidatorProvider.RegisterAdapter(
  typeof(RequiredAttribute),
  typeof(MyRequiredAttributeAdapter));

And the class MyRequiredAttributeAdapter contains the following code:

public class MyRequiredAttributeAdapter : RequiredAttributeAdapter
{
    public MyRequiredAttributeAdapter(
        ModelMetadata metadata,
        ControllerContext context,
        RequiredAttribute attribute
    )
        : base(metadata, context, attribute)
    {
        if (attribute.ErrorMessageResourceType == null)
        {
            attribute.ErrorMessageResourceType = typeof(Resources.WebResources);
        }
        if (attribute.ErrorMessageResourceName == null)
        {
            attribute.ErrorMessageResourceName = "PropertyValueRequired";
        }
    }
}

This is working locally however does anyone have any idea on how to get the "built in" messages to work after this is published?

Thank you for your help!

Best regards, Andreas

Adoptive answered 28/5, 2013 at 10:39 Comment(0)
A
5

I figured this one out myself. If you are trying to accomplish the above you must separate the localized error messages.

Create a *.resx file for the other error messages fx "PropertyValueRequired" and set the Build Action to “Embedded”, set the Copy to Output Directory to “Do no Copy”, set the Custom Tool to “PublicResXFileCodeGenerator” and set the Custom Tool Namespace to “Resources”.

In my case I have moved "PropertyValueRequired" to a file called LocalDanish.resx (still in the App_GlobalResources folder) and changed the line in my "MyRequiredAttributeAdapter" from

attribute.ErrorMessageResourceType = typeof(Resources.WebResources);

to

attribute.ErrorMessageResourceType = typeof(Resources.LocalDanish);

In order to get the "built in" error messages to work, you must create two *.resx files. I have created WebResources.resx and WebResources.da.resx. Do NOT change anything, leave the settings on them on default (Build Action to "Content", etc.). I guess the website automatically looks for the *.da.resx files in my case because I have set the globalization in my WebConfig:

<globalization uiCulture="da-DK" culture="da-DK"/>

Hope this helps anybody.

Best regards, Andreas

Adoptive answered 28/5, 2013 at 12:30 Comment(0)
P
1

I have made some minor additions to the original post, which didn't translate all messages in my case. (String length and invalid property values)

Follow the above steps, to create the *.resx files, set their properties, and then set the locale in web.config, as described by Andreas.

Then create a couple of adapters:

// As described in original post:
public class LocalizedRequiredAttributeAdapter : RequiredAttributeAdapter
{
    public LocalizedRequiredAttributeAdapter(
        ModelMetadata metadata,
        ControllerContext context,
        RequiredAttribute attribute
    )
        : base(metadata, context, attribute)
    {
        if (attribute.ErrorMessageResourceType == null)
            attribute.ErrorMessageResourceType = typeof(Resources.Resources);
        if (attribute.ErrorMessageResourceName == null)
            attribute.ErrorMessageResourceName = "PropertyValueRequired";
    }
}

// Addition to original post:
public class LocalizedStringLengthAttributeAdapter : StringLengthAttributeAdapter
{
    public LocalizedStringLengthAttributeAdapter(
        ModelMetadata metadata,
        ControllerContext context,
        StringLengthAttribute attribute
    )
        : base(metadata, context, attribute)
    {
        if (attribute.ErrorMessageResourceType == null)
            attribute.ErrorMessageResourceType = typeof(Resources.Resources);
        if (attribute.ErrorMessageResourceName == null)
            attribute.ErrorMessageResourceName = "StringLengthAttribute_ValidationError";
    }
}

And in Global.asax.cx:

// Addition to original post: (Used for "PropertyValueInvalid")
DefaultModelBinder.ResourceClassKey = "Resources";

// As described in original post:
ClientDataTypeModelValidatorProvider.ResourceClassKey = "Resources";
DataAnnotationsModelValidatorProvider.RegisterAdapter(typeof(RequiredAttribute), typeof(LocalizedRequiredAttributeAdapter));
DataAnnotationsModelValidatorProvider.RegisterAdapter(typeof(StringLengthAttribute), typeof(LocalizedStringLengthAttributeAdapter));
Patriarchy answered 1/10, 2013 at 10:36 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.