DDD EventSourcing ValueObject,支持多种语言

问题描述 投票:0回答:1

有一份申请书,写在

.net
,写着
DDD
CQRS+EventSourcing
。有一个要求 - 为某些值对象添加翻译。如何实现这样的功能?

例如

有聚合产品和活动:

    public class ProductId
    {
        public long Id {get;set;}
    }
    public class ProductDescription
    {
        public string Description {get;set;}
    }
    public class ProductName
    {
        public string Name{get;set;}
    }
    public class ProductAggregate
    {
        public ProductId {get;set;}
        public ProductDescription Description{get;set;}
        public ProductName Name{get;set;}
        public ProductPrice {get;set;} // no need to have translation for this field while
        ...
    }
    public class DescriptionUpdatedEvent
    {
        ProductId Id{ get;set;}
        PeoductDescription Description {get;set;}
    }

应该能够为某些聚合的某些属性提供多种语言支持。例如,当用户使用英语语言的 UI 时,他应该看到“产品描述”,当用户将 UI 中的语言切换到 Fr 时,他应该看到“产品描述”。问题不在于如何翻译 UI,而在于如何向数据添加翻译。

我的想法:

  1. 为每个需要翻译的字段添加重复字段。它可以是字典,其中键是语言(“en”,“fr”等)
    public class ProductAggregate
    {
        public ProductId {get;set;}
        public ProductDescription Description{get;set;}
        public Dictionary<string,ProductDescription> DescriptionTranslations{get;set;}
    
        public ProductName Name{get;set;}
        public Dictionary<string,ProductName> NameTranslations{get;set;}
        ...
    }
    public class DescriptionTrnslationUpdated // new event should be added
    {
        ProductId Id{ get;set;}
        string Language {get;set;} // can be 'en','fr' etc.
        ProductDescription {get;set;}
    }

看起来这是最简单的方法,每个字段只需添加 1 个事件。我在这里看到的唯一一个问题 - 我们将实体与其翻译混合在一起,它使聚合的大小加倍

  1. 将此类字典添加到 ValueObject 中
    public class ProductDescription
    {
        public string Description {get;set;}
        public Dictionary<string,ProductDescription> Translations{get;set;}
    }
    public class DescriptionTrnslationUpdated // new event should be added
    {
        ProductId Id{ get;set;}
        string Language {get;set;} // can be 'en','fr' etc.
        ProductDescription {get;set;}
    }
    public class DescriptionUpdatedEvent2 // since VO modified, old event will be broken and we need to convert old event to new type or create new type and use it
    {
        ProductId Id{ get;set;}
        PeoductDescription Description {get;set;}
    }

这种方法看起来很复杂。

  1. 为我们需要支持的每种语言添加新的聚合,其中仅包含需要翻译的字段。该聚合可能应该具有与之前相同的密钥,因此当您需要将翻译添加到 Product-1 时,您知道翻译聚合的 id,它将是
    ProductFr-1
    :
    public class ProductFrAggregate
    {
        public ProductId {get;set;}
        public ProductDescription Description{get;set;}
        public ProductName Name{get;set;}
        ...
    }
    public class DescriptionFrUpdated // new event should be added 
    {
        ProductFrId {get;set}
        string Language {get;set;} // can be 'en','fr' etc.
        ProductDescription {get;set;}
    }
    public class DescriptionEnUpdated // new event should be added 
    {
        ProductFrId {get;set}
        string Language {get;set;} // can be 'en','fr' etc.
        ProductDescription {get;set;}
    }

也很简单,但是我们应该添加很多事件类型,每种语言 1 个事件

  1. 为我们需要支持的所有语言添加新的聚合,其中将包含所有需要翻译的字段的翻译。该聚合可能应该具有与之前相同的密钥,因此当您需要将翻译添加到 Product-1 时,您知道翻译聚合的 id,它将是
    ProductTranslations-1
    :
    public class ProductTranslationsAggregate
    {
        public ProductTranslationId {get;set;}
        public Dictionary<string,ProductDescription> DescriptionTranslations{get;set;}
        public Dictionary<string,ProductName> NameTranslations{get;set;}
        ...
    }
    public class DescriptionTranslationUpdated // new event should be added 
    {
        ProductTranslationId {get;set}
        string Language {get;set;} // can be 'en','fr' etc.
        ProductDescription {get;set;}
    }
    public class NameTranslationUpdated // new event should be added 
    {
        ProductTranslationId {get;set}
        string Language {get;set;} // can be 'en','fr' etc.
        ProductDescription {get;set;}

看起来和第一个一样简单,不需要添加太多事件类型。但由于我们将使用 2 个聚合,因此每个聚合都将具有一致性。目前还不清楚如何使用它。如果产品将被删除怎么办?或者有一些逻辑 - 有点“如果价格发生变化,描述应该更新”,在两个聚合之间管理这种情况变得很困难

domain-driven-design multilingual cqrs event-sourcing value-objects
1个回答
0
投票

我认为您不会找到这个问题的权威答案。

但是非权威地说...

你的大部分代码可能不关心翻译来自哪里;代码只是想知道要使用什么值。例如,如果您要生成目录的 HTML 表示形式,我们可能会有一个产品标识符、一个语言代码和一个时间戳,然后我们会将这些传递到某个黑匣子以获取我们需要的文本(可能是包含在带有其他有趣信息的数据结构中)。

换句话说,翻译的集合,以及决定在哪种情况下使用哪些翻译的政策可能是参考数据。在最幼稚的版本中,我们只是使用翻译者最后写入数据库的任何值。

如果翻译和翻译政策是您工作中的关键区别因素,那么您可能有一堆聚合来协助创建/维护翻译的过程。因此,您需要坐下来与“领域专家”进行翻译,弄清楚流程是什么,以及自动化如何提供价值。

(亚历克斯向我们发送了一份新的英文产品描述。因此,首先,我们确定需要提前准备哪些翻译,这是我们确定的方法......然后,对于每个翻译,我们向谷歌翻译提交请求,在这些条件下,该翻译“足够好”,我们将在其他条件下使用它;我们将谷歌的建议发送给帕特和查理,他们将进行改进,然后将该文本发送给金。最终批准....)

但是,如果您除了复制翻译者提供给您的信息之外没有做任何其他事情,那么您可能是一个数据库,而不是域模型,并且让自己陷入一堆“聚合”仪式中是一种浪费时间和资源。

© www.soinside.com 2019 - 2024. All rights reserved.