zoukankan      html  css  js  c++  java
  • DDD开发框架ABP之本地化资源的数据库存储扩展

          在上一篇《DDD开发框架ABP之本地化/多语言支持》中,我们知道,ABP开发框架中本地化资源存储可以采用XML文件,RESX资源文件,也提供了其他自定义的存储方式的扩展接口。ABP框架默认实现了前面两种方式,而数据库存储方式则需要自己扩展,大概是因为数据库存储涉及到了实体和仓储等方面的具体内容,不适合放在基本框架里面。

          以数据库的方式存储本地化资源,一个最明显的好处就是方便修改,尤其是对于基于数据库的应用系统而言,可以提供统一的维护界面。接下来我们就来一步步地实现将本地化资源存储在数据库中。

    第一步 建立实体

          如果以XML存储资源,我们需要建立XML的资源文件,支持多少种语言则需要建立多少个资源文件。那么以数据库存储资源文本,自然也需要建立实体,然后实现实体的读操作。

          为了存储资源,我们需要建立一个实体:

     1 public class DBLocalization : Entity
     2 {
     3     [Required]
     4     [StringLength(10)]
     5     public virtual string Culture { get; set; }
     6     [Required]
     7     [StringLength(50)]
     8     public virtual string Name { get; set; }
     9     [Required]
    10     public virtual string Value { get; set; }
    11 }

          其中Culture属性为语言代码,比如en, zh-TW, zh-CN等。Name属性为名称,Value属性为对应的文本。基类Entity是ABP框架提供的通用领域实体类,默认具有整型Id,且实现了IEntity接口。

    第二步 建立领域服务

          领域服务提供对实体的数据操作,比如取得语言种类和语言字典。

     1 public class DBLocalizationManager : DomainService
     2 {
     3     private readonly IRepository<DBLocalization> _localizationRepository; 
     4     public DBLocalizationManager(IRepository<DBLocalization> localizationRepository) 
     5     {
     6         _localizationRepository = localizationRepository;
     7     }
     8     public List<CultureInfo> GetCultures() 
     9     {
    10         return _localizationRepository.GetAllList()
    11         .Select(p => new CultureInfo(p.Culture))
    12         .Distinct()
    13         .ToList<CultureInfo>();
    14     }
    15     public List<DBLocalization> GetDictionary()
    16     {
    17         return _localizationRepository.GetAllList();
    18     }
    19 }

          其中IRepository<DBLocalization>以构造函数方式注入。

    第三步 实现本地化资源接口(ILocalizationSource)

          ILocalizationSource是本地化框架的核心接口,接口方法包括:

          Name:资源名称,
          Initialize():初始化方法,注册时被ABP调用
          string GetString(string name) 根据名称取得文本
          IReadOnlyList<LocalizedString> GetAllStrings() 取得当前语言的全部字典清单

          ABP已经有三个实现了ILocalizationSource接口的类:NullLocalizationSource、ResourceFileLocalizationSource 和 DictionaryBasedLocalizationSource。

          把资源文本存储于数据库中,每次取得文本时都访问数据库取得数据,但基于性能的考虑,显然将资源文本提前在初始化时一次性加载到内存,应该是更好地方式。由于DictionaryBasedLocalizationSource已经实现了内存字典的通用方法,我们不太需要再另外写一个DBLocalizationSource。查看DictionaryBasedLocalizationSource代码,可以看到其构造函数需要传入一个ILocalizationDictionaryProvider的实例,这个实例用于取得本地化字典的详细内容。
          接下来我们建立一个类实现ILocalizationDictionaryProvider接口:

     1 public class DBLocalizationDictionaryProvider : ILocalizationDictionaryProvider
     2 {
     3     private DBLocalizationManager _dbLocalizationManager;
     4     public IEnumerable<LocalizationDictionaryInfo> GetDictionaries(string sourceName)
     5     {
     6         if (_dbLocalizationManager == null) 
     7         {
     8             if (IocManager.Instance.IsRegistered<DBLocalizationManager>())
     9             {
    10             _dbLocalizationManager = IocManager.Instance.Resolve<DBLocalizationManager>();
    11             }
    12         }
    13         var dictionaries = new List<LocalizationDictionaryInfo>();
    14         foreach (var culture in _dbLocalizationManager.GetCultures())
    15         {
    16             dictionaries.Add(
    17                 new LocalizationDictionaryInfo(
    18                     DBLocalizationDictionary.Build(culture.Name,
    19                     _dbLocalizationManager.GetDictionary()) ,
    20                     isDefault: culture.Name == ZeroConsts.DefaultLanguage
    21                 )
    22             );
    23         }
    24         return dictionaries;
    25     }
    26 }

          该类实现了接口的GetDictionaries方法,取得字典对象DBLocalizationDictionary。方法首先利用依赖注入容器自动得到一个IDBLocalizationManager的实例。

          下面是DBLocalizationDictionary字典类的实现代码:

     1 public class DBLocalizationDictionary : LocalizationDictionary
     2 {
     3     private DBLocalizationDictionary(CultureInfo cultureInfo)
     4         : base(cultureInfo)
     5     {
     6     }
     7     public static DBLocalizationDictionary Build(string cultureName, List<DBLocalization> dictList)
     8     {
     9         try
    10         {
    11             var dictionary = new DBLocalizationDictionary(new CultureInfo(cultureName));
    12             var dublicateNames = new List<string>();
    13             if (dictList != null && dictList.Count>0)
    14             {
    15                 foreach (DBLocalization item in dictList.FindAll(c => c.Culture == cultureName))
    16                 {
    17                     if (string.IsNullOrEmpty(item.Name))
    18                     {
    19                         throw new AbpException("name of a dictionary is empty in given data.");
    20                     }
    21                     if (dictionary.Contains(item.Name))
    22                     {
    23                         dublicateNames.Add(item.Name);
    24                     }
    25                     dictionary[item.Name] = item.Value.NormalizeLineEndings();
    26                 }
    27             }
    28             if (dublicateNames.Count > 0)
    29             {
    30                 throw new AbpException("A dictionary can not contain same key twice. There are some duplicated names: " + dublicateNames.JoinAsString(", "));
    31             }
    32             return dictionary;
    33         }
    34         catch (Exception ex)
    35         {
    36             throw new AbpException("Invalid localization data format! ", ex);
    37         }
    38     }
    39 }

    第四步 注册资源

          在需要使用多语言本地化的模块,我们可以在模块的PreInitialize方法中,注册资源。一个模块可以在Configuration.Localization.Sources 集合中添加多个资源,只要实现了ILocalizationSource接口即可。

    1 public override void PreInitialize()
    2 {
    3     Configuration.Localization.Sources.Add(
    4         new DictionaryBasedLocalizationSource("Zero", new DBLocalizationDictionaryProvider()));
    5 }

      到这里,将本地化资源存储在数据库中就基本上已经全部实现,剩下的就是开发界面对本地化资源进行增删改查的维护了。

  • 相关阅读:
    max key length is 1000 bytes
    205 Reset Content
    The Path Attribute
    track message forwards, avoiding request loops, and identifying the protocol capabilities of all senders along the request/response chain
    test hypertext links for validity, accessibility, and recent modification
    ES6 will change the way you write JS code.
    ECMAScript Web APIs node.js
    Symbols
    HTML/Elements/base
    frag General URL components
  • 原文地址:https://www.cnblogs.com/defzhu/p/4855978.html
Copyright © 2011-2022 走看看