• asp.net core 之多语言国际化自定义资源文件


    先说说 asp.net core 默认的多语言和国际化。 官方文档

    一:基本使用方法

    先要安装 包 Microsoft.AspNetCore.Mvc.Localization (依赖 Microsoft.Extensions.Localization)  然后使用 资源文件保存不同的语言对应的数据。

    1,在视图页面注入 IViewLocalizer ,然后在需要的地方使用即可。 比如:

    1 @inject IViewLocalizer Localizer
    2 
    3 <h2>@Localizer["hello"]</h2>

    其中 中括号中的字符 即是资源文件中的名称, 运行后,输出的即是 当前语言对应的资源文件下的设置的资源值。

    那么有个问题来了,资源文件怎么设置?

    1,默认情况下会去查找 设置的 LocalizationOptions.ResourcesPath  的值对应的文件夹,如果没有设置,则去根目录下查找。

    在 Startup 中设置 ResourcesPath  。

    services.AddLocalization(options => options.ResourcesPath = "Resources");

    2,查找当前视图文件对应的同名资源文件。 默认支持 使用 点 . 和路径 path 查找两种方式,当然也可以指定其中一个方式。 比如 当前视图路径是 views/account/login.cshtml ,那么 查找的资源文件是  views/account/login.{CultureName}.resx 文件和 views.account.login.{CultureName}.resx 文件 

    services.AddMvc()
             .AddViewLocalization()
              //.AddViewLocalization(Microsoft.AspNetCore.Mvc.Razor.LanguageViewLocationExpanderFormat.SubFolder)
              .AddDataAnnotationsLocalization();

    3,如果是 model 类, 查找的路径则变成了model 类对应的命名空间即typeof(model).FullName 全路径。比如 ViewModels/account/login.{CultureName}.resx 文件和 ViewModels.account.login.{CultureName}.resx 文件 。同理 如果是在controller  那么,资源文件 则是  Controllers.HomeController.{CultureName}.resx 或者 Controllers/HomeController.{CultureName}.resx


    二:解析

    那么这个是如何实现的呢?如果我想使用 数据库或者是 json 文件来存在这些资源文件。

    在试图文件中 注入的是 IViewLocalizer 接口,对应的实现是  ViewLocalizer 。ViewLocalizer 实现了IViewLocalizer 和IHtmlLocalizer 的定义,并且 IViewLocalizer 继承自IHtmlLocalizer。  ViewLocalizer 会注入一个IHtmlLocalizerFactory,然后 用 IHtmlLocalizerFactory创建一个 IHtmlLocalizer 对应的实例。 在创建的时候 会带入两个参数 ,一个是 当前 试图的路径,一个是当前应用名称。 

    IHtmlLocalizer 定义如下:

    所以在 IHtmlLocalizer的实例中, 既可以轻松的获取对应的值。

    因为 ViewLocalizer 会注入一个IHtmlLocalizerFactory 的实例。默认的实例 是  HtmlLocalizerFactory , 在 HtmlLocalizerFactory 的构造函数中会注入一个 IStringLocalizerFactory 的实例(位于Microsoft.Extensions.Localization.Abstractions)。

    的定义是 

    而  IHtmlLocalizerFactory 的定义是 

    可以说  HtmlLocalizerFactory 是对 HtmlLocalizerFactory 的一个包装。

    查阅代码知道 默认 IStringLocalizerFactory 实现是 ResourceManagerStringLocalizerFactory ,并且读取资源文件均是这个实现来操作。

    回到开头的问题,假设我要使用 json 文件 代替 resx 文件。该如何实现呢,。?  有2种方法

    1)只要实现对应的 IStringLocalizerFactory 并且代替默认的 ResourceManagerStringLocalizerFactory 。

    2)重写 ResourceManagerStringLocalizerFactory 。

    1) 1,定义一个  JsonStringLocalizerFactory 并实现 IStringLocalizerFactory 。

    public class JsonStringLocalizerFactory : IStringLocalizerFactory
        {
            private readonly string _applicationName;
            private readonly IHostingEnvironment _hostingEnvironment;
            private readonly LocalizationOptions _options;
            public JsonStringLocalizerFactory(IHostingEnvironment hostingEnvironment, IOptions<LocalizationOptions> localizationOptions)
            {
                if (localizationOptions == null)
                {
                    throw new ArgumentNullException(nameof(localizationOptions));
                }
                this._hostingEnvironment = hostingEnvironment ?? throw new ArgumentNullException(nameof(hostingEnvironment));
                this._options = localizationOptions.Value;
                this._applicationName = hostingEnvironment.ApplicationName;
            }
    
            public IStringLocalizer Create(Type resourceSource)
            {
                TypeInfo typeInfo = IntrospectionExtensions.GetTypeInfo(resourceSource);
                //Assembly assembly = typeInfo.Assembly;
                //AssemblyName assemblyName = new AssemblyName(assembly.FullName);
    
                string baseResourceName = typeInfo.FullName;
                baseResourceName = TrimPrefix(baseResourceName, _applicationName + ".");
    
                return new JsonStringLocalizer(_hostingEnvironment, _options, baseResourceName, null);
            }
    
            public IStringLocalizer Create(string baseName, string location)
            {
                location = location ?? _applicationName;
    
                string baseResourceName = baseName;
                baseResourceName = TrimPrefix(baseName, location + ".");
    
                return new JsonStringLocalizer(_hostingEnvironment, _options, baseResourceName, null);
            }
    
            private static string TrimPrefix(string name, string prefix)
            {
                if (name.StartsWith(prefix, StringComparison.Ordinal))
                {
                    return name.Substring(prefix.Length);
                }
    
                return name;
            }
        }

    2, JsonStringLocalizer

    public class JsonStringLocalizer : IStringLocalizer
        {
            private readonly ConcurrentDictionary<string, string> _all;
    
            private readonly IHostingEnvironment _hostingEnvironment;
            private readonly LocalizationOptions _options;
    
            private readonly string _baseResourceName;
            private readonly CultureInfo _cultureInfo;
    
            public LocalizedString this[string name] => Get(name);
            public LocalizedString this[string name, params object[] arguments] => Get(name, arguments);
    
            public JsonStringLocalizer(IHostingEnvironment hostingEnvironment, LocalizationOptions options, string baseResourceName, CultureInfo culture)
            {
                _options = options;
                _hostingEnvironment = hostingEnvironment;
    
                _cultureInfo = culture ?? CultureInfo.CurrentUICulture;
                _baseResourceName = baseResourceName + "." + _cultureInfo.Name;
                _all = GetAll();
    
            }
    
            public IEnumerable<LocalizedString> GetAllStrings(bool includeParentCultures)
            {
                return _all.Select(t => new LocalizedString(t.Key, t.Value, true)).ToArray();
            }
    
            public IStringLocalizer WithCulture(CultureInfo culture)
            {
                if (culture == null)
                    return this;
    
                CultureInfo.CurrentUICulture = culture;
                CultureInfo.DefaultThreadCurrentCulture = culture;
    
                return new JsonStringLocalizer(_hostingEnvironment, _options, _baseResourceName, culture);
            }
    
            private LocalizedString Get(string name, params object[] arguments)
            {
                if (_all.ContainsKey(name))
                {
                    var current = _all[name];
                    return new LocalizedString(name, string.Format(_all[name], arguments));
                }
                return new LocalizedString(name, name, true);
            }
    
            private ConcurrentDictionary<string, string> GetAll()
            {
                var file = Path.Combine(_hostingEnvironment.ContentRootPath, _baseResourceName + ".json");
                if (!string.IsNullOrEmpty(_options.ResourcesPath))
                    file = Path.Combine(_hostingEnvironment.ContentRootPath, _options.ResourcesPath, _baseResourceName + ".json");
    
                Debug.WriteLineIf(!File.Exists(file), "Path not found! " + file);
    
                if (!File.Exists(file))
                    return new ConcurrentDictionary<string, string>();
    
                try
                {
                    var txt = File.ReadAllText(file);
    
                    return JsonConvert.DeserializeObject<ConcurrentDictionary<string, string>>(txt);
                }
                catch (Exception)
                {
                }
    
                return new ConcurrentDictionary<string, string>();
            }
        }

    3,添加注入 

    services.AddSingleton<IStringLocalizerFactory, JsonStringLocalizerFactory>();

    4,json 文件

    上面的代码只是简单的实现了 使用 点(.) 作为分隔符的json 文件作为资源文件。(其实上面的代码运行后有个小问题)

    代码已经放到 Github 

    2)。待实现~~~ 

    链接:http://blog.wuliping.cn/post/aspnet-core-localization-and-custom-resource-service-with-file

  • 相关阅读:
    小师妹学JVM之:JDK14中JVM的性能优化
    小师妹学JVM之:深入理解JIT和编译优化-你看不懂系列
    小师妹学JVM之:GC的垃圾回收算法
    小师妹学JVM之:JVM的架构和执行过程
    小师妹学JavaIO之:用Selector来发好人卡
    小师妹学JavaIO之:NIO中那些奇怪的Buffer
    小师妹学JavaIO之:MappedByteBuffer多大的文件我都装得下
    小师妹学JavaIO之:NIO中Channel的妙用
    小师妹学JavaIO之:Buffer和Buff
    小师妹学JavaIO之:文件File和路径Path
  • 原文地址:https://www.cnblogs.com/passingwind/p/aspnet-core-localization-and-custom-resource-service-with-file.html
Copyright © 2020-2023  润新知