Localization Blazor WebAssembly客户端数据注释本地化

Localization Blazor WebAssembly客户端数据注释本地化,localization,client,blazor,data-annotations,webassembly,Localization,Client,Blazor,Data Annotations,Webassembly,Asp.net核心服务器端本地化有很好的文档记录,适合我。但是如何在Blazor webassembly的客户端上本地化DTO模型上的数据注释呢 在服务器端,我添加了下面的代码,并本地化了DataAnnotation。一切正常 ... services .AddRazorPages() .AddViewLocalization(Microsoft.AspNetCore.Mvc.Razor.LanguageViewLocationExpanderFormat.Suffix

Asp.net核心服务器端本地化有很好的文档记录,适合我。但是如何在Blazor webassembly的客户端上本地化DTO模型上的数据注释呢

在服务器端,我添加了下面的代码,并本地化了DataAnnotation。一切正常

...
services
.AddRazorPages()              .AddViewLocalization(Microsoft.AspNetCore.Mvc.Razor.LanguageViewLocationExpanderFormat.Suffix)
                .AddDataAnnotationsLocalization(
                    options =>
                    {
                        options.DataAnnotationLocalizerProvider = (type, factory) =>
                        {
                            return factory.Create(typeof(CommonStrings));
                        };

                    });
...
但是我如何在Blazor客户端(webassembly)上做同样的事情呢? 例如,我有一个位于客户端的模型:

public class ApplicationUserDTO
    {
        public string Id { get; set; }

        [Required(ErrorMessage ="Field {0} is required")]
        [Display(Name ="First name")]
        public string FirstName { get; set; }

        [Required]
        [Display(Name = "Last name")]
        public string LastName { get; set; }

        [Required]
        [Display(Name = "Email")]
        public string Email { get; set; }

        [Required]
        [Display(Name = "Username")]
        public string Username { get; set; }


    }
我想通过
组件将其发布到后端,然后在客户端进行验证。 我还想像在aspnet.core服务器上一样对其进行本地化-错误/验证消息和显示名称

我尝试使用LocalizedValidator组件:

    public class MessageValidatorBase<TValue> : ComponentBase, IDisposable
    {
        private FieldIdentifier _fieldIdentifier;
        private EventHandler<ValidationStateChangedEventArgs> _stateChangedHandler
            => (sender, args) => StateHasChanged();
        [CascadingParameter]
        private EditContext EditContext { get; set; }
        [Parameter]
        public Expression<Func<TValue>> For { get; set; }
        [Parameter]
        public string Class { get; set; }
        protected IEnumerable<string> ValidationMessages =>
            EditContext.GetValidationMessages(_fieldIdentifier);
        protected override void OnInitialized()
        {
            _fieldIdentifier = FieldIdentifier.Create(For);
            EditContext.OnValidationStateChanged += _stateChangedHandler;
        }
        public void Dispose()
        {
            EditContext.OnValidationStateChanged -= _stateChangedHandler;
        }
    }
@typeparam TValue
@inherits MessageValidatorBase<TValue>
@inject StringLocalizationService _localizer
@foreach (var message in ValidationMessages)
{
    <div class="@Class">
        @_localizer[message]
        
    </div>
}
公共类MessageValidatorBase:ComponentBase,IDisposable { 专用字段标识符_FieldIdentifier; 私有事件处理程序\u stateChangedHandler =>(发送方,参数)=>状态已更改(); [CascadingParameter] 私有EditContext EditContext{get;set;} [参数] {get;set;}的公共表达式 [参数] 公共字符串类{get;set;} 受保护的IEnumerable ValidationMessages=> EditContext.GetValidationMessages(_fieldIdentifier); 受保护的覆盖无效OnInitialized() { _fieldIdentifier=fieldIdentifier.Create(For); EditContext.OnValidationStateChanged+=\u stateChangedHandler; } 公共空间处置() { EditContext.OnValidationStateChanged-=\u stateChangedHandler; } } 然后创建组件:

    public class MessageValidatorBase<TValue> : ComponentBase, IDisposable
    {
        private FieldIdentifier _fieldIdentifier;
        private EventHandler<ValidationStateChangedEventArgs> _stateChangedHandler
            => (sender, args) => StateHasChanged();
        [CascadingParameter]
        private EditContext EditContext { get; set; }
        [Parameter]
        public Expression<Func<TValue>> For { get; set; }
        [Parameter]
        public string Class { get; set; }
        protected IEnumerable<string> ValidationMessages =>
            EditContext.GetValidationMessages(_fieldIdentifier);
        protected override void OnInitialized()
        {
            _fieldIdentifier = FieldIdentifier.Create(For);
            EditContext.OnValidationStateChanged += _stateChangedHandler;
        }
        public void Dispose()
        {
            EditContext.OnValidationStateChanged -= _stateChangedHandler;
        }
    }
@typeparam TValue
@inherits MessageValidatorBase<TValue>
@inject StringLocalizationService _localizer
@foreach (var message in ValidationMessages)
{
    <div class="@Class">
        @_localizer[message]
        
    </div>
}
@typeparam TValue
@继承MessageValidatorBase
@注入StringLocalizationService\u定位器
@foreach(ValidationMessages中的var消息)
{
@_定位器[信息]
}
但问题是我已经在这里得到了扩展字符串。例如,如果我有这样的错误消息“字段{0}是必需的”我得到“字段名是必需的”,这将不会本地化,因为我没有具有该键的资源,并且我不打算为每个属性名翻译相同的错误消息

[编辑] 我只是想知道是否有一些琐碎的事情我没有做,而是完全在我自己的

WebAssembly示例中实现了它。 示例属性 在客户端中创建一个名为Resources的文件夹。 为每种语言添加一个“.resx”文件,外加一个默认值(无语言)

确保将访问修饰符设置为
Public

法语输出示例。

我认为可能有一种方法可以像使用ui-with.resx文件一样使用本地化。这是否回答了您的问题@Quango我不想接受这个答案,因为它清楚地表明了“服务器端”,这是关于客户端的side@Darftagan那不会是一个好主意difference@Quango这可能会让以后阅读本文的人感到困惑。我只想补充一点,若要本地化DisplayAttribute,必须避免在Name属性中使用空格。我有“First name”,我收到错误“无法检索属性'name',因为本地化失败。键入'Resources.Resource'不是公共的…”即使它是公共的并且“First name”键存在,但只要我有了“FirstName”,一切就开始工作了…@Darftagan这是将资源设置为公共的结果,这还指示编译器生成静态类。当然,属性名称不能包含空格。为了解决这个问题,我使用一个单独的
.resx
文件进行数据注释。我同意。我刚才提到了它,以防有人拥有具有空格的密钥的资源。