A Technical Tour of the Sitecore Auto Dictionary Module

In the last article I introduced the Sitecore Auto Dictionary Module, explaining the benefits of using it over the out of the box Dictionary. Today I'll talk to those who are interested in the technical approach to this feature, covering the configuration and use of pipelines it employs.

 

The Module in Action

The last article explains what this module does, but in short it will:

  • Automatically display default text as defined by the developer
  • Create a Dictionary Domain if one was not found (and the site is configured for one)
  • Create dictionary folders if the developer has specified a path should be created
  • Create the new dictionary item in Sitecore
  • Compile a list of items what were created, and notify the content team by using an authorable email template.
  • Publish the newly-created items

 

Installing and Configuring the Module

You can get the packages here, or run a build of your own by getting the source

There's nothing that must be changed after installing the module, but there's certainly options available to you in the config file and settings item. 


The AutoDictionary.config file

The Settings items are string values which get used in the notification email. They're meant to be changed if your team is using another language.

The CreationReport task is configured to run every 5 minutes, which can be changed for your needs. Bear in mind if an item is created and then the site restarts before an email is sent, they will not be retained for sending later.

The SitecoreFundamentalsAutoDictionaryEnabled attribute needs to be added to each site that you want to use with this module. Without this, the default key will be shown when no item is found. This allows you to pick and choose which sites will use this.

View the code here.


The Auto Dictionary Settings item

Found at /sitecore/system/Modules/SitecoreFundamentals/AutoDictionary/Auto Dictionary Settings, this item will have the email sender, recipient(s), Bcc recipients(s), subject beginning and end of email. The list of items that are created will appear between that beginning and end email content. Most importantly, you can also disable emailing altogether.


 


The Module's Process

You have two options when calling dictionary items. Simply using the key, or also providing the path for where the item should be created if it's not found, and the default text. The path isn't used when resolving to an item; the module just uses the standard procedure to do that. 

SitecoreFundamentals.AutoDictionary.Translate.Text("demo.site", "Global/Branding", "Demo Site")
  
SitecoreFundamentals.AutoDictionary.Translate.Text("demo.site")

 

Translate/Text.cs

Here you will see a string value will be retrieved from Sitecore. If configured to use the module, this will be empty if not found, instead of the default key value. 

var result = Sitecore.Globalization.Translate.Text(key);

It then constructs the path to be made and checks to see if the item exists. If it doesn't find anything, it checks a static list to see if the item has already been sent into the Event Queue. If not, it adds this item to the list for future skipping.

if (!dictionaryReportItems.GetAll()
.Any(x => x.Path.ToLowerInvariant() == itemPath.ToLowerInvariant() 
&& x.LanguageName == Sitecore.Context.Language.Name))
{
    dictionaryReportItems.Add(new DictionaryReportItem()
    {
        Path = itemPath,
        LanguageName = Sitecore.Context.Language.Name
    });

An instance of the AddItemSaveEvent is created after adding the item to the list. 

AddItemSaveEvent evt = new AddItemSaveEvent();
evt.DictionaryDomain = dictionaryDomain;
evt.Path = itemPath;
evt.Key = key;
evt.Phrase = defaultValue;
evt.ContextUrl = HttpContext.Current?.Request.Url.AbsoluteUri;
evt.Language = Sitecore.Context.Language;

Finally it will send the new item to the Event Queue.

Sitecore.Configuration.Factory.GetDatabase("web").RemoteEvents.EventQueue.QueueEvent<AddItemSaveEvent>(evt, true, true);

View the code here.

 

EventHandlers/ItemSaveEvent.cs

The ItemSaveEvent will receive the new item and construct the IA based on the Path that was given. It's too large to go over everything, but some key points are:

Only the last item in the constructed path would be the dictionary item, so as this iterates over all items to be created, the last one will be true.

var commitFields = false;
...
if (commitFields)
{
    saveItem.Editing.BeginEdit();
    saveItem.Fields["key"].Value = args.Key;
    saveItem.Fields["phrase"].Value = !string.IsNullOrEmpty(args.Phrase) ? args.Phrase : itemName;
    saveItem.Editing.EndEdit();
}


A list of items that were created are retained and emailed to the content team. 

var dictionaryReportItems = new Lists.DictionaryReportItems();
...
var reportItem = new DictionaryReportItem()
{
    Path = itemPath,
    Key = args.Key,
    DefaultValue = args.Phrase,
    ContextUrl = args.ContextUrl,
    LanguageName = args.Language.Name
};
dictionaryReportItems.Add(reportItem);


As the items are created, the itemToPublish will be the highest in the IA that's new or updated, so at the end of the process this item and its children will be published.

Sitecore.Data.Items.Item itemToPublish = null;
...
if (itemToPublish != null)
{
    Database[] databases = new Database[1] { webDb };
    Language[] language = new Language[1] { itemToPublish.Language };
    Sitecore.Handle publishHandle = PublishManager.PublishItem(itemToPublish, databases, language, true, false);
}

View the code here.


Tasks/CreationReport.cs

This one's pretty simple. The Run method will get all dictionary items in the dictionaryReportItems list and email them to the team.

var dictionaryReportItems = new Lists.DictionaryReportItems();
var allDictionaryReportItems = dictionaryReportItems.GetAll();


You can see here where the settings from the config file above are used.

foreach (var reportItem in allDictionaryReportItems)
{
    sb.Append($"<strong>{Settings.GetSetting("SitecoreFundamentals.AutoDictionary.CreationReportEmail.NewItem")}:</strong> {reportItem.Path}<br />");
    sb.Append($"<strong>{Settings.GetSetting("SitecoreFundamentals.AutoDictionary.CreationReportEmail.Key")}:</strong> {reportItem.Key}<br />");
    sb.Append($"<strong>{Settings.GetSetting("SitecoreFundamentals.AutoDictionary.CreationReportEmail.ValueText")}:</strong> {reportItem.DefaultValue}<br />");
    sb.Append($"<strong>{Settings.GetSetting("SitecoreFundamentals.AutoDictionary.CreationReportEmail.Language")}:</strong> {reportItem.LanguageName}<br />");
    sb.Append($"<strong>{Settings.GetSetting("SitecoreFundamentals.AutoDictionary.CreationReportEmail.PageUrl")}:</strong> <a href=\"{reportItem.ContextUrl}\">{reportItem.ContextUrl}</a><br />");


Finally, if the emailing task is turned off or there's no sender or destination address nothing is sent.

if (settingsItem.Fields[Constants.Templates.Settings.Fields.SendEmailNotifications].Value != "1")
{
    Log.Info($"{typeof(CreationReport).FullName}.{nameof(Run)} => Dictionary creation emails are disabled. Nothing will be sent.", this);
    return;
}

and

if (string.IsNullOrWhiteSpace(emailFrom) || string.IsNullOrWhiteSpace(emailTo))
{
    Log.Warn($"{typeof(CreationReport).FullName}.{nameof(Run)} => Dictionary creation emails are enabled but the From or To address is empty.", this);
    return;
}

View the code here.


That's it. Let me know if you want changes or improvements to this module, and I'd be happy to hear your ideas!