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

栏目: ASP.NET · 发布时间: 8年前

内容简介:asp.net core 之多语言国际化自定义资源文件

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

一:基本使用方法

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

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

@inject IViewLocalizer Localizer

<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 对应的实例。 在创建的时候 会带入两个参数 ,一个是 当前 试图的路径,一个是当前应用名称。

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

IHtmlLocalizer 定义如下:

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

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

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

的定义是

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

而  IHtmlLocalizerFactory 的定义是 asp.net core 之多语言国际化自定义资源文件

可以说  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 文件

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

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

代码已经放到 Github 

2)。待实现~~~


以上所述就是小编给大家介绍的《asp.net core 之多语言国际化自定义资源文件》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Programming Collective Intelligence

Programming Collective Intelligence

Toby Segaran / O'Reilly Media / 2007-8-26 / USD 39.99

Want to tap the power behind search rankings, product recommendations, social bookmarking, and online matchmaking? This fascinating book demonstrates how you can build Web 2.0 applications to mine the......一起来看看 《Programming Collective Intelligence》 这本书的介绍吧!

JS 压缩/解压工具
JS 压缩/解压工具

在线压缩/解压 JS 代码

MD5 加密
MD5 加密

MD5 加密工具

XML 在线格式化
XML 在线格式化

在线 XML 格式化压缩工具