Caching - Dictionary Service in Sitecore-JSS
Akif Irfan
Sr. Sitecore Consultant @ Edari | Sitecore? 9.0 Certified Platform Associate Developer
I outlined the below?scenario in a?previous post. In this article, we will focus on performance improvement.
"Default, you might observe that your JSS application, built using the Sitecore starting template, requests data from /Sitecore/API/dictionary each time a page loads.
Knowing that Sitecore dictionaries are pretty static and that client-side queries are made regardless of whether your application is running headless or integrated with SSR,?it is not just an ideal choice."
The starter?template has a suggestion?in?/src/i18n.js file to cache the dictionary data.
Install the packages i18next-chained-backend, i18next-localstorage-backend, and i18next-fetch-backend (if not previously installed).
npm install i18next-chained-backend
npm install i18next-localstorage-backend
npm install i18next-fetch-backend
领英推荐
Note: i18next.js is a translation module. It may be difficult to understand if you are not familiar with it. Simply adhere to the guidelines.
Replace the following code in the src/i18n.js file after installing the packages. With this modification, the dictionary data will be cached in local storage for 10?minutes.
import i18n from 'i18next';
// eslint-disable-next-line import/no-extraneous-dependencies
import backend from 'i18next-chained-backend';
// eslint-disable-next-line import/no-extraneous-dependencies
import localStorageBackend from 'i18next-localstorage-backend';
// eslint-disable-next-line import/no-extraneous-dependencies
import fetchBackend from 'i18next-fetch-backend';
import { initReactI18next } from 'react-i18next';
import { dictionaryServiceFactory } from './lib/dictionary-service-factory';
import config from './temp/config';
/**
* Initializes the i18next library to provide a translation dictionary to the app.
* If your app is not multilingual, this file and references to it can be removed.
* Elsewhere in the app to use the dictionary `import { t } from 'i18next'; ... t('key')`
* @param {string} language Optional, the initial language. Only used for SSR; otherwise language set in RouteHandler.
* @param {*} dictionary Optional, the dictionary to load. Only used for SSR; otherwise, the dictionary is loaded via JSS dictionary service.
*/
export default function i18nInit(language, dictionary) {
return new Promise((resolve, reject) => {
const options = {
debug: false,
lng: language,
fallbackLng: false, // fallback to keys
load: 'currentOnly', // e.g. don't load 'es' when requesting 'es-MX' -- Sitecore config should handle this
useCookie: false, // using URLs and Sitecore to store language context, don't need a cookie
interpolation: {
escapeValue: false, // not needed for react
},
};
if (dictionary) {
// if we got dictionary passed, that means we're in a SSR context with a server-provided dictionary
// so we do not want a backend, because we already know all possible keys
if (!i18n.isInitialized) {
i18n.use(initReactI18next).init(options, (error) => {
if (error) reject(error);
i18n.addResourceBundle(language, 'translation', dictionary, true, true);
resolve();
});
} else {
i18n.changeLanguage(language).then(() => {
i18n.addResourceBundle(language, 'translation', dictionary, true, true);
resolve();
});
}
} else {
// We're running client-side, so we get translation data from the Sitecore dictionary API using fetch backend
// For higher performance (but less simplicity), consider adding the
// i18n chained backend to a local cache option like the local storage backend.
// instantiate the dictionary service.
const dictionaryServicePath = `${config.sitecoreApiHost}/sitecore/api/jss/dictionary/${config.jssAppName}/{{lng}}?sc_apikey=${config.sitecoreApiKey}`;
options.backend = {
backends: [localStorageBackend, fetchBackend],
backendOptions: [
{
prefix: 'jss-dic-translation', // cache prefix use your app name here
expirationTime: 10 * 60 * 1000, // cache for 10 minutes
},
{
loadPath: dictionaryServicePath,
parse: (data) => {
const parsedData = JSON.parse(data);
if (parsedData.phrases) {
return parsedData.phrases;
}
return parsedData;
},
},
],
};
i18n
.use(backend)
.use(initReactI18next)
.init(options, (error) => {
if (error) reject(error);
resolve();
});
}
});
}
Start the application in connected mode and reload the page, now you see the dictionary is cached for 10 minutes in local storage.
I've configured a 10-minute cache expiration period in my case, but you may adjust it to suit your needs by changing the highlighted string below.
I hope this post?is useful to you.
Thanks.