可以看到在下述代码当中,ABP vNext 会扫描当前 ResouceType 的特性,并将其定义的复用类型添加到基类集合当中。
public class LocalizationResource { [NotNull] public Type ResourceType { get; } [NotNull] public string ResourceName => LocalizationResourceNameAttribute.GetName(ResourceType); [CanBeNull] public string DefaultCultureName { get; set; } [NotNull] public LocalizationResourceContributorList Contributors { get; } [NotNull] public List<Type> BaseResourceTypes { get; } public LocalizationResource( [NotNull] Type resourceType, [CanBeNull] string defaultCultureName = null, [CanBeNull] ILocalizationResourceContributor initialContributor = null) { ResourceType = Check.NotNull(resourceType, nameof(resourceType)); DefaultCultureName = defaultCultureName; BaseResourceTypes = new List<Type>(); Contributors = new LocalizationResourceContributorList(); if (initialContributor != null) { Contributors.Add(initialContributor); } AddBaseResourceTypes(); } protected virtual void AddBaseResourceTypes() { var descriptors = ResourceType .GetCustomAttributes(true) .OfType<IInheritedResourceTypesProvider>(); foreach (var descriptor in descriptors) { foreach (var baseResourceType in descriptor.GetInheritedResourceTypes()) { BaseResourceTypes.AddIfNotContains(baseResourceType); } } } }当资源类型(Resource Type) 定义好之后,通过上面的一番操作,就能够得到一个 LocalizationResource 实例,并将其添加到了 AbpLocalizationOptions 内的 LocalizationResourceDictionary 对象。开发人员定义了多少个本地化资源类型,就会往这个字典添加多少个 LocaliztaionResource 实例。
2.2.4 本地化的数据源不论是配置项还是某个本地化资源定义类,都会存储一组 Contributor 。转到对应的接口定义,这个接口定义了三个公开方法,分别用于初始化(Initialize())、获取某个具体的本地化字符串(LocalizedString())、为指定的字典填充本地化资源数据(Fill())。
public interface ILocalizationResourceContributor { void Initialize(LocalizationResourceInitializationContext context); LocalizedString GetOrNull(string cultureName, string name); void Fill(string cultureName, Dictionary<string, LocalizedString> dictionary); }所有的数据源都是由各个 Contributor 提供的,这里以 VirtualFileLocalizationResourceContributorBase 为例,在内部通过虚拟文件系统获取到了文件数据,通过文件数据构造一系列的字典。这里的 字典有两层,第一层的 Key 是区域文化信息,Value 是对应区域文化信息的本地化字符串字典。第二层的 Key 是本地化字符串的标识,Value 就是具体的 LocalizedString 实例。
public abstract class VirtualFileLocalizationResourceContributorBase : ILocalizationResourceContributor { // ... 其他代码 public void Initialize(LocalizationResourceInitializationContext context) { _virtualFileProvider = context.ServiceProvider.GetRequiredService<IVirtualFileProvider>(); } public LocalizedString GetOrNull(string cultureName, string name) { return GetDictionaries().GetOrDefault(cultureName)?.GetOrNull(name); } public void Fill(string cultureName, Dictionary<string, LocalizedString> dictionary) { GetDictionaries().GetOrDefault(cultureName)?.Fill(dictionary); } private Dictionary<string, ILocalizationDictionary> GetDictionaries() { // ... 获取本地化资源的字典,这里的字典按区域文化进行分组。 } private Dictionary<string, ILocalizationDictionary> CreateDictionaries() { var dictionaries = new Dictionary<string, ILocalizationDictionary>(); foreach (var file in _virtualFileProvider.GetDirectoryContents(_virtualPath)) { // ... 其他代码。 // 根据文件创建某个区域文化的具体的数据源字典。 var dictionary = CreateDictionaryFromFile(file); if (dictionaries.ContainsKey(dictionary.CultureName)) { throw new AbpException($"{file.GetVirtualOrPhysicalPathOrNull()} dictionary has a culture name '{dictionary.CultureName}' which is already defined!"); } dictionaries[dictionary.CultureName] = dictionary; } return dictionaries; } protected abstract bool CanParseFile(IFileInfo file); protected virtual ILocalizationDictionary CreateDictionaryFromFile(IFileInfo file) { using (var stream = file.CreateReadStream()) { return CreateDictionaryFromFileContent(Utf8Helper.ReadStringFromStream(stream)); } } protected abstract ILocalizationDictionary CreateDictionaryFromFileContent(string fileContent); } 2.2.5 本地化资源字典具体存储本地化字符串标识和展示文本的对象是 ILocalizationDictionary,它的具体实现是 StaticLocalizationDictionary,在其内部有一个 Dictionary<string, LocalizedString> 字典,这个字典就对应的 JSON 文件当中的本地化数据了。
{ "culture": "zh-Hans", "texts": { "DisplayName:Abp.Localization.DefaultLanguage": "默认语言", "Description:Abp.Localization.DefaultLanguage": "应用程序的默认语言." } }