本地化模块

ABP的本地化系统与Microsoft.Extensions.Localization无缝集成,并与AspnetCore的本地化文档兼容. 它添加了一些实用功能和增强功能, 使其更易于在实际开发中应用.

SupportedCultures 的 CultureInfo 对象决定了和文化相关的函数,如日期,时间,数字和货币格式的结果。 SupportedCultures 同时决定了文字如何排序,大小写转换以及字符串比较。参考CultureInfo.CurrentCulture 获取更多关于服务器如何获取文化的信息。SupportedUICultures 决定如何通过 ResourceManager 查找翻译字符串(从 .resx 文件)

Volo.Abp.Localization是本地化系统的核心包.本地化资源用于将相关的本地化字符串组合在一起,并将它们与应用程序的其他本地化字符串分开.通常一个模块会定义自己的本地化资源. 本地化资源就是一个普通的类.

注意虚拟文件的命名空间与路径,比如AbpValidation,它的命令空间是Volo.Abp.Localization.Resources.AbpValidation,

则options.FileSets.AddEmbedded<AbpLocalizationModule>("Volo.Abp", "Volo/Abp"),而在AddVirtualJson("/Localization/Resources/AbpValidation")

public class TestResource
{
}
[DependsOn(typeof(AbpLocalizationModule))]
public class MyModule : AbpModule
{
    public override void ConfigureServices(ServiceConfigurationContext context)
    {
        Configure<VirtualFileSystemOptions>(options =>
        {
            // "YourRootNameSpace" 是项目的根命名空间名字. 如果你的项目的根命名空间名字为空,则无需传递此参数.
            options.FileSets.AddEmbedded<MyModule>("YourRootNameSpace");
        });

        Configure<AbpLocalizationOptions>(options =>
        {
            options.Resources
                .Add<TestResource>("en")
                .AddVirtualJson("/Localization/Resources/Test");
        });
    }
}
  • 添加了一个新的本地化资源, 使用"en"(英语)作为默认的本地化.
  • 用JSON文件存储本地化字符串.
  • 使用虚拟文件系统 将JSON文件嵌入到程序集中
  •  
 
{
  "culture": "en",
  "texts": {
    "HelloWorld": "Hello World!"
  }
}
 
  • 每个本地化文件都需要定义 culture (文化) 代码 (例如 "en" 或 "en-US"). //zh-Hans
  • texts 部分只包含本地化字符串的键值集合 (键也可能有空格)
 
本地化资源也可以在客户端(JavaScript)使用. 因此, 为本地化资源设置一个简短的名称可以更方便的本地化文本. 例如 
[LocalizationResourceName("Test")]
public class TestResource
{
}

资源可以从其他资源继承,这使得可以在不引用现有资源的情况下重用现有的本地化字符串. 例如:[InheritResource(typeof(AbpValidationResource))]

也可以通过 AbpLocalizationOptions 配置: 

services.Configure<AbpLocalizationOptions>(options =>
{
    options.Resources
        .Add<TestResource>("en") //Define the resource by "en" default culture
        .AddVirtualJson("/Localization/Resources/Test") //Add strings from virtual json files
        .AddBaseTypes(typeof(AbpValidationResource)); //Inherit from an existing resource
});

资源可以从多个资源继承.如果新的本地化资源定义了相同的本地化字符串, 那么它会覆盖该字符串 

 

使用AbpStringLocalizerFactory替换了IStringLocalizerFactory,增加单例ResourceManagerStringLocalizerFactory,

虚拟文件定义,本地化配置文件

 

所以整个过程,通过AbpStringLocalizerFactory创建IStringLocalizer,Create(ResourceType)方法,根据这个ResourceType从AbpLocationOption中LocalizationResourceDictionary获取到LocationResource,IStringLocalizer是包装这个LocationResource,用到是LocationResource.Contributor,即JsonVirtualFileLocationResourceContributor去得到相应的语言的值

 

应用里要先对AbpLocationOption进行配置,首先是根据resourceType(自定义的类,可使用LocalizationResourceName、InheritResource扩展

在AbpLocalizationOptions.Resources.Add<ResourceType>(默认语言).AddVirtualJson(这个是sonContributor,虚拟文件路径)),增加到LocalizationResourceDictionary,它是管理LocationResource的列表,三个方法 Add<TResouce>(默认语言),AddVirtualJson(),AddBaseTypes

LocationResource的属性,

1、ResourceType,在资源文件里新建的类,可加上Attributor可以LocalizationResourceName(), InheritResource(typeof(另一个资源类))

2、ResourceName》从LocalizationResourceNameAttribute

3、DefaultCultureName:上面Option方法new要传进来,后续的作用是?如果当前的线程的CultureInfo找不到这个值,则使用这个

4、BaseResourceTypes:来自InheritResourceAttribute,用于遍历,如果当前找不到,就遍历找InheritResource的type

5、Contributor List<ILocalizationResourceContributor>: 获取对应的值实现由它要提供,即LocationResource.Contributor.GetOrNull(),只要遍历到一个就返回,实现使用是JsonVirtualFileLocalizationResourceContributor,它扩展

AbpLocationOption有一个全局的Contributor,这个增加到上面LocaionResource.Contributor里面去。

在Volo.Abp.AspNetCore.Mvc.Client添加 一个GlobalContributors是RemoteLocalizationContributor,

  

从工厂Create出来的IStringLocalizer<ResourceType>是AbpDictionaryBasedStringLocalizer,

首先是AbpLocalizationOptions.Add方法是增加到Resources,LocationResources列表,返回在这个ResourceType的LocaltionResource,再AddVirtualJson是增加到LocationResources的贡献者(Contributes)里面,AddBaseTypes是增加到BaseResourceType里面。 同在Location的初始化的时候,已经将InheritResource作为baseresourceType的增加进去了

查找到这个前面Add这个Resource里面对应的LocationResource,找不到就使用原来的ResourceManagerStringLocalizerFactory。

使用ABP,其中要使用的AbpDictionaryBasedStringLocalizer,也要连带List<IStringLocalizer> baseLocalizers

索引获取方法

public virtual LocalizedString this[string name] => GetLocalizedString(name); protected virtual LocalizedString GetLocalizedString(string name) { return GetLocalizedString(name, CultureInfo.CurrentUICulture.Name); /当前线程的CultureInfo }

IStringLocalizer<ResourceType> 的GetLocalizedString(“字符串”)的方法

它是使用此ResourceType的LocationResource,先使用contributor(这个是JsonVirtualFileLocalizationResourceContributor,读取虚拟文件值,增加到字典里),再从BaseLocationResourceType添加进去

这个存储的数据结构是Dictionary<string, ILocalizationDictionary>,其中key的索引是cultureCode,而ILocalizationDictionary是StaticLocalizationDictionary(特定语言)

再根据当前语言值,获取到StaticLocalizationDictionary,再获取对应值LocalizedString

dictionary[item.Key] = new LocalizedString(item.Key, item.Value.NormalizeLineEndings());

 

若GetAllStrings(语言,是否包含默认语言,是否包含基类)

 在AbpApplicationConfigurationController,控制器,[Route("api/abp/application-configuration")],对所有Location进行配置

protected virtual async Task<ApplicationLocalizationConfigurationDto> GetLocalizationConfigAsync()
        {
            var localizationConfig = new ApplicationLocalizationConfigurationDto();
            localizationConfig.Languages.AddRange(await _languageProvider.GetLanguagesAsync());
            foreach (var resource in _localizationOptions.Resources.Values) //所有的Resources
            {
                var dictionary = new Dictionary<string, string>();
                var localizer = _serviceProvider.GetRequiredService(
                    typeof(IStringLocalizer<>).MakeGenericType(resource.ResourceType)
                ) as IStringLocalizer;
                foreach (var localizedString in localizer.GetAllStrings())
                {
                    dictionary[localizedString.Name] = localizedString.Value;
                }
                localizationConfig.Values[resource.ResourceName] = dictionary;
            }
            localizationConfig.CurrentCulture = GetCurrentCultureInfo();
            return localizationConfig;
        }

 模块的定义

[DependsOn(
        typeof(AbpVirtualFileSystemModule),
        typeof(AbpSettingsModule),
        typeof(AbpLocalizationAbstractionsModule)
        )]
    public class AbpLocalizationModule : AbpModule
    {
        public override void ConfigureServices(ServiceConfigurationContext context)
        {
            AbpStringLocalizerFactory.Replace(context.Services);

            Configure<VirtualFileSystemOptions>(options =>
            {
                options.FileSets.AddEmbedded<AbpLocalizationModule>("Volo.Abp", "Volo/Abp");
            });

            Configure<AbpLocalizationOptions>(options =>
            {
                options
                    .Resources
                    .Add<DefaultResource>("en");

                options
                    .Resources
                    .Add<AbpValidationResource>("en")
                    .AddVirtualJson("/Localization/Resources/AbpValidation");
            });
        }
    }

 配置Options有三个集合,本地化资源LocalizationResource,本地化资源贡献者ILocalizationResourceContributor,语言种类LanguageInfo

 public class AbpLocalizationOptions
    {
        public LocalizationResourceDictionary Resources { get; }

        public ITypeList<ILocalizationResourceContributor> GlobalContributors { get; }

        public List<LanguageInfo> Languages { get; }

        public AbpLocalizationOptions()
        {
            Resources = new LocalizationResourceDictionary();
            GlobalContributors = new TypeList<ILocalizationResourceContributor>();
            Languages = new List<LanguageInfo>();
        }
    }

AbpCultureHelper.Use,设置当前的语言,同设置租户功能差不多,可以自定义当前线程的CultureInfo和CurrentUICulture,而不用通过中间件进行设置

public static IDisposable Use([NotNull] CultureInfo culture, CultureInfo uiCulture = null)
        {
            Check.NotNull(culture, nameof(culture));

            var currentCulture = CultureInfo.CurrentCulture;
            var currentUiCulture = CultureInfo.CurrentUICulture;

            CultureInfo.CurrentCulture = culture;
            CultureInfo.CurrentUICulture = uiCulture ?? culture;

            return new DisposeAction(() =>
            {
                CultureInfo.CurrentCulture = currentCulture;
                CultureInfo.CurrentUICulture = currentUiCulture;
            });
        }

2、获取本地化文本,在服务端获取本地化文本的用法是非常标准的(它与AspNetCore提供的获取本地化资源方式无缝集成).

本地化字符串访问器IStringLocalizer<T>,IStringLocalizer 是一个实现了 IEnumerable 的简单接口并且拥有索引器来来返回本地化的字符串。

AbpDictionaryBasedStringLocalizer,如_localizer["About Title"] 没有发现 “About Title” 的本地化值,则索引的键值被返回

 

3、中间件

https://github.com/aspnet/AspNetCore/blob/e9179bacd7f997a51f9619511985671e0c131a11/src/Middleware/Localization/src/RequestLocalizationMiddleware.cs

 RequestLocalizationOptions:

Abp赋值了DefaultRequestCulture,SupportedCultures,SupportedUICultures,并且增加Action<RequestLocalizationOptions> optionsAction 委托

DefaultRequestCulture是默认的cultureName、uiCultureName  ,ABP定义是从SettingProviders中获取得到,GetLanguages

 List<IRequestCultureProvider> RequestCultureProviders,如果有设置,则根据这个是设置当前Culture。默认顺序QueryStringRequestCultureProvider、CookieRequestCultureProvider、AcceptLanguageHeaderRequestCultureProvider

await provider.DetermineProviderCultureResult(context)  返回地的 ProviderCultureResult,即是List<StringSegment> cultures UIcultures

目的首先将Culture和UICulture写入当前线程,将Context.Features.设置请求CultureFeature,设置是否将当前Culture返回给客户端,HeaderName.ContentLanguage

NET 的每个线程都会拥有 CurrentCulture 和CurrentUICulture 对象

 

 

FixedLocalizableString

public class FixedLocalizableString : ILocalizableString
    {
        public string Value { get; }

        public FixedLocalizableString(string value)
        {
            Value = value;
        }

        public LocalizedString Localize(IStringLocalizerFactory stringLocalizerFactory)
        {
            return new LocalizedString(Value, Value);
        }
    }

 

客户端:ABP提供了JavaScript服务, 可以在客户端使用相同的本地化文本. 

var testResource = abp.localization.getResource('Test');
var str = testResource('HelloWorld');

posted on 2019-07-12 11:40  dollymi  阅读(1026)  评论(0编辑  收藏  举报

导航