Warning: Invalid argument supplied for foreach() in D:\home\site\wwwroot\wp-includes\translations.php on line 1174 Warning: Invalid argument supplied for foreach() in D:\home\site\wwwroot\wp-includes\translations.php on line 1367

Localization in C# is very straightforward. C# comes with Resource files, which are great because they can be easily translated, and C# can switch between them automatically.
 

First, add a new Resource File to your project. In my case, I called it SiteFields.resx. This will be the default language file, which in this case is English.
 

Next, we create a Localized Display Name Attribute, so we can leverage our ViewModels properly, instead of relying on text.

public class LocalizedDisplayNameAttribute : DisplayNameAttribute
{
    public LocalizedDisplayNameAttribute(string resourceId) : base(GetMessageFromResource(resourceId))
    {

    }

    private static string GetMessageFromResource(string resourceId)
    {
        CultureInfo culture = null;

        if (HttpContext.Current.Session["CultureInfo"] != null)
            culture = (CultureInfo)HttpContext.Current.Session["CultureInfo"];
        else
            culture = CultureInfo.CurrentCulture;

        return Resources.SiteFields.ResourceManager.GetString(resourceId, culture);
    }
}

 

We now have a new attribute we can use, so let's take advantage of it, and add it to one of our ViewModels.

public partial class ProfileViewModel
{
    [LocalizedDisplayNameAttribute("DisplayName")]
    public string DisplayName { get; set; }

    [LocalizedDisplayNameAttribute("AboutMe")]
    public string AboutMe { get; set; }

    [LocalizedDisplayNameAttribute("ProfileUrl")]
    public string ProfileUrl { get; set; }

    [LocalizedDisplayNameAttribute("ProfilePhoto")]
    public string Photo { get; set; }
}

 

NOTE: Resource keys have to be unique, so you'll want to pick your names carefully, so you know where the particular text is shown

 

Next, let's create another Resource file to handle Validation Errors. MVC has something already built-in for this, so we're in luck. I named my resource file SiteValidation. We'll make the Display Name and About Me required, and we have:

public partial class ProfileViewModel
{
    [LocalizedDisplayNameAttribute("DisplayName")]
    [Required(ErrorMessageResourceName = "DisplayNameRequired", ErrorMessageResourceType=typeof(Resources.SiteValidation))]
    public string DisplayName { get; set; }

    [LocalizedDisplayNameAttribute("AboutMe")]
    [Required(ErrorMessageResourceName = "AboutMeRequired", ErrorMessageResourceType = typeof(Resources.SiteValidation))]
    public string AboutMe { get; set; }

    [LocalizedDisplayNameAttribute("ProfileUrl")]
    public string ProfileUrl { get; set; }

    [LocalizedDisplayNameAttribute("ProfilePhoto")]
    public string Photo { get; set; }
}

 

In the above class, the ErrorMessageResourceType specifies which resource file to look at for the key.
 

Now to make your site multi-lingual, just duplicate the resource files you already have, change the text inside to the appropriate language (keep the key always the same, of course), and name them:

SiteFields.fr.resx - for french
SiteValidation.fr.resx
or
SiteFields.en-GB.resx - for British English
SiteValidation.en-GB.resx

 

The appropriate language file will be read automatically by C# and assigned to the properties based on the locale that's set.
You can optionally assign the culture using:

Session["CultureInfo"] = CultureInfo.GetCultureInfoByIetfLanguageTag(culture);