@Tseng,抱歉,我应该说得更清楚,我的意思是我们应该使用命名约定或共享资源。但不是两者兼而有之,我在很多情况下都有很多共享资源和许多特定于 ViewModel 的字符串(所以是混合的)。这是 .Net Core 本地化解决方案无法实现的。
如果您唯一担心的是您能否确定是否选择一个或多个资源文件,则可以轻松配置。我不得不深入研究一下源代码,这似乎是可能的。
正如我们所看到的here the localizer
由配置中定义的工厂决定
if (_stringLocalizerFactory != null && _localizationOptions.DataAnnotationLocalizerProvider != null)
{
localizer = _localizationOptions.DataAnnotationLocalizerProvider(containerType, _stringLocalizerFactory);
}
whereas _localizationOptions
is MvcDataAnnotationsLocalizationOptions
.
默认实现MvcDataAnnotationsLocalizationOptions
is here:
/// <inheritdoc />
public void Configure(MvcDataAnnotationsLocalizationOptions options)
{
if (options == null)
{
throw new ArgumentNullException(nameof(options));
}
options.DataAnnotationLocalizerProvider = (modelType, stringLocalizerFactory) =>
stringLocalizerFactory.Create(modelType);
}
因此它默认使用每个模型的资源。
你可以将其更改为SharedResource
如果您愿意,可以保存所有数据注释的文件,并在您的文件中包含以下内容Startup.ConfigureServices
(未经测试,但应该有效):
services.AddMvc()
.AddDataAnnotationsLocalization(options =>
{
options.DataAnnotationLocalizerProvider = (type, factory) =>
factory.Create(typeof(SharedResource));
});
这将有效地忽略传递的类型并始终返回共享字符串本地化程序。
当然,您可以在其中添加任何逻辑,并根据每种类型的情况决定要使用哪个本地化程序。
Edit
如果这还不够,您可以实现自己的自定义IDisplayMetadataProvider
它按照你想要的方式处理它。但使用DisplayAttribute
实际上应该足够了。DisplayAttribute
有额外的参数允许您定义资源类型。
[Display(Name = "StringToLocalize", ResourceType = typeof(SharedResource))]
随着ResourceType
您可以选择用于查找本地化的类(以及资源文件名)。
编辑2:使用包裹IStringLocalizer
回退到每个视图模型资源
更优雅的解决方案涉及使用上面的MvcDataAnnotationsLocalizationOptions
选项文件返回您自己的IStringLocalizer
它会查看一个资源文件并返回到另一个资源文件。
public class DataAnnotationStringLocalizer : IStringLocalizer
{
private readonly IStringLocalizer primaryLocalizer;
private readonly IStringLocalizer fallbackLocalizer;
public DataAnnotationStringLocalizer(IStringLocalizer primaryLocalizer, IStringLocalizer fallbackLocalizer)
{
this.primaryLocalizer = primaryLocalizer ?? throw new ArgumentNullException(nameof(primaryLocalizer));
this.fallbackLocalizer = fallbackLocalizer ?? throw new ArgumentNullException(nameof(fallbackLocalizer));
}
public LocalizedString this[string name]
{
get
{
LocalizedString localizedString = primaryLocalizer[name];
if (localizedString.ResourceNotFound)
{
localizedString = fallbackLocalizer[name];
}
return localizedString;
}
}
public LocalizedString this[string name, params object[] arguments]
{
get
{
LocalizedString localizedString = primaryLocalizer[name, arguments];
if (localizedString.ResourceNotFound)
{
localizedString = fallbackLocalizer[name, arguments];
}
return localizedString;
}
}
public IEnumerable<LocalizedString> GetAllStrings(bool includeParentCultures)
=> primaryLocalizer.GetAllStrings(includeParentCultures).Concat(fallbackLocalizer.GetAllStrings(includeParentCultures));
public IStringLocalizer WithCulture(CultureInfo culture)
=> new DataAnnotationStringLocalizer(primaryLocalizer.WithCulture(culture), fallbackLocalizer.WithCulture(culture));
}
并有以下选项
services.AddMvc()
.AddDataAnnotationsLocalization(options =>
{
options.DataAnnotationLocalizerProvider = (type, factory) =>
{
return new DataAnnotationStringLocalizer(
factory?.Create(typeof(SharedResource)),
factory?.Create(type)
);
};
});
现在,首先从共享资源解析该字符串,如果在那里找不到该字符串,它将从视图模型类型(传递给工厂方法的类型参数)解析它。
如果您不喜欢该逻辑并且希望它首先查看视图模型资源文件,则只需将顺序更改为
services.AddMvc()
.AddDataAnnotationsLocalization(options =>
{
options.DataAnnotationLocalizerProvider = (type, factory) =>
{
return new DataAnnotationStringLocalizer(
factory?.Create(type),
factory?.Create(typeof(SharedResource))
);
}
});
现在,视图模型是主要解析器,共享资源是辅助解析器