title: Blazor WebAssembly Client DataAnnotations Localization
body: <p>Asp.net core server side localization is well documented and working for me. But how do you localize DataAnnotations on DTO models on the client side of Blazor webassembly?</p>
  <p>On server side I've added the code below and DataAnnotations are localized. Everything is working as expected.</p>
  <pre><code>...
  services
  .AddRazorPages()              .AddViewLocalization(Microsoft.AspNetCore.Mvc.Razor.LanguageViewLocationExpanderFormat.Suffix)
                  .AddDataAnnotationsLocalization(
                      options =&gt;
                      {
                          options.DataAnnotationLocalizerProvider = (type, factory) =&gt;
                          {
                              return factory.Create(typeof(CommonStrings));
                          };
  
                      });
  ...
  </code></pre>
  <p>But how do I do the same thing on Blazor client side (webassembly)?
  For example I have this model which is on client side:</p>
  <pre><code>public class ApplicationUserDTO
      {
          public string Id { get; set; }
  
          [Required(ErrorMessage =&quot;Field {0} is required&quot;)]
          [Display(Name =&quot;First name&quot;)]
          public string FirstName { get; set; }
  
          [Required]
          [Display(Name = &quot;Last name&quot;)]
          public string LastName { get; set; }
  
          [Required]
          [Display(Name = &quot;Email&quot;)]
          public string Email { get; set; }
  
          [Required]
          [Display(Name = &quot;Username&quot;)]
          public string Username { get; set; }
  
  
      }
  </code></pre>
  <p>I want to post it to backend via <code>&lt;EditForm&gt;</code> component, and before I do that do the validation on client side.
  I also want to localize it like i would on aspnet.core server - Error/validation messages and display names...</p>
  <p>I tried with LocalizedValidator component:</p>
  <pre><code>    public class MessageValidatorBase&lt;TValue&gt; : ComponentBase, IDisposable
      {
          private FieldIdentifier _fieldIdentifier;
          private EventHandler&lt;ValidationStateChangedEventArgs&gt; _stateChangedHandler
              =&gt; (sender, args) =&gt; StateHasChanged();
          [CascadingParameter]
          private EditContext EditContext { get; set; }
          [Parameter]
          public Expression&lt;Func&lt;TValue&gt;&gt; For { get; set; }
          [Parameter]
          public string Class { get; set; }
          protected IEnumerable&lt;string&gt; ValidationMessages =&gt;
              EditContext.GetValidationMessages(_fieldIdentifier);
          protected override void OnInitialized()
          {
              _fieldIdentifier = FieldIdentifier.Create(For);
              EditContext.OnValidationStateChanged += _stateChangedHandler;
          }
          public void Dispose()
          {
              EditContext.OnValidationStateChanged -= _stateChangedHandler;
          }
      }
  </code></pre>
  <p>and then created component:</p>
  <pre><code>@typeparam TValue
  @inherits MessageValidatorBase&lt;TValue&gt;
  @inject StringLocalizationService _localizer
  @foreach (var message in ValidationMessages)
  {
      &lt;div class=&quot;@Class&quot;&gt;
          @_localizer[message]
          
      &lt;/div&gt;
  }
  </code></pre>
  <p>but the problem is I get already expanded string here. For example if I have error message like this &quot;The field {0} is required&quot; I get &quot;The field First name is required&quot; which will not be localized since I don't have the resource with that key and I don't intend to translate the same error message for every property name...</p>
  <p>[EDIT]
  I just want to know if there is something trivial I didn't do instead of implementing it completely on my own</p>