具体的实现模块逻辑也不复杂,首先替换了默认的本地化资源容器工厂。接着往 ABP 的虚拟文件系统添加了当前模块,以便后续访问对应的 JSON 文件,最后往本地化的相关配置项添加了两个本地化资源。
public class AbpLocalizationModule : AbpModule { public override void ConfigureServices(ServiceConfigurationContext context) { AbpStringLocalizerFactory.Replace(context.Services); Configure<AbpVirtualFileSystemOptions>(options => { options.FileSets.AddEmbedded<AbpLocalizationModule>("Volo.Abp", "Volo/Abp"); }); Configure<AbpLocalizationOptions>(options => { options .Resources .Add<DefaultResource>("en"); options .Resources .Add<AbpLocalizationResource>("en") .AddVirtualJson("/Localization/Resources/AbpLocalization"); }); } } 2.2.2 本地化的配置AbpLocalizationOptions 内部定义了本地化系统的相关参数,主要由资源集合(Resources)、默认资源(DefaultResourceType)、全局的本地化数据源提供者(GlobalContributors)、支持的语言(Languages)。
注意:
当进行本地化操作时,没有指定资源类型的时候会使用默认资源类型。
public class AbpLocalizationOptions { public LocalizationResourceDictionary Resources { get; } public Type DefaultResourceType { get; set; } public ITypeList<ILocalizationResourceContributor> GlobalContributors { get; } public List<LanguageInfo> Languages { get; } public Dictionary<string, List<NameValue>> LanguagesMap { get; } public Dictionary<string, List<NameValue>> LanguageFilesMap { get; } public AbpLocalizationOptions() { Resources = new LocalizationResourceDictionary(); GlobalContributors = new TypeList<ILocalizationResourceContributor>(); Languages = new List<LanguageInfo>(); LanguagesMap = new Dictionary<string, List<NameValue>>(); LanguageFilesMap = new Dictionary<string, List<NameValue>>(); } }从上述代码我们可以知道,要让本地化系统正常工作,我们会接触到下面这几个类型 LocalizationResourceDictionary、LocalizationResource、ILocalizationResourceContributor、LanguageInfo。
2.2.3 本地化资源的定义在使用本地化系统的时候,ABP vNext 文档首先会让我们定义一个类型,并在模块的 ConfigureService() 周期,通过配置项添加到本地化系统当中,就像这样。
Configure<AbpLocalizationOptions>(options => { options.Resources .Add<DataDictionaryResource>("en") .AddVirtualJson("/Localization/Resources"); });这里可以看到,ABP vNext 实现了一套流畅方法(Fluent Method),通过这一系列的操作,我们会生成一个 LocalizationResource 实例,添加到配置系统当中,以便后续进行使用。
这里的 Add() 方法是由 LocalizationResourceDictionary 提供的,它本质上就是一个字典,只不过由 ABP vNext 封装了一些自定义的方法,方便添加字典项数据。可以看到它的实现也很简单,首先判断字典是否存在对应的 Key,如果不存在就使用资源类型和区域文化信息构造一个新的 LocalizationResource 对象,并将其添加到字典当中。
public class LocalizationResourceDictionary : Dictionary<Type, LocalizationResource> { public LocalizationResource Add<TResouce>([CanBeNull] string defaultCultureName = null) { return Add(typeof(TResouce), defaultCultureName); } public LocalizationResource Add(Type resourceType, [CanBeNull] string defaultCultureName = null) { if (ContainsKey(resourceType)) { throw new AbpException("This resource is already added before: " + resourceType.AssemblyQualifiedName); } return this[resourceType] = new LocalizationResource(resourceType, defaultCultureName); } // ... 其他代码。 }转到 LocalizationResouce 的定义,内部存储了具体的资源类型、资源名称、当前资源默认的区域文化信息、本地化数据源提供者(与全局的不同,这里仅作用于某个具体本地化资源)、继承的基类资源类型集合。
资源类型和资源名称用于区分不同的本地化资源。默认区域文化信息代表当前资源,当获取指定语言的本地化字符串失败时,会读取默认的区域文化信息对应的本地化字符串。
这里的 BaseResouceTypes 是为了复用其他资源的本地化字符串,例如你定义了一个 AppleResouceType,但是你想要获取 FruitResouceType 对应的字符串,那么就需要往这个集合添加需要服用的资源类型。ABP vNext 为 LocalizationResource 提供了一个扩展方法 AddBaseTypes() 便于在模块配置时添加需要复用的类型。除此之外 ABP vNext 也提供了特性支持,跟模块定义一样,在类定义上面添加 InheritResourceAttribute 特性,传入需要复用的类型定义即可。
[InheritResource( typeof(LocalizationTestValidationResource), typeof(LocalizationTestCountryNamesResource) )] public sealed class LocalizationTestResource { }