Skip to main content

Back-End Development

How to Get Sitecore Dictionary in JavaScript

Pc Setup@1x.jpg

It’s very easy to get translations in back-end code — either Razor views or .cs files — by simply calling to Sitecore.Globalization.Translate.Text(). But what about JavaScript widgets? There we have several options:

  • Item Web API results in overhead and is hard to use without additional implementation.
  • StringDictionary embeds values right in HTML and needs to be configured accordingly.
  • Injecting translated text into .js components via HTML tags has the same drawbacks as StringDictionary.

All these options are cumbersome and inconvenient.

I will show you a convenient way to have Translate.Text() right in JavaScript! The idea is to use a JavaScript dictionary object in our .js widgets/components. To achieve the goal we need the following:

  • Serialize dictionary values into .json files
  • Implement Dictionary.js

Let’s start coding!

Serializing the dictionary into .json files

Serializing the whole dictionary creates one .json file per language in a temp folder. The file’s name looks like “dictionary.{language}.json”, e.g. “dictionary.fr-CA.json”. The dictionary is serialized each time we perform a site publish or when we publish a Dictionary root item or its descendants.

1using Newtonsoft.Json;
2using Newtonsoft.Json.Converters;
3using Sitecore;
4using Sitecore.Data;
5using Sitecore.Data.Events;
6using Sitecore.Data.Items;
7using Sitecore.Data.Managers;
8using Sitecore.Diagnostics;
9using Sitecore.Events;
10using Sitecore.Globalization;
11using Sitecore.IO;
12using Sitecore.Publishing;
13using System;
14using System.Collections.Generic;
15using System.Dynamic;
16using System.Linq;
17 
18namespace Company.Project.EventHandlers
19{
20/// <summary>
21/// Creates dictionary .json files on publish events
22/// </summary>
23public class SerializeDictionaryToJson
24{
25private static ID DictionaryFolderTemplateID = new ID("{267D9AC7-5D85-4E9D-AF89-99AB296CC218}");
26 
27public void OnPublishEnd(object sender, EventArgs args)
28{
29var sitecoreArgs = args as SitecoreEventArgs;
30Assert.IsNotNull(sitecoreArgs, "The parameter 'sitecoreArgs' is null");
31 
32var publisher = sitecoreArgs.Parameters[0] as Publisher;
33Assert.IsNotNull(publisher, "The parameter 'publisher' is null");
34 
35var rootItem = publisher.Options.RootItem;
36 
37if (ShouldSearializeDictionary(rootItem))
38{
39SerializeDictionaryToJsonFiles();
40}
41}
42 
43public void OnPublishEndRemote(object sender, EventArgs args)
44{
45var remoteEventArgs = args as PublishEndRemoteEventArgs;
46Assert.IsNotNull(remoteEventArgs, "The parameter 'remoteEventArgs' is null");
47 
48Item rootItem = null;
49var rootItemID = remoteEventArgs.RootItemId;
50if (rootItemID != default(Guid))
51{
52var db = Database.GetDatabase("web");
53rootItem = db.GetItem(ID.Parse(rootItemID));
54}
55 
56if (ShouldSearializeDictionary(rootItem))
57{
58SerializeDictionaryToJsonFiles();
59}
60}
61 
62private bool ShouldSearializeDictionary(Item rootItem)
63{
64return rootItem == null ||
65rootItem.TemplateID == DictionaryFolderTemplateID ||
66rootItem.TemplateID == TemplateIDs.DictionaryEntry ||
67rootItem.ID == ItemIDs.Dictionary;
68}
69 
70public void SerializeDictionaryToJsonFiles()
71{
72var db = Database.GetDatabase("web");
73var languages = LanguageManager.GetLanguages(db);
74 
75foreach (var language in languages)
76{
77var values = GetDictionaryValues(db, language);
78CreateDictionaryJsonFile(values, language);
79}
80 
81Log.Info("Dictionary has been serialized to json files successfully.", this);
82}
83 
84public void CreateDictionaryJsonFile(IDictionary<string, object> values, Language language)
85{
86var json = JsonConvert.SerializeObject(values, new KeyValuePairConverter());
87var filePath = $"{TempFolder.Folder}/dictionary.{language.Name}.json";
88FileUtil.WriteToFile(filePath, json);
89}
90 
91public IDictionary<string, object> GetDictionaryValues(Database db, Language language)
92{
93IDictionary<string, object> dictionary = new ExpandoObject();
94 
95using (new LanguageSwitcher(language))
96{
97var root = db.GetItem("/sitecore/system/Dictionary");
98 
99var items = root.Axes.GetDescendants()
100.Where(i => i.TemplateID == TemplateIDs.DictionaryEntry);
101 
102foreach (var item in items)
103{
104var key = item[FieldIDs.DictionaryKey];
105dictionary[key] = item[FieldIDs.DictionaryPhrase];
106}
107}
108 
109return dictionary;
110}
111}
112}

The last thing is to plug SerializeDictionaryToJson.cs to publish:end and publish:end:remote events by using patch config.

1<?xml version="1.0" encoding="utf-8"?>
2<configuration xmlns:patch="http://www.sitecore.net/xmlconfig/">
3<sitecore>
4<events>
5<event name="publish:end">
6<handler type="Company.Project.EventHandlers.SerializeDictionaryToJson, Company.Project" method="OnPublishEnd"/>
7</event>
8<event name="publish:end:remote">
9<handler type="Company.Project.EventHandlers.SerializeDictionaryToJson, Company.Project" method="OnPublishEndRemote"/>
10</event>
11</events>
12</sitecore>
13</configuration>

 

Implement Dictionary.js

I assume you are using a module loader; in my example it’s require.js. Dictionary.js loads the proper .json file only once per page based on the current context language and provides translation.

1define(["jquery"], function ($) {
2 
3Dictionary._instance = null;
4 
5function Dictionary() {
6this.values = {};
7}
8 
9Dictionary.prototype.translate = function (key) {
10return this.values[key] || key;
11}
12 
13Dictionary.prototype.getContextLanguage = function () {
14return $('meta[http-equiv="content-language"]').attr("content");
15}
16 
17Dictionary.prototype.loadValues = function () {
18var language = this.getContextLanguage();
19var valuesUrl = "/temp/dictionary." + language + ".json";
20 
21// We disable browser's cache to ensure translations are up to date
22$.ajax({ cache: false, async: false, url: valuesUrl })
23.done(function (data) {
24this.values = Object.freeze(data);
25}.bind(this))
26.fail(function () {
27console.error("Couldn't load dictionary values");
28});
29}
30 
31Dictionary.getInstance = function () {
32if (Dictionary._instance == null) {
33var dictionary = new Dictionary();
34dictionary.loadValues();
35Dictionary._instance = dictionary;
36}
37return Dictionary._instance;
38}
39 
40return Dictionary.getInstance();
41});

 

How to use Dictionary.js

In this sample, our SearchBox widget utilizes translations based on the current page language.

1define(["Dictionary"], function (dictionary) {
2 
3function SearchBox(options) {
4this.noResultsFoundText = dictionary.translate("NoResultsFound");
5 
6//...
7}
8 
9//...
10 
11return SearchBox;
12});

dictionary.en.json snippet

1{ ... "NoResultsFound": "Sorry, we have no content matching your criteria." ... }

dictionary.fr-CA.json snippet

1{ ... "NoResultsFound": "Désolé, nous avons aucun contenu ne correspond à vos critères." ... }

 

Dictionary.js features

  • Doesn’t inject values into HTML.
  • Doesn’t impact SEO.
  • Lazy loading.
  • No need to configure.
  • Small overhead: serialized .json file is 13kB for 300 items in real-world application.
  • Can be loaded from browser’s cache.

Thoughts on “How to Get Sitecore Dictionary in JavaScript”

  1. Maksim Shamihulau Post author

    > Thanks for pointing me out, you’re absolutely right. I will update the post in case of CD.

  2. That’s very similar to a way how translation is done in Experience Editor(look at TranslationUtil.js).
    define([“sitecore”], function (Sitecore) {
    var translationUtils = {
    keys: {
    },

    translateText: function (key) {
    return Sitecore.Resources.Dictionary[key];
    },

    translateTextByServer: function (key) {

    },
    };

    return translationUtils;
    });

  3. Maksim Shamihulau Post author

    TranslationUtil.js looks ‘similar’ but:
    TranslationUtil.translateText uses values injected in html and StringDictionary needs to be configured for each page.
    TranslationUtil.translateTextByServer can be used in Experience Editor context only and sends one ajax per ‘key’ which results in request/response overhead.

    The approach described in the post uses more flexible way without needs to configure, injections and so on.

  4. Pingback: Sitecore Dictionaries Best Practices | Sitecore notes - Stelio Di Bello

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.

Maksim Shamihulau

Maksim is a full stack web applications and game developer. He has many years of experience with Sitecore, and is a certified Sitecore Website .NET Developer. Maksim also has a Brainbench Master Certification in C# 4.0 and extensive knowledge of many programming technologies such as .NET, JavaScript and ASP.net.

More from this Author

Follow Us