How do you reference your Dictionary?

One of the requirements for the new GoCollette website was there were to be no hard coded text on the site. If we needed a Spanish version of the site, we didn’t want it to break because we were not utilizing the CMS to what it can do naturally. Due to this requirement we needed to create many dictionary items and therefore reference them throughout the web project.

Thankfully Sitecore is well equipped for this type of scenario. They provide us with a Translate class where you can easily reference your dictionary items by calling the Text() method: Translate.Text(“SomeDictionaryKey”);

The problem I see with this approach is that you have to remember the key or go back to Sitecore to look it up. What happens when you make a spelling mistake, you have a duplicate key in the system, or if the key doesn’t exist because it wasn’t packaged up during a deployment?

Solution

The solution is based on a class called the Dictionary Reference Object. It’s a simple wrapper that takes a GUID in it’s constructor and gives us easy access to it’s properties. We have direct access to the sitecore item, the phrase, and it’s key.

You might be wondering why this is any better than calling Translate.Text? You still need to remember the guid, right? Wrong, keep reading below 🙂

public class DictionaryReferenceObject
{
	public DictionaryReferenceObject(string guid)
	{
		Guid = guid;

		Database db = Sitecore.Context.Database;
		if (db.Name.ToLower() == "core")
		{
			db = Database.GetDatabase("web");
		}

		Item item = db.GetItem(guid);
		if (item == null)
		{
			return;
		}

		InnerItem = item;
	}

	/// <summary>
	/// Sitecore dictionary item
	/// </summary>
	public Item InnerItem { get; private set; }

	/// <summary>
	/// ID of the dictionary item
	/// </summary>
	public string Guid { get; private set; }

	/// <summary>
	/// Dictionary Key
	/// </summary>
	public string Key
	{
		get
		{
			if (InnerItem == null)
			{
				return string.Empty;
			}

			return InnerItem["Key"];
		}
	}

	/// <summary>
	/// Translated Dictionary Phrase
	/// </summary>
	public string Phrase
	{
		get
		{
			if (string.IsNullOrEmpty(Key))
			{
				return string.Empty;
			}

			return Translate.Text(InnerItem["Phrase"]);
		}
	}
}

Auto-Generated Dictionary Reference Class

When we reference the dictionary, we do it through an auto-generated dictionary reference class that is hooked into the “item:saved” event. This class gives us easy access to the dictionary items using an object orientated approach where each dictionary item is represented by a dictionary reference object. From our code base we can reference one by calling: DictionaryReference.Common_Calendar_Day.Phrase

Below is a code snippet that shows how we have hooked into the “item:saved” event. We have a handler called CreateDictionaryReferences which is responsible for iterating over each of the dictionary items and regenerating the DictionaryReference class (shown below). This only runs on our local development environment thanks to a little help from our friend nant (no need to have this event handler in production!).

Review the code below and feel free to implement it into your own solution. As always, if you have any questions I’m happy to help.
Thanks!
Tim

Config Patch

<events>
	<event name="item:saved">
		<handler type="Collette.Library.CustomSitecore.Events.Saved.CreateDictionaryReferences, Collette.Library" method="OnItemSaved" />
	</event>
</events>

Dictionary Reference Class

public class DictionaryReference
{
	public static DictionaryReferenceObject Common_Calendar_Day { get { return new DictionaryReferenceObject("{030404AF-BE2E-4FF9-8FFB-271A4F69D257}"); } }
	public static DictionaryReferenceObject Common_Calendar_Days { get { return new DictionaryReferenceObject("{47DE515E-376A-4157-9F72-5AB2C7B43433}"); } }
	public static DictionaryReferenceObject Common_Calendar_Hour { get { return new DictionaryReferenceObject("{ABD5670C-DC64-43B5-8E62-142BE6864CAB}"); } }
	public static DictionaryReferenceObject Common_Calendar_Hours { get { return new DictionaryReferenceObject("{9904EA9F-040A-419F-947D-82D72C9BEAF2}"); } }
	public static DictionaryReferenceObject Common_Calendar_Month { get { return new DictionaryReferenceObject("{B939FD03-717B-466F-9540-4D67C64ED33B}"); } }
	public static DictionaryReferenceObject Common_Calendar_Year { get { return new DictionaryReferenceObject("{716299C3-048A-4F2A-914E-CAB62BE92DB9}"); } }
}

Class that generates the Dictionary Reference Class

public class CreateDictionaryReferences
{
	private string _path = WebConfigurationManager.AppSettings["Sitecore.DataDirectory"].ToString();
	private Item _dictionaryItem;

	private Item DictionaryFolderItem
	{
		get
		{
			_dictionaryItem = Database.GetDatabase("master").GetItem(ItemReference.System_Dictionary.Guid);
			if (_dictionaryItem == null)
			{
				return null;
			}

			return _dictionaryItem;
		}
	}

	/// <summary>
	/// On save, recreate the dictionary reference class
	/// </summary>
	/// <param name="sender"></param>
	/// <param name="args"></param>
	public void OnItemSaved(object sender, EventArgs args)
	{
		if (!ConfigurationSettings.DictionaryReference_BuildOnSave)
		{
			return;
		}

		if (args == null)
		{
			return;
		}

		//take item from args
		SitecoreEventArgs sitecoreArgs = args as SitecoreEventArgs;
		Assert.IsNotNull(sitecoreArgs, "eventArgs");

		SitecoreEventArgs eventArgs = args as SitecoreEventArgs;
		Assert.IsNotNull(eventArgs, "eventArgs");
		Item currentItem = eventArgs.Parameters[0] as Item;
		Assert.IsNotNull(currentItem, "item");


		//verify we have an item and that it is of a dictionary item
		if (currentItem == null || !currentItem.IsOfTemplate(TemplateIDs.DictionaryEntry.ToString()))
		{
			return;
		}

		if (DictionaryFolderItem == null)
		{
			return;
		}

		TextWriter builder = new StreamWriter(_path);

		builder.WriteLine("namespace Collette.Library.Reference");
		builder.WriteLine("{");
		builder.WriteLine("	public class DictionaryReference");
		builder.WriteLine("	{");

		foreach (Item item in DictionaryFolderItem.Axes.GetDescendants().Where(x => x.IsOfTemplate(TemplateIDs.DictionaryEntry.ToString())))
		{
			if (item == null)
			{
				continue;
			}

			builder.WriteLine(GetReferenceString(item));
		}

		builder.WriteLine("	}");
		builder.WriteLine("}");
		builder.Close();

		ICache cache = CacheFactory.GetCache();
		cache.Remove(string.Format("{0}.DictionaryService", Sitecore.Context.GetSiteName()));
	}

	private string GetReferenceString(Item dictionaryItem)
	{
		string name = GetName(dictionaryItem);
		return "		public static DictionaryReferenceObject " + name + " { get { return new DictionaryReferenceObject(\"" + dictionaryItem.ID + "\"); } }";
	}

	private string GetName(Item dictionaryItem)
	{
		List<string> names = new List<string>();

		bool metTarget = false;
		foreach (Item ancestor in dictionaryItem.Axes.GetAncestors())
		{
			if (ancestor == null)
			{
				continue;
			}

			if (ancestor.ID.ToString() == DictionaryFolderItem.ID.ToString())
			{
				metTarget = true;
				continue;
			}

			if (!metTarget)
			{
				continue;
			}

			names.Add(CleanName(ancestor.Name));
		}

		names.Add(CleanName(dictionaryItem.Name));

		return StringUtil.Join(names, "_");
	}

	/// <summary>
	/// Capitalize each word, remove spaces
	/// </summary>
	/// <param name="name"></param>
	/// <returns></returns>
	private string CleanName(string name)
	{
		name = Collette.Library.Util.ItemUtil.GetItemName(name);
		name = name.Replace(" ", string.Empty);

		return name;
	}
}

One thought on “How do you reference your Dictionary?

  1. Pingback: You should probably start using Sitecore Dictionary Domains | Sitecore.Context.Item

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s