<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom"><title type="text">Blog posts by devabees</title><link href="http://world.optimizely.com" /><updated>2014-03-11T17:12:00.0000000Z</updated><id>https://world.optimizely.com/blogs/devabees/</id> <generator uri="http://world.optimizely.com" version="2.0">Optimizely World</generator> <entry><title>Integrating the EPiServer LocalizationService with MVC Validation Attributes</title><link href="https://world.optimizely.com/blogs/devabees/Dates/2014/3/Integrating-LocalizationService-with-MVC-DataAnnotations/" /><id>&lt;p&gt;The code-first content modelling technique made main stream by EPiServer CMS 7 and now almost universal with EPiServer 7.5 and EPiServer Commerce 7 makes extensive use of the DataAnnotations available within ASP.Net. This has enriched and strengthened the Edit Mode experience for our beloved Content Editors and allows Implementers a relatively easy way to customize the Error and Warning Messages issued by EPiServer’s Edit Mode views when an attempt to violate the Content Model is detected.&lt;/p&gt;  &lt;p&gt;Simply put, by setting the ErrorMessage property of a Validation Annotation class attached to a Content Property to a string starting with “/”, EPiServer CMS Edit Mode will attempt to use the value as a Localization Service Resource Key during On-Page Edit and All Properties View interactions.&lt;/p&gt;  &lt;p&gt;For example,&lt;/p&gt;  &lt;div class=&quot;csharpcode&quot;&gt;   &lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;&lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;class&lt;/span&gt; SimplePage : PageData&lt;/code&gt;&lt;/pre&gt;

  &lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;{&lt;/code&gt;&lt;/pre&gt;

  &lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;   [Display(Name = &lt;span class=&quot;str&quot;&gt;&amp;quot;Heading&amp;quot;&lt;/span&gt;,&lt;/code&gt;&lt;/pre&gt;

  &lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;      Description = &lt;span class=&quot;str&quot;&gt;&amp;quot;The Main Heading (h1) for the Page.&amp;quot;&lt;/span&gt;,&lt;/code&gt;&lt;/pre&gt;

  &lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;      GroupName = SystemTabNames.Content,&lt;/code&gt;&lt;/pre&gt;

  &lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;      Order = 10)]&lt;/code&gt;&lt;/pre&gt;

  &lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;   [Required(ErrorMessage=&lt;span class=&quot;str&quot;&gt;&amp;quot;/contenttypes/SimplePage/headingrequired&amp;quot;&lt;/span&gt;]&lt;/code&gt;&lt;/pre&gt;

  &lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;   &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;virtual&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;string&lt;/span&gt; Heading { get; set; }&lt;/code&gt;&lt;/pre&gt;

  &lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;style type=&quot;text/css&quot;&gt;


















.csharpcode {margin:20px 0px;}

.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, &quot;Courier New&quot;, courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }&lt;/style&gt;

&lt;p&gt;The thing is though, there is no such integration for the View Models one may create to support a custom application with a need to interact with the Visitor, such as a Cart or Checkout application or indeed a custom logon page. Therefore, here is but one idea as to how this might be achieved. I am sure there are a legion of other ways and I know of at least one other by &lt;a href=&quot;http://world.episerver.com/Blogs/Lars-Woetmann-Pedersen/Dates/2013/7/MVC-ValidationAttribute-ErrorMessage-populated-at-runtime/&quot;&gt;Vladimir Levchuk&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;My solution for integrating the EPiServer Localization Service with MVC View Models and Data Annotations is to:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Override the MVC CachedDataAnnotationsModelMetadataProvider to be able to extend the Model Metadata a little bit. 
    &lt;br /&gt;Basically, detect an instance of an annotation class that has its ErrorMessage property set with a string value starting with &amp;quot;/&amp;quot;; storing in a custom Model Metadata property the value of the resource key. &lt;/li&gt;

  &lt;li&gt;Create or override (&lt;em&gt;as appropriate&lt;/em&gt;) Attribute Adapter classes for the desired Annotation Attribute types used by the application&#39;s View Models: such as RequiredAttributeAdapter and StringLengthAttributeAdapter. The Attribute Adapter classes look for the Model Metadata custom property created by the Model Metadata Provider and then use the Localization Service to obtain the translated, custom error message value to use during Model Validation, whether that be Server or Client side validation. &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So taking, as an example, a fairly typical Logon View Model:&lt;/p&gt;

&lt;div class=&quot;csharpcode&quot;&gt;
  &lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;&lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;class&lt;/span&gt; LogonViewModel&lt;/code&gt;&lt;/pre&gt;

  &lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;{&lt;/code&gt;&lt;/pre&gt;

  &lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;   [Required(AllowEmptyStrings = &lt;span class=&quot;kwrd&quot;&gt;false&lt;/span&gt;, ErrorMessage = &lt;span class=&quot;str&quot;&gt;&amp;quot;/contenttypes/logonpage/username/required&amp;quot;&lt;/span&gt;)]&lt;/code&gt;&lt;/pre&gt;

  &lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;   [EmailAddress(ErrorMessage = &lt;span class=&quot;str&quot;&gt;&amp;quot;/contenttypes/logonpage/username/mustbeanemail&amp;quot;&lt;/span&gt;)]&lt;/code&gt;&lt;/pre&gt;

  &lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;   &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;string&lt;/span&gt; Username { get; set; }&lt;/code&gt;&lt;/pre&gt;

  &lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;&amp;#160;&lt;/code&gt;&lt;/pre&gt;

  &lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;   [Required(AllowEmptyStrings = &lt;span class=&quot;kwrd&quot;&gt;false&lt;/span&gt;, ErrorMessage = &lt;span class=&quot;str&quot;&gt;&amp;quot;/contenttypes/logonpage/password/required&amp;quot;&lt;/span&gt;)]&lt;/code&gt;&lt;/pre&gt;

  &lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;   [StringLength(15, MinimumLength = 6, ErrorMessage = &lt;span class=&quot;str&quot;&gt;&amp;quot;/contenttypes/logonpage/password/lengthproblem&amp;quot;&lt;/span&gt;)]&lt;/code&gt;&lt;/pre&gt;

  &lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;   [DataType(DataType.Password)]&lt;/code&gt;&lt;/pre&gt;

  &lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;   &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;string&lt;/span&gt; Password { get; set; }&lt;/code&gt;&lt;/pre&gt;

  &lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;&amp;#160;&lt;/code&gt;&lt;/pre&gt;

  &lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;   [DataType(DataType.Password)]&lt;/code&gt;&lt;/pre&gt;

  &lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;   [System.Web.Mvc.Compare(&lt;span class=&quot;str&quot;&gt;&amp;quot;Password&amp;quot;&lt;/span&gt;, ErrorMessage = &lt;span class=&quot;str&quot;&gt;&amp;quot;/contenttypes/logonpage/confirmpwd/doesnotcompare&amp;quot;&lt;/span&gt;)]&lt;/code&gt;&lt;/pre&gt;

  &lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;   &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;string&lt;/span&gt; ConfirmPassword { get; set; }&lt;/code&gt;&lt;/pre&gt;

  &lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;We see that we will need at the very least Attribute Adapters for Required, String Length, Email and Compare Attributes. The great thing about these Attribute Adapters, once written they can be re-used over and over again.&lt;/p&gt;

&lt;p&gt;So here are our Attribute Adapters...&lt;/p&gt;

&lt;div class=&quot;csharpcode&quot;&gt;
  &lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;&lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;class&lt;/span&gt; LocalisableRequiredAnnotationsAdapter: RequiredAttributeAdapter &lt;/code&gt;&lt;/pre&gt;

  &lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;{&lt;/code&gt;&lt;/pre&gt;

  &lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;    &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; LocalisableRequiredAnnotationsAdapter(ModelMetadata metadata, ControllerContext context, RequiredAttribute attribute) : &lt;span class=&quot;kwrd&quot;&gt;base&lt;/span&gt;(metadata, context, attribute)&lt;/code&gt;&lt;/pre&gt;

  &lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;    {&lt;/code&gt;&lt;/pre&gt;

  &lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;        LocalisableAnnotationAdapterInitialiser.Initialise(metadata, attribute);&lt;/code&gt;&lt;/pre&gt;

  &lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;    }&lt;/code&gt;&lt;/pre&gt;

  &lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;&amp;#160;&lt;/code&gt;&lt;/pre&gt;

  &lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;    &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;void&lt;/span&gt; SelfRegister()&lt;/code&gt;&lt;/pre&gt;

  &lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;    {&lt;/code&gt;&lt;/pre&gt;

  &lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;        DataAnnotationsModelValidatorProvider.RegisterAdapter(&lt;span class=&quot;kwrd&quot;&gt;typeof&lt;/span&gt;(RequiredAttribute),&lt;/code&gt;&lt;/pre&gt;

  &lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;            &lt;span class=&quot;kwrd&quot;&gt;typeof&lt;/span&gt;(LocalisableRequiredAnnotationsAdapter));&lt;/code&gt;&lt;/pre&gt;

  &lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;    }&lt;/code&gt;&lt;/pre&gt;

  &lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;}&lt;/code&gt;&lt;/pre&gt;

  &lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;&amp;#160;&lt;/code&gt;&lt;/pre&gt;

  &lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;&lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;class&lt;/span&gt; LocalisableStringLengthAnnotationsAdapter : StringLengthAttributeAdapter&lt;/code&gt;&lt;/pre&gt;

  &lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;{&lt;/code&gt;&lt;/pre&gt;

  &lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;    &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; LocalisableStringLengthAnnotationsAdapter(ModelMetadata metadata, ControllerContext context, StringLengthAttribute attribute) : &lt;span class=&quot;kwrd&quot;&gt;base&lt;/span&gt;(metadata, context, attribute)&lt;/code&gt;&lt;/pre&gt;

  &lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;    {&lt;/code&gt;&lt;/pre&gt;

  &lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;        LocalisableAnnotationAdapterInitialiser.Initialise(metadata, attribute);&lt;/code&gt;&lt;/pre&gt;

  &lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;    }&lt;/code&gt;&lt;/pre&gt;

  &lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;&amp;#160;&lt;/code&gt;&lt;/pre&gt;

  &lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;    &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;void&lt;/span&gt; SelfRegister()&lt;/code&gt;&lt;/pre&gt;

  &lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;    {&lt;/code&gt;&lt;/pre&gt;

  &lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;        DataAnnotationsModelValidatorProvider.RegisterAdapter(&lt;span class=&quot;kwrd&quot;&gt;typeof&lt;/span&gt;(StringLengthAttribute),&lt;/code&gt;&lt;/pre&gt;

  &lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;            &lt;span class=&quot;kwrd&quot;&gt;typeof&lt;/span&gt;(LocalisableStringLengthAnnotationsAdapter));&lt;/code&gt;&lt;/pre&gt;

  &lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;    }&lt;/code&gt;&lt;/pre&gt;

  &lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;}&lt;/code&gt;&lt;/pre&gt;

  &lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;&amp;#160;&lt;/code&gt;&lt;/pre&gt;

  &lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;&lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;class&lt;/span&gt; LocalisableEmailAddressAnnotationsAdapter : DataAnnotationsModelValidator&amp;lt;EmailAddressAttribute&amp;gt;&lt;/code&gt;&lt;/pre&gt;

  &lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;{&lt;/code&gt;&lt;/pre&gt;

  &lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;    &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; LocalisableEmailAddressAnnotationsAdapter(ModelMetadata metadata, ControllerContext context, EmailAddressAttribute attribute)&lt;/code&gt;&lt;/pre&gt;

  &lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;        : &lt;span class=&quot;kwrd&quot;&gt;base&lt;/span&gt;(metadata, context, attribute)&lt;/code&gt;&lt;/pre&gt;

  &lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;    {&lt;/code&gt;&lt;/pre&gt;

  &lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;        LocalisableAnnotationAdapterInitialiser.Initialise(metadata, attribute);&lt;/code&gt;&lt;/pre&gt;

  &lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;    }&lt;/code&gt;&lt;/pre&gt;

  &lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;&amp;#160;&lt;/code&gt;&lt;/pre&gt;

  &lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;    &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;override&lt;/span&gt; IEnumerable&amp;lt;ModelClientValidationRule&amp;gt; GetClientValidationRules()&lt;/code&gt;&lt;/pre&gt;

  &lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;    {&lt;/code&gt;&lt;/pre&gt;

  &lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;        &lt;span class=&quot;kwrd&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;new&lt;/span&gt;[]&lt;/code&gt;&lt;/pre&gt;

  &lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;        {&lt;/code&gt;&lt;/pre&gt;

  &lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;            &lt;span class=&quot;kwrd&quot;&gt;new&lt;/span&gt; ModelClientValidationRegexRule(ErrorMessage,&lt;/code&gt;&lt;/pre&gt;

  &lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;                &lt;span class=&quot;str&quot;&gt;&amp;quot;^((([a-z]|\\d|[!#\\$%&amp;amp;&#39;\\*\\+\\-\\/=\\?\\^_`{\\|}~]|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])+(\\.([a-z]|\\d|[!#\\$%&amp;amp;&#39;\\*\\+\\-\\/=\\?\\^_`{\\|}~]|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])+)*)|((\\x22)((((\\x20|\\x09)*(\\x0d\\x0a))?(\\x20|\\x09)+)?(([\\x01-\\x08\\x0b\\x0c\\x0e-\\x1f\\x7f]|\\x21|[\\x23-\\x5b]|[\\x5d-\\x7e]|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])|(\\\\([\\x01-\\x09\\x0b\\x0c\\x0d-\\x7f]|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF]))))*(((\\x20|\\x09)*(\\x0d\\x0a))?(\\x20|\\x09)+)?(\\x22)))@((([a-z]|\\d|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])|(([a-z]|\\d|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])([a-z]|\\d|-|\\.|_|~|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])*([a-z]|\\d|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])))\\.)+(([a-z]|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])|(([a-z]|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])([a-z]|\\d|-|\\.|_|~|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])*([a-z]|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])))\\.?$&amp;quot;&lt;/span&gt;)&lt;/code&gt;&lt;/pre&gt;

  &lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;            {&lt;/code&gt;&lt;/pre&gt;

  &lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;                ValidationType = &lt;span class=&quot;str&quot;&gt;&amp;quot;email&amp;quot;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

  &lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;            }&lt;/code&gt;&lt;/pre&gt;

  &lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;        };&lt;/code&gt;&lt;/pre&gt;

  &lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;    }&lt;/code&gt;&lt;/pre&gt;

  &lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;&amp;#160;&lt;/code&gt;&lt;/pre&gt;

  &lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;    &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;void&lt;/span&gt; SelfRegister()&lt;/code&gt;&lt;/pre&gt;

  &lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;    {&lt;/code&gt;&lt;/pre&gt;

  &lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;        DataAnnotationsModelValidatorProvider.RegisterAdapter(&lt;span class=&quot;kwrd&quot;&gt;typeof&lt;/span&gt;(EmailAddressAttribute),&lt;/code&gt;&lt;/pre&gt;

  &lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;            &lt;span class=&quot;kwrd&quot;&gt;typeof&lt;/span&gt;(LocalisableEmailAddressAnnotationsAdapter));&lt;/code&gt;&lt;/pre&gt;

  &lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;    }&lt;/code&gt;&lt;/pre&gt;

  &lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;}&lt;/code&gt;&lt;/pre&gt;

  &lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;&amp;#160;&lt;/code&gt;&lt;/pre&gt;

  &lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;&lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;class&lt;/span&gt; LocalisableCompareAnnotationsAdapter : CompareAttributeAdapter&lt;/code&gt;&lt;/pre&gt;

  &lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;{&lt;/code&gt;&lt;/pre&gt;

  &lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;    &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; LocalisableCompareAnnotationsAdapter(ModelMetadata metadata, ControllerContext context, System.Web.Mvc.CompareAttribute attribute) : &lt;span class=&quot;kwrd&quot;&gt;base&lt;/span&gt;(metadata, context, attribute)&lt;/code&gt;&lt;/pre&gt;

  &lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;    {&lt;/code&gt;&lt;/pre&gt;

  &lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;        LocalisableAnnotationAdapterInitialiser.Initialise(metadata, attribute);&lt;/code&gt;&lt;/pre&gt;

  &lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;    }&lt;/code&gt;&lt;/pre&gt;

  &lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;&amp;#160;&lt;/code&gt;&lt;/pre&gt;

  &lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;    &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;void&lt;/span&gt; SelfRegister()&lt;/code&gt;&lt;/pre&gt;

  &lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;    {&lt;/code&gt;&lt;/pre&gt;

  &lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;        DataAnnotationsModelValidatorProvider.RegisterAdapter(&lt;span class=&quot;kwrd&quot;&gt;typeof&lt;/span&gt;(System.Web.Mvc.CompareAttribute),&lt;/code&gt;&lt;/pre&gt;

  &lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;            &lt;span class=&quot;kwrd&quot;&gt;typeof&lt;/span&gt;(LocalisableCompareAnnotationsAdapter));&lt;/code&gt;&lt;/pre&gt;

  &lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;    }&lt;/code&gt;&lt;/pre&gt;

  &lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;}&lt;/code&gt;&lt;/pre&gt;

  &lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;&amp;#160;&lt;/code&gt;&lt;/pre&gt;

  &lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;&lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;class&lt;/span&gt; CompareAttributeAdapter : DataAnnotationsModelValidator&amp;lt;System.Web.Mvc.CompareAttribute&amp;gt;&lt;/code&gt;&lt;/pre&gt;

  &lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;{&lt;/code&gt;&lt;/pre&gt;

  &lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;    &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; CompareAttributeAdapter(ModelMetadata metadata, ControllerContext context, System.Web.Mvc.CompareAttribute attribute)&lt;/code&gt;&lt;/pre&gt;

  &lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;        : &lt;span class=&quot;kwrd&quot;&gt;base&lt;/span&gt;(metadata, context, attribute)&lt;/code&gt;&lt;/pre&gt;

  &lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;    {    }&lt;/code&gt;&lt;/pre&gt;

  &lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;&amp;#160;&lt;/code&gt;&lt;/pre&gt;

  &lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;    &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;override&lt;/span&gt; IEnumerable&amp;lt;ModelClientValidationRule&amp;gt; GetClientValidationRules()&lt;/code&gt;&lt;/pre&gt;

  &lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;    {&lt;/code&gt;&lt;/pre&gt;

  &lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;        &lt;span class=&quot;kwrd&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;new&lt;/span&gt;[] { &lt;span class=&quot;kwrd&quot;&gt;new&lt;/span&gt; ModelClientValidationEqualToRule(ErrorMessage, System.Web.Mvc.CompareAttribute.FormatPropertyForClientValidation(Attribute.OtherProperty)) };&lt;/code&gt;&lt;/pre&gt;

  &lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;    }&lt;/code&gt;&lt;/pre&gt;

  &lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;}&lt;/code&gt;&lt;/pre&gt;

  &lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;&amp;#160;&lt;/code&gt;&lt;/pre&gt;

  &lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;&lt;span class=&quot;kwrd&quot;&gt;internal&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;class&lt;/span&gt; LocalisableAnnotationAdapterInitialiser&lt;/code&gt;&lt;/pre&gt;

  &lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;{&lt;/code&gt;&lt;/pre&gt;

  &lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;    &lt;span class=&quot;kwrd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;readonly&lt;/span&gt; LocalizationService LocalizationService = ServiceLocator.Current.GetInstance&amp;lt;LocalizationService&amp;gt;();&lt;/code&gt;&lt;/pre&gt;

  &lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;&amp;#160;&lt;/code&gt;&lt;/pre&gt;

  &lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;    &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;void&lt;/span&gt; Initialise(ModelMetadata metadata, ValidationAttribute attribute)&lt;/code&gt;&lt;/pre&gt;

  &lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;    {&lt;/code&gt;&lt;/pre&gt;

  &lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;        &lt;span class=&quot;kwrd&quot;&gt;object&lt;/span&gt; resourceKeyObj;&lt;/code&gt;&lt;/pre&gt;

  &lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;        &lt;span class=&quot;kwrd&quot;&gt;string&lt;/span&gt; resourceKey;&lt;/code&gt;&lt;/pre&gt;

  &lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;        &lt;span class=&quot;kwrd&quot;&gt;if&lt;/span&gt; (metadata.AdditionalValues.TryGetValue(attribute.GetHashCode().ToString(CultureInfo.InvariantCulture),&lt;/code&gt;&lt;/pre&gt;

  &lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;            &lt;span class=&quot;kwrd&quot;&gt;out&lt;/span&gt; resourceKeyObj)&lt;/code&gt;&lt;/pre&gt;

  &lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;            &amp;amp;&amp;amp; !&lt;span class=&quot;kwrd&quot;&gt;string&lt;/span&gt;.IsNullOrWhiteSpace(resourceKey = (&lt;span class=&quot;kwrd&quot;&gt;string&lt;/span&gt;)resourceKeyObj)&lt;/code&gt;&lt;/pre&gt;

  &lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;            &amp;amp;&amp;amp; resourceKey.StartsWith(&lt;span class=&quot;str&quot;&gt;&amp;quot;/&amp;quot;&lt;/span&gt;))&lt;/code&gt;&lt;/pre&gt;

  &lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;        {&lt;/code&gt;&lt;/pre&gt;

  &lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;            attribute.ErrorMessage = LocalizationService.GetString(resourceKey, resourceKey);&lt;/code&gt;&lt;/pre&gt;

  &lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;        }&lt;/code&gt;&lt;/pre&gt;

  &lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;    }&lt;/code&gt;&lt;/pre&gt;

  &lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;And here is our own extended implementation for &lt;em&gt;CachedDataAnnotationsModelMetadataProvider&lt;/em&gt;...&lt;/p&gt;

&lt;div class=&quot;csharpcode&quot;&gt;
  &lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;[ServiceConfiguration(&lt;span class=&quot;kwrd&quot;&gt;typeof&lt;/span&gt;(ModelMetadataProvider), Lifecycle = ServiceInstanceScope.Singleton)]&lt;/code&gt;&lt;/pre&gt;

  &lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;&lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;class&lt;/span&gt; LocalizableModelMetadataProvider : CachedDataAnnotationsModelMetadataProvider&lt;/code&gt;&lt;/pre&gt;

  &lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;{&lt;/code&gt;&lt;/pre&gt;

  &lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;   &lt;span class=&quot;kwrd&quot;&gt;protected&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;override&lt;/span&gt; CachedDataAnnotationsModelMetadata CreateMetadataFromPrototype(CachedDataAnnotationsModelMetadata prototype, Func&amp;lt;&lt;span class=&quot;kwrd&quot;&gt;object&lt;/span&gt;&amp;gt; modelAccessor)&lt;/code&gt;&lt;/pre&gt;

  &lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;   {&lt;/code&gt;&lt;/pre&gt;

  &lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;      var result = &lt;span class=&quot;kwrd&quot;&gt;base&lt;/span&gt;.CreateMetadataFromPrototype(prototype, modelAccessor);&lt;/code&gt;&lt;/pre&gt;

  &lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;      &lt;span class=&quot;kwrd&quot;&gt;foreach&lt;/span&gt; (var additionalValue &lt;span class=&quot;kwrd&quot;&gt;in&lt;/span&gt; prototype.AdditionalValues)&lt;/code&gt;&lt;/pre&gt;

  &lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;      {&lt;/code&gt;&lt;/pre&gt;

  &lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;         result.AdditionalValues.Add(additionalValue.Key, additionalValue.Value);&lt;/code&gt;&lt;/pre&gt;

  &lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;      }&lt;/code&gt;&lt;/pre&gt;

  &lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;      &lt;span class=&quot;kwrd&quot;&gt;return&lt;/span&gt; result;&lt;/code&gt;&lt;/pre&gt;

  &lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;   }&lt;/code&gt;&lt;/pre&gt;

  &lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;&amp;#160;&lt;/code&gt;&lt;/pre&gt;

  &lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;&lt;span class=&quot;kwrd&quot;&gt;   protected&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;override&lt;/span&gt; CachedDataAnnotationsModelMetadata CreateMetadataPrototype(IEnumerable&amp;lt;Attribute&amp;gt; attributes, Type containerType, Type modelType, &lt;span class=&quot;kwrd&quot;&gt;string&lt;/span&gt; propertyName)&lt;/code&gt;&lt;/pre&gt;

  &lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;&amp;#160;&amp;#160; {&lt;/code&gt;&lt;/pre&gt;

  &lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;   var theAttributes = attributes &lt;span class=&quot;kwrd&quot;&gt;as&lt;/span&gt; Attribute[] ?? attributes.ToArray();&lt;/code&gt;&lt;/pre&gt;

  &lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;   var prototype = &lt;span class=&quot;kwrd&quot;&gt;base&lt;/span&gt;.CreateMetadataPrototype(theAttributes, containerType, modelType, propertyName);&lt;/code&gt;&lt;/pre&gt;

  &lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;   &lt;span class=&quot;kwrd&quot;&gt;foreach&lt;/span&gt; (var a &lt;span class=&quot;kwrd&quot;&gt;in&lt;/span&gt; theAttributes.OfType&amp;lt;ValidationAttribute&amp;gt;()&lt;/code&gt;&lt;/pre&gt;

  &lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;         .Where(a =&amp;gt; !&lt;span class=&quot;kwrd&quot;&gt;string&lt;/span&gt;.IsNullOrWhiteSpace(a.ErrorMessage) &lt;/code&gt;&lt;/pre&gt;

  &lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;         &amp;amp;&amp;amp; a.ErrorMessage.StartsWith(&lt;span class=&quot;str&quot;&gt;&amp;quot;/&amp;quot;&lt;/span&gt;)))&lt;/code&gt;&lt;/pre&gt;

  &lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;      {&lt;/code&gt;&lt;/pre&gt;

  &lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;         prototype.AdditionalValues.Add(a.GetHashCode().ToString(CultureInfo.InvariantCulture), a.ErrorMessage);&lt;/code&gt;&lt;/pre&gt;

  &lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;      }&lt;/code&gt;&lt;/pre&gt;

  &lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;      &lt;span class=&quot;kwrd&quot;&gt;return&lt;/span&gt; prototype;&lt;/code&gt;&lt;/pre&gt;

  &lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;   }&lt;/code&gt;&lt;/pre&gt;

  &lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;Finally, a small EPiServer Initialization Module to register the Attribute Adapters with the ASP.Net run-time.&lt;/p&gt;

&lt;div class=&quot;csharpcode&quot;&gt;
  &lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;[InitializableModule]&lt;/code&gt;&lt;/pre&gt;

  &lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;[ModuleDependency(&lt;span class=&quot;kwrd&quot;&gt;typeof&lt;/span&gt; (InitializationModule))]&lt;/code&gt;&lt;/pre&gt;

  &lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;&lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;class&lt;/span&gt; DataAnnotationsModelValidatorInitialization : IInitializableModule&lt;/code&gt;&lt;/pre&gt;

  &lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;{&lt;/code&gt;&lt;/pre&gt;

  &lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;    &lt;span class=&quot;kwrd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;bool&lt;/span&gt; _initialized;&lt;/code&gt;&lt;/pre&gt;

  &lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;&amp;#160;&lt;/code&gt;&lt;/pre&gt;

  &lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;    &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;void&lt;/span&gt; Initialize(InitializationEngine context)&lt;/code&gt;&lt;/pre&gt;

  &lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;    {&lt;/code&gt;&lt;/pre&gt;

  &lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;        &lt;span class=&quot;kwrd&quot;&gt;if&lt;/span&gt; (_initialized)&lt;/code&gt;&lt;/pre&gt;

  &lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;        {&lt;/code&gt;&lt;/pre&gt;

  &lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;            &lt;span class=&quot;kwrd&quot;&gt;return&lt;/span&gt;;&lt;/code&gt;&lt;/pre&gt;

  &lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;        }&lt;/code&gt;&lt;/pre&gt;

  &lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;        LocalisableRequiredAnnotationsAdapter.SelfRegister();&lt;/code&gt;&lt;/pre&gt;

  &lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;        LocalisableStringLengthAnnotationsAdapter.SelfRegister();&lt;/code&gt;&lt;/pre&gt;

  &lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;        LocalisableEmailAddressAnnotationsAdapter.SelfRegister();&lt;/code&gt;&lt;/pre&gt;

  &lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;        LocalisableCompareAnnotationsAdapter.SelfRegister();&lt;/code&gt;&lt;/pre&gt;

  &lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;        _initialized = &lt;span class=&quot;kwrd&quot;&gt;true&lt;/span&gt;;&lt;/code&gt;&lt;/pre&gt;

  &lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;    }&lt;/code&gt;&lt;/pre&gt;

  &lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;&amp;#160;&lt;/code&gt;&lt;/pre&gt;

  &lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;    &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;void&lt;/span&gt; Uninitialize(InitializationEngine context)&lt;/code&gt;&lt;/pre&gt;

  &lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;    {  }&lt;/code&gt;&lt;/pre&gt;

  &lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;&amp;#160;&lt;/code&gt;&lt;/pre&gt;

  &lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;    &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;void&lt;/span&gt; Preload(&lt;span class=&quot;kwrd&quot;&gt;string&lt;/span&gt;[] parameters)&lt;/code&gt;&lt;/pre&gt;

  &lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;    {  }&lt;/code&gt;&lt;/pre&gt;

  &lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;We&#39;re done, except of course to create the Localization Resources, either in the form of an XML File read by the standard XML Localization Provider, or in the form required by whatever other Localization Provider you are using; maybe one similar to that suggested by &lt;a href=&quot;http://world.episerver.com/Blogs/Jeroen-Stemerdink/&quot;&gt;Jeroen Stemerdink&lt;/a&gt; on &lt;a href=&quot;https://jstemerdink.wordpress.com/2013/06/20/a-custom-localization-provider-for-episerver-7-2/&quot;&gt;his Blog&lt;/a&gt;.&lt;/p&gt;</id><updated>2014-03-11T17:12:00.0000000Z</updated><summary type="html">Blog post</summary></entry></feed>