[Abp vNext 源码分析] - 21. 界面与文字的本地化 (4)

对应的字典形式就是内部字典的 KEY:Value。

public class StaticLocalizationDictionary : ILocalizationDictionary { public string CultureName { get; } protected Dictionary<string, LocalizedString> Dictionary { get; } public StaticLocalizationDictionary(string cultureName, Dictionary<string, LocalizedString> dictionary) { CultureName = cultureName; Dictionary = dictionary; } public virtual LocalizedString GetOrNull(string name) { return Dictionary.GetOrDefault(name); } public void Fill(Dictionary<string, LocalizedString> dictionary) { foreach (var item in Dictionary) { dictionary[item.Key] = item.Value; } } }

当最外层的 Contributor 获取文本的时候,实际是结合区域文化信息(Culture Name) 定义到对应的本地化资源字典,再通过 Name 获取资源字典内部对应的 LocalizedString 对象。

2.3 同 Microsoft 本地化集成

2.2 节讲完了 ABP vNext 实现的基础设施,结合某个资源类型附带的 Contributor 组就能够获取到具体的本地化字符串数据,在本节主要讲解 ABP vNext 同 Microsoft 的集成。

2.3.1 IStringLocalizer 工厂

在 AbpLocalizationModule 模块中,第一句就是替换了默认的 String Localizer 工厂,并注入了 ResourceManagerStringLocalizerFactory 类型,这个类型主要用于后续的默认行为。

internal static void Replace(IServiceCollection services) { services.Replace(ServiceDescriptor.Singleton<IStringLocalizerFactory, AbpStringLocalizerFactory>()); services.AddSingleton<ResourceManagerStringLocalizerFactory>(); }

在 Microsoft 提供的 IStringLocalizerFactory 接口中,只定义了两个创建 IStringLocalizer 的方法。

public interface IStringLocalizerFactory { IStringLocalizer Create(Type resourceSource); IStringLocalizer Create(string baseName, string location); }

第二个方法 ABP 是直接调用的默认工厂(ResouceManagerStringLocalizerFactory) 提供的方法,而且还加了个 TODO 注明不知道什么时候会被调用。

public virtual IStringLocalizer Create(string baseName, string location) { //TODO: Investigate when this is called? return InnerFactory.Create(baseName, location); }

这里我们着重关注第一个方法,ABP 主要实现的也是第一个方法,它会根据传入的 resourceSource 参数从缓存当中获取(不存在则构造)对应的 IStringLocalizer 。如果在 ABP 提供的资源集合当中,没有查找到对应的 Type,则直接调用默认工厂返回 IStringLocalizer。如果存在则会以 Type 作为 Key,StringLocalizerCacheItem(就是 LocalizationResource 的马甲) 作为 Value,从缓存拿,没拿到就构建一个新的并加入到缓存中。

public virtual IStringLocalizer Create(Type resourceType) { var resource = AbpLocalizationOptions.Resources.GetOrDefault(resourceType); if (resource == null) { return InnerFactory.Create(resourceType); } if (LocalizerCache.TryGetValue(resourceType, out var cacheItem)) { return cacheItem.Localizer; } lock (LocalizerCache) { return LocalizerCache.GetOrAdd( resourceType, _ => CreateStringLocalizerCacheItem(resource) ).Localizer; } } private StringLocalizerCacheItem CreateStringLocalizerCacheItem(LocalizationResource resource) { // 构造时会将全局配置的 Contributor 添加到对应的组。 foreach (var globalContributor in AbpLocalizationOptions.GlobalContributors) { resource.Contributors.Add((ILocalizationResourceContributor) Activator.CreateInstance(globalContributor)); } using (var scope = ServiceProvider.CreateScope()) { var context = new LocalizationResourceInitializationContext(resource, scope.ServiceProvider); // 调用各个 Contributor 的初始化方法,进行初始化操作。 foreach (var contributor in resource.Contributors) { contributor.Initialize(context); } } return new StringLocalizerCacheItem( new AbpDictionaryBasedStringLocalizer( resource, resource.BaseResourceTypes.Select(Create).ToList() ) ); } 2.3.2 IStringLocalizer

ABP 针对 IStringLocalizer 的默认实现是 AbpDictionaryBasedStringLocalizer,IStringLocalizer 主要包含两个索引器和一个 GetAllStrings() 方法。

索引器本身直接就调用的 GetLocalizedString() 与 GetLocalizedStringFormatted() 方法。后者用于处理格式化的参数,内部就是利用的 string.Format() 方法替换占位符的内容。

public class AbpDictionaryBasedStringLocalizer : IStringLocalizer, IStringLocalizerSupportsInheritance { // ... 其他代码 public virtual LocalizedString this[string name] => GetLocalizedString(name); public virtual LocalizedString this[string name, params object[] arguments] => GetLocalizedStringFormatted(name, arguments); // ... 其他代码 protected virtual LocalizedString GetLocalizedString(string name) { return GetLocalizedString(name, CultureInfo.CurrentUICulture.Name); } protected virtual LocalizedString GetLocalizedString(string name, string cultureName) { var value = GetLocalizedStringOrNull(name, cultureName); // 如果没有从当前容器取得对应的本地化字符串,就从复用的基类中获取。 if (value == null) { foreach (var baseLocalizer in BaseLocalizers) { using (CultureHelper.Use(CultureInfo.GetCultureInfo(cultureName))) { var baseLocalizedString = baseLocalizer[name]; if (baseLocalizedString != null && !baseLocalizedString.ResourceNotFound) { return baseLocalizedString; } } } return new LocalizedString(name, name, resourceNotFound: true); } return value; } }

转到 GetLocalizedStringOrNull() 方法内部,可以看到获取本地化字符串的具体逻辑。

首先会从本地化资源定义的 Contributors 中获取本地化字符串。

如果没有找到则尝试从类似的区域文化信息字典中获取,例如 zh-Hans(简体中文) 源没有拿到则考虑从 zh-Hant(繁体中文)获取。

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wpzssf.html