纸壳CMS旗舰版支持多语言,并且有一套完整的多语言体系来支持不同语言的响应,开发多语言内容模块也很便捷,接下来跟我们一步一步的让现有内容支持多语言。

IMultiLanContent

首先你的实体(Entity)需要继承IMultiLanContent接口。

namespace ZKEACMS.MultiLanguage
{
    public interface IMultiLanContent
    {
        string ContentID { get; set; }
        int CultureID { get; set; }
        object GetContentID();
        void SetContentID(object Id);
        IMultiLanContent[] CultureContents { get; set; }
    }
}
ContentID:是主记录的ID,就是默认语言那条记录的ID。
CultureID:语言ID,对应Culture表。
GetContentID():用于获取当前记录的ID
SetContentID(object Id):设置记录ID
CultureContents:所有语言内容

例如像文章实体:

[Table("Article")]
public class ArticleEntity : EditorEntity, IImage, IMultiLanContent
{
    ...
    public string ContentID { get; set; }
    public int CultureID { get; set; }
    [NotMapped]
    public IMultiLanContent[] CultureContents { get; set; }

    public object GetContentID()
    {
        return ID;
    }
    public void SetContentID(object Id)
    {
        ID = (int)Id;
    }
}

注意:请务必将CultureContents标记为NotMapped

元数据配置

多语言的元数据MetaData,需要继承自LocalizeViewMetaData<T>

class ArticleEntityMeta : LocalizeViewMetaData<ArticleEntity>
{
    protected override void ViewConfigure()
    {
        base.ViewConfigure();
        ...     
    }
}

这样实体就配置好了。

Service

在Service里面要做的事情比较简单,只要继承对应的接口和基类就可以了。

  • 接口:ILocalizeService<T>
  • 实现:LocalizeService<T>

同样以ArticleService为例

首先,先在IArticleService需要继承自ILocalizeService<T>

namespace ZKEACMS.Article.Service
{
    public interface IArticleService : ILocalizeService<ArticleEntity>
    {
        ...
    }
}

然后在ArticleService需要继承LocalizeService<T>

namespace ZKEACMS.Article.Service
{
    public class ArticleService : LocalizeService<ArticleEntity>, IArticleService
    {
        private readonly ILocalize _localize;
        public ArticleService(IApplicationContext applicationContext, ILocalize localize, CMSDbContext dbContext)
            : base(applicationContext, dbContext)
        {
            _localize = localize;
        }
        ...
    }
}

请视具体情况来确定是否使用LocalizeService<T>,如果业务比较特殊,也可自己做实现,或者重载基类方法。

Controller

创建,Create Action:

[DefaultAuthorize(Policy = PermissionKeys.ManageArticle)]
public IActionResult Create(int? ContentID, int? CultureID)
{
    ArticleEntity entity = null;
    if (ContentID.HasValue && CultureID.HasValue)
    {
        entity = Service.Get(ContentID.Value);
    }
    else
    {
        entity = new ArticleEntity { Status = (int)RecordStatus.Active };
    }
    return View(entity);
}
[HttpPost, DefaultAuthorize(Policy = PermissionKeys.ManageArticle)]
public IActionResult Create(ArticleEntity entity, CultureFlag cultureFlag)
{
    if (ModelState.IsValid)
    {
        UpLoadImage(entity as IImage);
        var result = Service.Add(entity, cultureFlag);
        if (result.HasViolation)
        {
            foreach (var item in result.RuleViolations)
            {
                ModelState.AddModelError(item.ParameterName, item.ErrorMessage);
            }
            cultureFlag.Resotre(entity);
            return View(entity);
        }
        if (entity.ActionType == ActionType.Publish && _authorizer.Authorize(PermissionKeys.PublishArticle))
        {
            Service.Publish(entity.ID);
        }
        return RedirectToAction("Edit", new { Id = entity.ID });
    }
    cultureFlag.Resotre(entity);
    return View(entity);
}

编辑,Edit Action:

[DefaultAuthorize(Policy = PermissionKeys.ManageArticle)]
public override IActionResult Edit(int Id)
{
    return base.Edit(Id);
}
[HttpPost, DefaultAuthorize(Policy = PermissionKeys.ManageArticle)]
public IActionResult Edit(ArticleEntity entity, CultureFlag cultureFlag)
{
    if (entity.ActionType == ActionType.Delete)
    {
        Service.Remove(entity.ID);
        if (entity.ID.ToString() == entity.ContentID)
        {
            return RedirectToAction("Index");
        }
        else
        {
            return RedirectToAction("Edit", new { Id = entity.ContentID });
        }
    }

    if (ModelState.IsValid)
    {
        var result = Service.Update(entity, cultureFlag);
        if (result.HasViolation)
        {
            foreach (var item in result.RuleViolations)
            {
                ModelState.AddModelError(item.ParameterName, item.ErrorMessage);
            }
            cultureFlag.Resotre(entity);
            return View(entity);
        }
        ...
        return RedirectToAction("Edit", new { Id = entity.ID });
    }
    cultureFlag.Resotre(entity);
    return View(entity);
}

获取数据列表GetList

在获取列表数据时,需要加入当前语言的ID作为条件:

[HttpPost, DefaultAuthorize(Policy = PermissionKeys.ViewArticle)]
public override IActionResult GetList(DataTableOption query)
{
    query.AppendCondition("CultureID", _applicationContextAccessor.Current.CurrentCulture.CultureID.ToString());
    return base.GetList(query);
}

View

View的修改比较简单,添加一行代码就可以了,用于显示语言旗帜:

<div class="panel panel-default">
    ...
    <div class="panel-body">
        @using (Html.BeginForm())
        {
            @Html.CultureFlag(new CultureFlag(Model))
            @Html.EditorForModel()
            ...
        }
    </div>
</div>

数据库

如果是有旧数据,可以使用以下脚本来添加新字段和更新默认值:

ALTER TABLE dbo.Article ADD ContentID NVARCHAR(100)
ALTER TABLE dbo.Article ADD CultureID INT
GO
UPDATE dbo.Article SET ContentID = ID,CultureID = 1