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.

using Newtonsoft.Json; using Newtonsoft.Json.Converters; using Sitecore; using Sitecore.Data; using Sitecore.Data.Events; using Sitecore.Data.Items; using Sitecore.Data.Managers; using Sitecore.Diagnostics; using Sitecore.Events; using Sitecore.Globalization; using Sitecore.IO; using Sitecore.Publishing; using System; using System.Collections.Generic; using System.Dynamic; using System.Linq; namespace Company.Project.EventHandlers { /// &lt;summary&gt; /// Creates dictionary .json files on publish events /// &lt;/summary&gt; public class SerializeDictionaryToJson { private static ID DictionaryFolderTemplateID = new ID("{267D9AC7-5D85-4E9D-AF89-99AB296CC218}"); public void OnPublishEnd(object sender, EventArgs args) { var sitecoreArgs = args as SitecoreEventArgs; Assert.IsNotNull(sitecoreArgs, "The parameter 'sitecoreArgs' is null"); var publisher = sitecoreArgs.Parameters[0] as Publisher; Assert.IsNotNull(publisher, "The parameter 'publisher' is null"); var rootItem = publisher.Options.RootItem; if (ShouldSearializeDictionary(rootItem)) { SerializeDictionaryToJsonFiles(); } } public void OnPublishEndRemote(object sender, EventArgs args) { var remoteEventArgs = args as PublishEndRemoteEventArgs; Assert.IsNotNull(remoteEventArgs, "The parameter 'remoteEventArgs' is null"); Item rootItem = null; var rootItemID = remoteEventArgs.RootItemId; if (rootItemID != default(Guid)) { var db = Database.GetDatabase("web"); rootItem = db.GetItem(ID.Parse(rootItemID)); } if (ShouldSearializeDictionary(rootItem)) { SerializeDictionaryToJsonFiles(); } } private bool ShouldSearializeDictionary(Item rootItem) { return rootItem == null || rootItem.TemplateID == DictionaryFolderTemplateID || rootItem.TemplateID == TemplateIDs.DictionaryEntry || rootItem.ID == ItemIDs.Dictionary; } public void SerializeDictionaryToJsonFiles() { var db = Database.GetDatabase("web"); var languages = LanguageManager.GetLanguages(db); foreach (var language in languages) { var values = GetDictionaryValues(db, language); CreateDictionaryJsonFile(values, language); } Log.Info("Dictionary has been serialized to json files successfully.", this); } public void CreateDictionaryJsonFile(IDictionary&lt;string, object&gt; values, Language language) { var json = JsonConvert.SerializeObject(values, new KeyValuePairConverter()); var filePath = $"{TempFolder.Folder}/dictionary.{language.Name}.json"; FileUtil.WriteToFile(filePath, json); } public IDictionary&lt;string, object&gt; GetDictionaryValues(Database db, Language language) { IDictionary&lt;string, object&gt; dictionary = new ExpandoObject(); using (new LanguageSwitcher(language)) { var root = db.GetItem("/sitecore/system/Dictionary"); var items = root.Axes.GetDescendants() .Where(i =&gt; i.TemplateID == TemplateIDs.DictionaryEntry); foreach (var item in items) { var key = item[FieldIDs.DictionaryKey]; dictionary[key] = item[FieldIDs.DictionaryPhrase]; } } return dictionary; } } }

COVID-19: Digital Insights For Enterprise Action Access Perficient’s latest insights into how you can leverage digital technologies to not only respond to the pandemic, but drive your operations forward and deliver experiences your customers need. Get Informed

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

&lt;?xml version="1.0" encoding="utf-8"?&gt; &lt;configuration xmlns:patch="http://www.sitecore.net/xmlconfig/"&gt; &lt;sitecore&gt; &lt;events&gt; &lt;event name="publish:end"&gt; &lt;handler type="Company.Project.EventHandlers.SerializeDictionaryToJson, Company.Project" method="OnPublishEnd"/&gt; &lt;/event&gt; &lt;event name="publish:end:remote"&gt; &lt;handler type="Company.Project.EventHandlers.SerializeDictionaryToJson, Company.Project" method="OnPublishEndRemote"/&gt; &lt;/event&gt; &lt;/events&gt; &lt;/sitecore&gt; &lt;/configuration&gt;

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.

define(["jquery"], function ($) { Dictionary._instance = null; function Dictionary() { this.values = {}; } Dictionary.prototype.translate = function (key) { return this.values[key] || key; } Dictionary.prototype.getContextLanguage = function () { return $('meta[http-equiv="content-language"]').attr("content"); } Dictionary.prototype.loadValues = function () { var language = this.getContextLanguage(); var valuesUrl = "/temp/dictionary." + language + ".json"; // We disable browser's cache to ensure translations are up to date $.ajax({ cache: false, async: false, url: valuesUrl }) .done(function (data) { this.values = Object.freeze(data); }.bind(this)) .fail(function () { console.error("Couldn't load dictionary values"); }); } Dictionary.getInstance = function () { if (Dictionary._instance == null) { var dictionary = new Dictionary(); dictionary.loadValues(); Dictionary._instance = dictionary; } return Dictionary._instance; } return Dictionary.getInstance(); });

How to use Dictionary.js

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

define(["Dictionary"], function (dictionary) { function SearchBox(options) { this.noResultsFoundText = dictionary.translate("NoResultsFound"); //... } //... return SearchBox; });

dictionary.en.json snippet

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

dictionary.fr-CA.json snippet

{ ... "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.