LibrarySites.Banner

Fallback Series Post 5: Using Fallback with the Dictionary

When creating a multilingual site in Sitecore, a common practice is to leverage the out-of-the-box functionality of the Sitecore Dictionary.  Every piece of text on the site should be dynamic so that when users switch languages, everything can be translated.

The Sitecore Dictionary can be found in any Sitecore installation at /sitecore/system/dictionary.  You can create one or more Sitecore Dictionary Folder items in this location which enables any preferred method of organization.  We typically create folders for each letter of the alphabet within the Dictionary Folder: A, B, C, etc.

Each Dictionary Entry item has two fields: Key and Phrase.  Key is a Shared Field which means that the field is shared across all language and number versions and is not meant to be different across versions.  The Phrase field is a multiline text field and is an Unversioned Field, meaning it can differ across language versions (but not number versions).  The idea is that you can create several different language versions of the same item and then change the Phrase value for each language. 

In the code, wherever you would have 'static' text (text not otherwise being managed through content items), instead of setting the text directly in the html or code-behind, you would add a Dictionary Entry item and then reference the Key via the Globalization Translate method.

Sitecore.Globalization.Translate.Text("Keyword")

The naming convention for keywords should be something that makes the most sense for your content authors, since ultimately they will be the ones maintaining this text and translating it.  In versions of Sitecore before 6.6, all dictionary entries had to be within the /sitecore/system/dictionary folder and ALL sites in your Sitecore instance used the same pool of entries.  This limitation meant that you would need to prefix all of your keywords for each site.  So this would have to be part of your naming strategy. You could set the Key values to be something having to do with where the key is being used, but that would limit reuse of the same phrase across the site.  It would have to be in the context of the front-end of the site location, not code location, since the latter obviously would be meaningless to the content author.   We typically will use the main words in the phrase being output, eg: "View_All" or "Read_More". 

Since Sitecore 6.6, you can now set different Dictionary locations for each site in your Sitecore instance.  I HIGHLY recommend doing this.  This removes the need for having Site prefixes added to your Dictionary Keys.  You would add this to your site node in your Sitecore.SharedSource.PartialLanguageFallback.config file or whatever config file where you prefer adding your site attributes:

<patch:attribute name="dictionaryDomain">{GUID}</patch:attribute>

You would set {GUID} to the GUID of the Dictionary Domain item under which the Dictionary Folders and Entries for the current site live.  In Sitecore you might have the following content tree:

Sitecore Fallback

 

Once this is all setup, when developing the site, you simply need to add the dictionary entry for every piece of static text that comes up and then reference the Key with the Translate method.  On publish of the dictionary item, it prompts Sitecore to update a Dictionary.dat file that is stored in the temp folder of all of the server specific sites.  The front-end will use this dictionary.dat file to pull the values for display.

Note that versions of Sitecore before 6.6 had trouble with CD environments and notifying them that their dictionary.dat file needed to be refreshed.  Sitecore should be able to provide a patch that fixes that for earlier versions of Sitecore.

There is, however, a customization that needs to be added to make the Dictionary work with Alex Shyba's Partial Language Fallback Module

We discovered this need towards the end of development of a site that was implementing both Dictionary and the fallback module.  We had updated the Dictionary template fields to have 'Enabled Fallback If Configured' checked ‘true’ (which is a necessary step for any template that needs to fall back).  The language was set to fall back.  We did indeed have blank versions of each language created for the Dictionary items.  The dictionary item was successfully falling back in the content editor.  Yet on the front-end, it was displaying the Key instead of the Phrase when viewing the site through the context of a language that falls back.  Sitecore displays the Key when the Key/Phrase is not found in the dictionary.

WARNING: This specific example is compatible with Sitecore 6.6 and above.  If you are looking to fix the dictionary for a version before 6.6, you will need to take a look at some of the getTranslation pipeline processors using reflection and use the concepts from what I do below, but make it specific for your version.  This is how I came up with this logic, specifically looking at the guts of the TryGetFromCoreDatabase method.

After spending some time looking at the getTranslation pipeline, I found that it was not taking fallback into consideration (which makes sense since fallback is only added in with an extra module).  To resolve the issue, I added in an additional processor to the getTranslation pipeline, TryGetFromFallbackLanguage, patching it in after the TryGetFromCoreDatabase processor within the Sitecore.SharedSource.PartialLanguageFallback.config file.

<getTranslation>

        <!-- Custom pipeline processor that will get the fallback language of the current language

        and attempt to get the translation of that, as a final step in getTranslation -->

        <processor patch:after="*[@type='Sitecore.Pipelines.GetTranslation.TryGetFromCoreDatabase, Sitecore.Kernel']" type="Verndale.SharedSource.SitecoreProcessors.TryGetFromFallbackLanguage, Verndale.SharedSource" />

      </getTranslation>

Using other getTranslation steps as examples, TryGetFromFallbackLanguage implements TryGetFromFallbackDomains.  It gets the correct dictionary domain and then calls a method called TryTranslateTextByFallbackLanguage and does the following:

  • Check if the language passed in with the args has fallback assigned.
  • If so, then get that fallback language.
  • Must try to get the translation based on that language.
  • Set the following: this.Args.Language = fallbackLanguage.
  • This will allow us to use the TryGetTranslation that was added to the TryGetFromCoreDatabase processor.
    • This is important because the methods it uses to get the actual translation is internal and our code can't use it directly.
  • If TryGetTranslation for the fallback language is successful, great, it will return that result.
  • If it is NOT successful, it will recursively call itself passing the fallbackLanguage to TryTranslateTextByFallbackLanguage.
      • This way, it will keep searching back through fallback to any potential fallback value, no matter how far back in chained languages it has to go.

By adding this pipeline processor to your solution, you will now be ready to use the Sitecore Dictionary and Alex's Partial Language Fallback Module together.  Don't forget to update the Dictionary entry template so that it's field’s fallback (by checking the Enable fallback checkbox for each field or clicking the Enable Fallback ribbon button while on the Dictionary entry template).

Link to Resources:

https://github.com/Verndale-Corp/Sitecore-Fallback-Dictionary-Updates

https://github.com/Verndale-Corp/Sitecore-Fallback-FullDemo

  • Great post, very helpful!  We had to implement dictionary fallback for one of our sites but we were using numerous domains and specifying them using Translate.TextByDomain().  For anyone else that might need this, you can modify line 40 of TryGetFromFallbackLanguage.cs to first try the domain name passed in the args before using the config defined dictionary domain.   string domainName = args.DomainName ?? Context.Site.DictionaryDomain;  if (!DictionaryDomain.TryParse(domainName, this.Database, out domain) || domain == null)                 return;  Thank you for the excellent series.