[Asp.net 5] Localization-resx资源文件的管理

上一篇博文地址:[Asp.net 5] Localization-简单易用的本地化-全球化信息

本文继续介绍asp.net 5多语言。今天重点讲的是多语言的resx文件。涉及到的工程有:Microsoft.Framework.Localization.Abstractions以及Microsoft.Framework.Localization。他们之间的类结构如下如所示:

[Asp.net 5] Localization-resx资源文件的管理

  • Abstractions包中,包含了定义在工程Microsoft.Framework.Localization.Abstractions的大部分类和接口
  • Localization包中,包含了定义在工程Microsoft.Framework.Localization中的大部分类和接口

Microsoft.Framework.Localization.Abstractions

该工程定义了本地化(全球化)的基本接口,以及一些抽象类。

  • LocalizedString 封装name、value等属性的结构体,用于表示本地化寻找的结果
  • IStringLocalizer 本地化访问的基本接口,通过方法或者属性(通过扩展方法,使得方法和属性调用一套逻辑)获得LocalizedString结构体对象;本解决方案中,对资源文件就是该接口的 实例操作的
  • IStringLocalizer<T> 本接口中未定义任何方法,是IStringLocalizer 的泛型版本
  • StringLocalizer<TResourceSource>,该类是IStringLocalizer<T> 的实现类,内部分装IStringLocalizer 接口。使用了代理模式(前面我们介绍的配置文件、以及依赖注入都使用了该模式),所有方法都是内部IStringLocalizer对象的封装。该类的构造函数是IStringLocalizerFactory接口。
  • IStringLocalizerFactory接口:根据不同的Type类型创建不同的IStringLocalizer对象
public struct LocalizedString

    {

        public LocalizedString([NotNull] string name, [NotNull] string value)

            : this(name, value, resourceNotFound: false)

        {



        }



        public LocalizedString([NotNull] string name, [NotNull] string value, bool resourceNotFound)

        {

            Name = name;

            Value = value;

            ResourceNotFound = resourceNotFound;

        }



        public static implicit operator string (LocalizedString localizedString)

        {

            return localizedString.Value;

        }



        public string Name { get; }



        public string Value { get; }



        public bool ResourceNotFound { get; }



        public override string ToString() => Value;

    }
LocalizedString
    public interface IStringLocalizer : IEnumerable<LocalizedString>

    {

        LocalizedString this[string name] { get; }



        LocalizedString this[string name, params object[] arguments] { get; }

        

        IStringLocalizer WithCulture(CultureInfo culture);

    }
IStringLocalizer
public interface IStringLocalizer<T> : IStringLocalizer

    {



    }



public class StringLocalizer<TResourceSource> : IStringLocalizer<TResourceSource>

    {

        private IStringLocalizer _localizer;



        public StringLocalizer([NotNull] IStringLocalizerFactory factory)

        {

            _localizer = factory.Create(typeof(TResourceSource));

        }



        public virtual IStringLocalizer WithCulture(CultureInfo culture) => _localizer.WithCulture(culture);



        public virtual LocalizedString this[[NotNull] string name] => _localizer[name];



        public virtual LocalizedString this[[NotNull] string name, params object[] arguments] =>

            _localizer[name, arguments];



        public virtual LocalizedString GetString([NotNull] string name) => _localizer.GetString(name);



        public virtual LocalizedString GetString([NotNull] string name, params object[] arguments) =>

            _localizer.GetString(name, arguments);



        public IEnumerator<LocalizedString> GetEnumerator() => _localizer.GetEnumerator();



        IEnumerator IEnumerable.GetEnumerator() => _localizer.GetEnumerator();

    }
StringLocalizer

根据上面的介绍,我们可以推断该类库的使用方式如下:

public void Test()

{    

       IStringLocalizerFactory factory=new ResourceManagerStringLocalizerFactory();

       IStringLocalizer localizer=new StringLocalizer<TType>(factory);
//IStringLocalizer<TType> localizer=new StringLocalizer<TType>();
//localizer=localizer.WithCulture(CultureInfo.CurrentUICulture); var localizedString=localizer.GetString(key); }

[StringLocalizer<TResource>的作用就是隐藏具体IStringLocalizer,使我们不用关心是哪个IStringLocalizer,这样做对于直接书写代码可能看不出直接意义,但是如果使用依赖注入,则可以明显的看出好处,我们可以为IStringLocalizer<TType>直接注入StringLocalizer<TType>类]

[如果对于依赖注入了解不多,可以看下篇博客:DependencyInjection项目代码分析-目录,略长]

Microsoft.Framework.Localization

  • ResourceManagerStringLocalizerFactory:创建ResourceManagerStringLocalizer类资源
  • ResourceManagerStringLocalizer:resx多语言文件的访问器(实际该代码并未另起灶炉,而是使用了ResourceManager类)
  • ResourceManagerWithCultureStringLocalizer:ResourceManagerStringLocalizer的子类,提供多语言访问接口。该类实际上是在父类中WithCulture中创建,而该方法内实际也是一个类似于代理模式的设计
  • LocalizationServiceCollectionExtensions类:该类将ResourceManagerStringLocalizerFactory注入到IStringLocalizerFactory接口,StringLocalizer<T> 注入到IStringLocalizer<T> 接口。
public class ResourceManagerStringLocalizerFactory : IStringLocalizerFactory

    {

        private readonly IApplicationEnvironment _applicationEnvironment;



        public ResourceManagerStringLocalizerFactory([NotNull] IApplicationEnvironment applicationEnvironment)

        {

            _applicationEnvironment = applicationEnvironment;

        }



        public IStringLocalizer Create([NotNull] Type resourceSource)

        {

            var typeInfo = resourceSource.GetTypeInfo();

            var assembly = new AssemblyWrapper(typeInfo.Assembly);

            var baseName = typeInfo.FullName;

            return new ResourceManagerStringLocalizer(new ResourceManager(resourceSource), assembly, baseName);

        }



        public IStringLocalizer Create([NotNull] string baseName, [NotNull] string location)

        {

            var assembly = Assembly.Load(new AssemblyName(location ?? _applicationEnvironment.ApplicationName));



            return new ResourceManagerStringLocalizer(

                new ResourceManager(baseName, assembly),

                new AssemblyWrapper(assembly),

                baseName);

        }

    }
ResourceManagerStringLocalizerFactory
public class ResourceManagerStringLocalizer : IStringLocalizer

    {

        private static readonly ConcurrentDictionary<string, IList<string>> _resourceNamesCache =

            new ConcurrentDictionary<string, IList<string>>();



        private readonly ConcurrentDictionary<string, object> _missingManifestCache =

            new ConcurrentDictionary<string, object>();



        private readonly ResourceManager _resourceManager;

        private readonly AssemblyWrapper _resourceAssemblyWrapper;

        private readonly string _resourceBaseName;



        public ResourceManagerStringLocalizer(

            [NotNull] ResourceManager resourceManager,

            [NotNull] Assembly resourceAssembly,

            [NotNull] string baseName)

            : this(resourceManager, new AssemblyWrapper(resourceAssembly), baseName)

        {

            

        }



        public ResourceManagerStringLocalizer(

            [NotNull] ResourceManager resourceManager,

            [NotNull] AssemblyWrapper resourceAssemblyWrapper,

            [NotNull] string baseName)

        {

            _resourceAssemblyWrapper = resourceAssemblyWrapper;

            _resourceManager = resourceManager;

            _resourceBaseName = baseName;

        }



        public virtual LocalizedString this[[NotNull] string name]

        {

            get

            {

                var value = GetStringSafely(name, null);

                return new LocalizedString(name, value ?? name, resourceNotFound: value == null);

            }

        }



        public virtual LocalizedString this[[NotNull] string name, params object[] arguments]

        {

            get

            {

                var format = GetStringSafely(name, null);

                var value = string.Format(format ?? name, arguments);

                return new LocalizedString(name, value, resourceNotFound: format == null);

            }

        }



        public IStringLocalizer WithCulture(CultureInfo culture)

        {

            return culture == null

                ? new ResourceManagerStringLocalizer(_resourceManager, _resourceAssemblyWrapper, _resourceBaseName)

                : new ResourceManagerWithCultureStringLocalizer(_resourceManager,

                    _resourceAssemblyWrapper,

                    _resourceBaseName,

                    culture);

        }



        protected string GetStringSafely([NotNull] string name, CultureInfo culture)

        {

            var cacheKey = $"name={name}&culture={(culture ?? CultureInfo.CurrentUICulture).Name}";



            if (_missingManifestCache.ContainsKey(cacheKey))

            {

                return null;

            }



            try

            {

                return culture == null ? _resourceManager.GetString(name) : _resourceManager.GetString(name, culture);

            }

            catch (MissingManifestResourceException)

            {

                _missingManifestCache.TryAdd(cacheKey, null);

                return null;

            }

        }



        public virtual IEnumerator<LocalizedString> GetEnumerator() => GetEnumerator(CultureInfo.CurrentUICulture);



        IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();



        protected IEnumerator<LocalizedString> GetEnumerator([NotNull] CultureInfo culture)

        {

            var resourceNames = GetResourceNamesFromCultureHierarchy(culture);



            foreach (var name in resourceNames)

            {

                var value = GetStringSafely(name, culture);

                yield return new LocalizedString(name, value ?? name, resourceNotFound: value == null);

            }

        }



        internal static void ClearResourceNamesCache() => _resourceNamesCache.Clear();



        private IEnumerable<string> GetResourceNamesFromCultureHierarchy(CultureInfo startingCulture)

        {

            var currentCulture = startingCulture;

            var resourceNames = new HashSet<string>();



            while (true)

            {

                try

                {

                    var cultureResourceNames = GetResourceNamesForCulture(currentCulture);

                    foreach (var resourceName in cultureResourceNames)

                    {

                        resourceNames.Add(resourceName);

                    }

                }

                catch (MissingManifestResourceException) { }



                if (currentCulture == currentCulture.Parent)

                {

                    // currentCulture begat currentCulture, probably time to leave

                    break;

                }



                currentCulture = currentCulture.Parent;

            }



            return resourceNames;

        }



        private IList<string> GetResourceNamesForCulture(CultureInfo culture)

        {

            var resourceStreamName = _resourceBaseName;

            if (!string.IsNullOrEmpty(culture.Name))

            {

                resourceStreamName += "." + culture.Name;

            }

            resourceStreamName += ".resources";



            var cacheKey = $"assembly={_resourceAssemblyWrapper.FullName};resourceStreamName={resourceStreamName}";



            var cultureResourceNames = _resourceNamesCache.GetOrAdd(cacheKey, key =>

            {

                var names = new List<string>();

                using (var cultureResourceStream = _resourceAssemblyWrapper.GetManifestResourceStream(key))

                using (var resources = new ResourceReader(cultureResourceStream))

                {

                    foreach (DictionaryEntry entry in resources)

                    {

                        var resourceName = (string)entry.Key;

                        names.Add(resourceName);

                    }

                }



                return names;

            });



            return cultureResourceNames;

        }

    }
ResourceManagerStringLocalizer
public class ResourceManagerWithCultureStringLocalizer : ResourceManagerStringLocalizer

    {

        private readonly CultureInfo _culture;



        public ResourceManagerWithCultureStringLocalizer(

            [NotNull] ResourceManager resourceManager,

            [NotNull] Assembly assembly,

            [NotNull] string baseName,

            [NotNull] CultureInfo culture)

            : base(resourceManager, assembly, baseName)

        {

            _culture = culture;

        }



        public ResourceManagerWithCultureStringLocalizer(

            [NotNull] ResourceManager resourceManager,

            [NotNull] AssemblyWrapper assemblyWrapper,

            [NotNull] string baseName,

            [NotNull] CultureInfo culture)

            : base(resourceManager, assemblyWrapper, baseName)

        {

            _culture = culture;

        }



        public override LocalizedString this[[NotNull] string name]

        {

            get

            {

                var value = GetStringSafely(name, _culture);

                return new LocalizedString(name, value ?? name);

            }

        }



        public override LocalizedString this[[NotNull] string name, params object[] arguments]

        {

            get

            {

                var format = GetStringSafely(name, _culture);

                var value = string.Format(_culture, format ?? name, arguments);

                return new LocalizedString(name, value ?? name, resourceNotFound: format == null);

            }

        }



        public override IEnumerator<LocalizedString> GetEnumerator() => GetEnumerator(_culture);

    }
ResourceManagerWithCultureStringLocalizer
public static class LocalizationServiceCollectionExtensions

    {

        public static IServiceCollection AddLocalization([NotNull] this IServiceCollection services)

        {

            services.TryAdd(new ServiceDescriptor(

                typeof(IStringLocalizerFactory),

                typeof(ResourceManagerStringLocalizerFactory),

                ServiceLifetime.Singleton));

            services.TryAdd(new ServiceDescriptor(

                typeof(IStringLocalizer<>),

                typeof(StringLocalizer<>),

                ServiceLifetime.Transient));



            return services;

        }

    }
LocalizationServiceCollectionExtensions

由于依赖注入的关系所以我们可以将代码简单的修改成如下:

          //var services = new ServiceCollection();

        //services.AddLocalization(); 系统初始化时执行过该部分代码

        public string Test(string key)

        {    

             var localizer=Provider.GetService<IStringLocalizer<RescoureType>>();

             //localizer=localizer.WithCulture(CultureInfo.CurrentUICulture);

             var localizedString=localizer.GetString(key);
if(localizedString.ResourceNotFound){
reuturn null;
}
return localizedString.Value; }


 

你可能感兴趣的:(asp.net)