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

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

第一步 建立实体

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

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

 public class DBLocalization : Entity
{
[Required]
[StringLength()]
public virtual string Culture { get; set; }
[Required]
[StringLength()]
public virtual string Name { get; set; }
[Required]
public virtual string Value { get; set; }
}

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

第二步 建立领域服务

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

 public class DBLocalizationManager : DomainService
{
private readonly IRepository<DBLocalization> _localizationRepository;
public DBLocalizationManager(IRepository<DBLocalization> localizationRepository)
{
_localizationRepository = localizationRepository;
}
public List<CultureInfo> GetCultures()
{
return _localizationRepository.GetAllList()
.Select(p => new CultureInfo(p.Culture))
.Distinct()
.ToList<CultureInfo>();
}
public List<DBLocalization> GetDictionary()
{
return _localizationRepository.GetAllList();
}
}

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

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

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

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

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

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

 public class DBLocalizationDictionaryProvider : ILocalizationDictionaryProvider
{
private DBLocalizationManager _dbLocalizationManager;
public IEnumerable<LocalizationDictionaryInfo> GetDictionaries(string sourceName)
{
if (_dbLocalizationManager == null)
{
if (IocManager.Instance.IsRegistered<DBLocalizationManager>())
{
_dbLocalizationManager = IocManager.Instance.Resolve<DBLocalizationManager>();
}
}
var dictionaries = new List<LocalizationDictionaryInfo>();
foreach (var culture in _dbLocalizationManager.GetCultures())
{
dictionaries.Add(
new LocalizationDictionaryInfo(
DBLocalizationDictionary.Build(culture.Name,
_dbLocalizationManager.GetDictionary()) ,
isDefault: culture.Name == ZeroConsts.DefaultLanguage
)
);
}
return dictionaries;
}
}

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

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

 public class DBLocalizationDictionary : LocalizationDictionary
{
private DBLocalizationDictionary(CultureInfo cultureInfo)
: base(cultureInfo)
{
}
public static DBLocalizationDictionary Build(string cultureName, List<DBLocalization> dictList)
{
try
{
var dictionary = new DBLocalizationDictionary(new CultureInfo(cultureName));
var dublicateNames = new List<string>();
if (dictList != null && dictList.Count>)
{
foreach (DBLocalization item in dictList.FindAll(c => c.Culture == cultureName))
{
if (string.IsNullOrEmpty(item.Name))
{
throw new AbpException("name of a dictionary is empty in given data.");
}
if (dictionary.Contains(item.Name))
{
dublicateNames.Add(item.Name);
}
dictionary[item.Name] = item.Value.NormalizeLineEndings();
}
}
if (dublicateNames.Count > )
{
throw new AbpException("A dictionary can not contain same key twice. There are some duplicated names: " + dublicateNames.JoinAsString(", "));
}
return dictionary;
}
catch (Exception ex)
{
throw new AbpException("Invalid localization data format! ", ex);
}
}
}

第四步 注册资源

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

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

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

DDD开发框架ABP之本地化资源的数据库存储扩展的更多相关文章

  1. DDD开发框架ABP之本地化/多语言支持

    本地化(Localization)也就是多语言功能,借此用户能够选择他的母语或熟悉的语言来使用系统,这显然非常有利于软件系统推向国际化.一个应用程序的UI界面至少有一种语言,DDD开发框架ABP就提供 ...

  2. ABP Zero 本地化语言的初始化和扩展

    在aspnetboilerplate.com生成后,在core下的本地化文件增加选项即可 初始化方法 解析: var currentCultureName = Thread.CurrentThread ...

  3. DDD开发框架ABP之导航菜单

    每一个网站都会有导航菜单(通常不止一个),ASP.NET Boilerplate(后文简称ABP)提供了一种创建和使用菜单的通用架构,利用架构我们可以方便的创建菜单并显示给用户.本文主要说明菜单的创建 ...

  4. DDD开发框架ABP之动态Web API层

    建立动态Web API 控制器 ASP.NET Boilerplate 能够自动为您的应用层产生Web API层.比如说我们有如下的一个应用服务: public interface ITaskAppS ...

  5. 基于DDD的现代ASP.NET开发框架--ABP系列之3、ABP分层架构

    基于DDD的现代ASP.NET开发框架--ABP系列之3.ABP分层架构 ABP是“ASP.NET Boilerplate Project (ASP.NET样板项目)”的简称. ABP的官方网站:ht ...

  6. 基于DDD的现代ASP.NET开发框架--ABP系列之2、ABP入门教程

    基于DDD的现代ASP.NET开发框架--ABP系列之2.ABP入门教程 ABP是“ASP.NET Boilerplate Project (ASP.NET样板项目)”的简称. ASP.NET Boi ...

  7. DDD的ABP开发框架

    基于DDD的ABP开发框架初探   一.基本概念 ABP是“ASP.NET Boilerplate Project (ASP.NET样板项目)”的简称. ABP是土耳其的以为架构师hikalkan开发 ...

  8. 基于DDD的现代ASP.NET开发框架--ABP系列之1、ABP总体介绍

    点这里进入ABP系列文章总目录 基于DDD的现代ASP.NET开发框架--ABP系列之1.ABP总体介绍 ABP是“ASP.NET Boilerplate Project (ASP.NET样板项目)” ...

  9. 线上分享-- 基于DDD的.NET开发框架-ABP介绍

    前言 为了能够帮助.Net开发者开拓视野,更好的把最新的技术应用到工作中,我在3月底受邀到如鹏网.net训练营直播间为各位学弟学妹们进行ABP框架的直播分享.同时为了让更多的.NET开发者了解ABP框 ...

随机推荐

  1. 【原】Telerik radwindow 在IE10下偶尔报 unable to get value of the property 'toLowerCase' 的解决办法

    笔者正在开发的新项目在升级了最新版本的Telerik Control和决定支持IE10后,遇到了一个很棘手的问题,偶尔会在打开Radwindow的时候报JS error :unable to get ...

  2. Android—自定义Dialog

    在 Android 日常的开发中,Dialog 使用是比较广泛的.无论是提示一个提示语,还是确认信息,还是有一定交互的(弹出验证码,输入账号密码登录等等)对话框. 而我们去看一下原生的对话框,虽然随着 ...

  3. iOS---数据本地化

    本篇随笔除了介绍 iOS 数据持久化知识之外,还贯穿了以下内容: (1)自定义 TableView,结合 block 从 ViewController 中分离出 View,轻 ViewControll ...

  4. C#设计模式系列:适配器模式(Adapter)

    在实际的软件系统设计和开发中,为了完成某项工作需要购买一个第三方的库来加快开发.这带来一个问题,在应用程序中已经设计好的功能接口,与这个第三方提供的接口不一致.为了使得这些接口不兼容的类可以在一起工作 ...

  5. SQL Server中的事务与锁

    了解事务和锁 事务:保持逻辑数据一致性与可恢复性,必不可少的利器. 锁:多用户访问同一数据库资源时,对访问的先后次序权限管理的一种机制,没有他事务或许将会一塌糊涂,不能保证数据的安全正确读写. 死锁: ...

  6. WPF DatePicker只显示年和月 修改:可以只显示年

    最近的项目,查询时只需要年和月,不需要日,因此需要对原有的DatePicker进行修改,查询了网上的内容,最终从一篇帖子里看到了添加附加属性的方法,地址是http://stackoverflow.co ...

  7. Unity事件

    unity3d事件函数整理,事件,回调函数,消息处理 Unity3D中所有控制脚本的基类MonoBehaviour有一些虚函数用于绘制中事件的回调,也可以直接理解为事件函数,例如大家都很清楚的Star ...

  8. 细说gulp

    一.概述&安装 Gulp,简而言之,就是前端自动化开发工具,利用它,我们可以提高开发效率. 比如: 1.  压缩js 2.  压缩css 3.  压缩less 4.  压缩图片 等等… 我们完 ...

  9. Javascript正则构造函数与正则表达字面量&&常用正则表达式

    本文不讨论正则表达式入门,即如何使用正则匹配.讨论的是两种创建正则表达式的优劣和一些细节,最后给出一些常用正则匹配表达式. Javascript中的正则表达式也是对象,我们可以使用两种方法创建正则表达 ...

  10. Ajax JQuery HTML 提交上传文件File HTML+ Ajax+ASP.NET+ WebService

    起因:公司最近有些项目用到了HTML+WebService的组合,发现访问速度等都快了许多,但是由于通过Ajax只能应付一些简单的文字类的传输,上传文件就捉襟见肘了,如果一直引用第三方的swf之类上传 ...