@Tseng,抱歉我当时没有说清楚,我的意思是我们应该使用命名约定或共享资源文件,但不能同时使用。在许多情况下,我有很多共享资源和许多ViewModel特定的字符串(混合使用)。这在.NET Core本地化解决方案中是不可行的。
如果你的唯一担忧是无法确定选择了一个或多个资源文件,那么这可以很容易地配置。我不得不深入挖掘源代码,但它似乎是可能的。
正如我们所见
这里,
localizer
是由配置中定义的工厂决定的。
if (_stringLocalizerFactory != null && _localizationOptions.DataAnnotationLocalizerProvider != null)
{
localizer = _localizationOptions.DataAnnotationLocalizerProvider(containerType, _stringLocalizerFactory);
}
而_localizationOptions
是MvcDataAnnotationsLocalizationOptions
。
MvcDataAnnotationsLocalizationOptions
的默认实现在这里:
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));
});
这将有效地忽略传递的类型并始终返回共享字符串本地化程序。
当然,您可以添加任何逻辑,并在每种类型的情况下决定要使用哪个本地化程序。
编辑
如果这还不够,您可以实现自己的自定义IDisplayMetadataProvider
,以您想要的方式处理它。但实际上使用 DisplayAttribute
就足够了。 DisplayAttribute
有其他参数,允许您定义资源类型。
[Display(Name = "StringToLocalize", ResourceType = typeof(SharedResource))]
使用
ResourceType
,您可以选择用于查找本地化的类(因此也是资源文件名)。
编辑2:使用包装的
IStringLocalizer
,并回退到每个视图模型资源
更优雅的解决方案涉及使用上述
MvcDataAnnotationsLocalizationOptions
选项文件返回自己的
IStringLocalizer
,该
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))
);
}
});
现在视图模型是主要的解析器,共享资源是次要的。
DisplayName
。 - Mohammed NoureldinIDisplayMetadataProvider
的默认实现来完成此操作。这里是去年关于DisplayNameAttribute
的最简示例,但您可以在其中选择要使用的类/资源文件。 - Tseng