Friday, May 30, 2014

Building support for multilingual content labels in Sitecore 7

When developing a multilingual site, one of the considerations (although maybe not one of the major ones) is translating all of those labels on buttons and other static elements on the page.

There are a couple of ways you could deal with those:
1.     Create a resource file to store string translations
2.     Use the built-in Sitecore dictionary: ex. Sitecore.Globalization.Translate.Text("More") 

From the two above, I would prefer to leave all translation responsibilities to the content editors (and possibly translation services...). However, the Sitecore Dictionary is hidden under /sitecore/system, which is not always available to content editors due to various permissions and access rights.


I wanted a way to allow the content editors to use a translation layer without having to alter permissions. So I created a Dictionary under /sitecore/content that would be accessible to content editors to create items and language versions. Since I didn't care much about the content hierarchy within the dictionary and I wanted quick and efficient word lookups, I marked the DictionaryItem template as bucketable and made my Dictionary a bucket.














I use the name of the dictionary item as a key for my look up and run a query to retrieve the first available search result with that name. Then all that's left is to get the corresponding item in the language version that's requested and return the text value.

This will work when you don’t want to grant your editors access to /sitecore/system. Content editors enter text into the item and create different language versions, then the static elements of the page get updated in accordance with the language version being requested. I haven’t fully tested the performance implications of doing this vs. the built-in Sitecore Dictionary, but I don’t foresee there being any large impact. If you have any suggestions, I’d love to hear them!


Below is my Dictionary class:

    /// <summary>
    /// The Dictionary class
    /// </summary>
    public class Dictionary
    {
        private const string DICTIONARY_PATH = "/sitecore/content/Data/Dictionary";
        private readonly ID DictionaryItemTemplateId = new ID("{C406784E-4E98-4671-ACC9-DCCFDF680B44}");

        /// <summary>
        /// Gets the dictionary value for the current language.
        /// </summary>
        /// <param name="key">The key.</param>
        /// <returns></returns>
        public string GetDictionaryValue(string key)
        {
            return GetDictionaryValue(key, Sitecore.Context.Item.Language);
        }

        /// <summary>
        /// Gets the dictionary value.
        /// </summary>
        /// <param name="key">The key.</param>
        /// <param name="language">The language.</param>
        /// <returns></returns>
        /// <exception cref="System.ArgumentNullException"></exception>
        public string GetDictionaryValue(string key, Language language)
        {
            string dictionaryValue;

            // key is a required paramater
            if (key == null)
            {
                throw new ArgumentNullException("key");
            }

            if (language != null)
            {
                Item dictionary = Sitecore.Context.Database.GetItem(DICTIONARY_PATH);

                if (dictionary != null)
                {
                    ISearchIndex index = ContentSearchManager.GetIndex(new SitecoreIndexableItem(dictionary));
                    using (IProviderSearchContext searchContext = index.CreateSearchContext())
                    {
                        SearchResultItem searchResult = searchContext.GetQueryable<SearchResultItem>()
                            .Where(resultItem => resultItem.Path.Contains(dictionary.Paths.FullPath))
                            .Where(resultItem => resultItem.TemplateId == DictionaryItemTemplateId)
                            .FirstOrDefault(resultItem => resultItem.Name == key);

                        if (searchResult != null)
                        {
                            Item dictionaryItem = Sitecore.Context.Database.GetItem(searchResult.ItemId, language);
                            dictionaryValue = dictionaryItem["Text"];
                        }
                        else
                        {
                            //no translation found
                            dictionaryValue = key;
                        }
                    }
                }
                else
                {
                    // dictionary does not exist in the current context
                    Log.Error(string.Format("Dictionary Folder Item not found: {0}.", DICTIONARY_PATH), typeof (Dictionary));
                    dictionaryValue = key;
                }
            }
            else
            {
                // dictionary value cannot be translated without a specified language
                dictionaryValue = key;
            }

            return dictionaryValue;
        }
    }