From ade99251e4ba36abdce9e5261d0f6565ce6b6952 Mon Sep 17 00:00:00 2001
From: Manuel Kocher <manuel.kocher@tugraz.at>
Date: Thu, 9 Jun 2022 09:03:29 +0200
Subject: [PATCH] Use global var as translation cache instead of sessionStorage

---
 packages/app-shell/src/app-shell.js |  7 +----
 packages/app-shell/src/i18n.js      |  4 +--
 packages/common/i18next.js          | 45 +++++------------------------
 packages/common/src/i18n.js         |  4 +--
 packages/common/src/translation.js  | 42 +++++++++++++++++++++------
 5 files changed, 45 insertions(+), 57 deletions(-)

diff --git a/packages/app-shell/src/app-shell.js b/packages/app-shell/src/app-shell.js
index ecf3fd38..0c7d2a88 100644
--- a/packages/app-shell/src/app-shell.js
+++ b/packages/app-shell/src/app-shell.js
@@ -1,4 +1,4 @@
-import {createInstance, fetchOverridestoSessionStorage} from './i18n.js';
+import {createInstance} from './i18n.js';
 import {html, css} from 'lit';
 import {ScopedElementsMixin} from '@open-wc/scoped-elements';
 import {LanguageSelect} from '@dbp-toolkit/language-select';
@@ -168,11 +168,6 @@ export class AppShell extends ScopedElementsMixin(DBPLitElement) {
         this.metadata = metadata;
         this.routes = routes;
 
-        // fetch translations
-        for(let lng of this._i18n.languages) {
-          fetchOverridestoSessionStorage(this.langDir, lng);
-        }
-
         // Switch to the first route if none is selected
         if (!this.activeView) this.switchComponent(routes[0]);
         else this.switchComponent(this.activeView);
diff --git a/packages/app-shell/src/i18n.js b/packages/app-shell/src/i18n.js
index 090a555c..0c6fedc8 100644
--- a/packages/app-shell/src/i18n.js
+++ b/packages/app-shell/src/i18n.js
@@ -1,4 +1,4 @@
-import {createInstance as _createInstance, fetchOverridestoSessionStorage} from '@dbp-toolkit/common/i18next.js';
+import {createInstance as _createInstance} from '@dbp-toolkit/common/i18next.js';
 
 import de from './i18n/de/translation.json';
 import en from './i18n/en/translation.json';
@@ -6,5 +6,3 @@ import en from './i18n/en/translation.json';
 export function createInstance() {
     return _createInstance({en: en, de: de}, 'de', 'en');
 }
-
-export {fetchOverridestoSessionStorage}
diff --git a/packages/common/i18next.js b/packages/common/i18next.js
index 74e8659d..d72b9abc 100644
--- a/packages/common/i18next.js
+++ b/packages/common/i18next.js
@@ -125,35 +125,17 @@ export function setOverrides(i18n, element, overrides) {
     i18n.setDefaultNamespace(hasOverrides ? overrideNamespace : namespace);
 }
 
-async function fetchOverridesByLanguage(overrides, lng) {
-  let result = await
-      fetch(overrides + lng +'/translation.json', {
-          headers: {'Content-Type': 'application/json'},
-      });
-  let json = await result.json();
-  return json;
-}
-
-export async function fetchOverridestoSessionStorage(overridesFile, lng) {
-  // use local cache for translation file
-  if (sessionStorage.getItem("translation-overrides-" + lng) === null) {
-    // get translation.json for each lang
-    let response = await fetchOverridesByLanguage(overridesFile, lng);
-    sessionStorage.setItem("translation-overrides-" + lng, JSON.stringify(response));
-
-  }
-}
-
 /**
  * Sets translation overrides for the given i18next instance. Any previously
  * applied overrides will be removed first. So calling this with an empty overrides
  * object is equal to removing all overrides.
+ * Expects overrides as promise and requests update after overrides have been set.
  *
  * @param {i18next.i18n} i18n - The i18next instance
  * @param {HTMLElement} element - The element at which the overrides are targeted
- * @param {string} overridesFile - Path to the translation file containing the overrides
+ * @param {object} overrides - The override data as promise
  */
-export async function setOverridesByFile(i18n, element, overridesFile, keyName) {
+export async function setOverridesByPromise(i18n, element, overrides) {
     // We add a special namespace which gets used with priority and falls back
     // to the original one. This way we an change the overrides at runtime
     // and can even remove them.
@@ -164,24 +146,13 @@ export async function setOverridesByFile(i18n, element, overridesFile, keyName)
     let overrideNamespace = getOverrideNamespace(namespace);
     let hasOverrides = false;
     for (let lng of i18n.languages) {
-
-        await fetchOverridestoSessionStorage(overridesFile, lng);
-
-        let response = JSON.parse(sessionStorage.getItem("translation-overrides-" + lng));
-
-        // remove old language
+        overrides[lng] = await overrides[lng];
         i18n.removeResourceBundle(lng, overrideNamespace);
-        // if no new translation is available, skip
-        if (response === undefined || response[tagName] === undefined) return;
-        // get new translation
-        let resource = {};
-        resource[keyName] = response[tagName][keyName];
+        if (overrides[lng] === undefined || overrides[lng][tagName] === undefined) continue;
+        let resources = overrides[lng][tagName];
         hasOverrides = true;
-
-        // set new translation
-        i18n.addResourceBundle(lng, overrideNamespace, resource);
+        i18n.addResourceBundle(lng, overrideNamespace, resources);
     }
-
     i18n.setDefaultNamespace(hasOverrides ? overrideNamespace : namespace);
-    return i18n;
+    element.requestUpdate();
 }
diff --git a/packages/common/src/i18n.js b/packages/common/src/i18n.js
index 63ed95a6..1db56149 100644
--- a/packages/common/src/i18n.js
+++ b/packages/common/src/i18n.js
@@ -1,4 +1,4 @@
-import {createInstance as _createInstance, setOverridesByFile} from '../i18next.js';
+import {createInstance as _createInstance, setOverridesByPromise} from '../i18next.js';
 
 import de from './i18n/de/translation.json';
 import en from './i18n/en/translation.json';
@@ -11,4 +11,4 @@ export function createInstanceGivenResources(en, de) {
     return _createInstance({en: en, de: de}, 'de', 'en');
 }
 
-export {setOverridesByFile};
+export {setOverridesByPromise};
diff --git a/packages/common/src/translation.js b/packages/common/src/translation.js
index d0fd965c..f459f2fc 100644
--- a/packages/common/src/translation.js
+++ b/packages/common/src/translation.js
@@ -1,7 +1,33 @@
 import {css, html} from 'lit';
 import {unsafeHTML} from 'lit/directives/unsafe-html.js';
 import DBPLitElement from '../dbp-lit-element';
-import {createInstanceGivenResources, setOverridesByFile} from './i18n.js';
+import {createInstanceGivenResources, setOverridesByPromise} from './i18n.js';
+
+// global variable as cache for translations
+const translationCache = {};
+
+// fetches overrides for given language
+async function fetchOverridesByLanguage(overrides, lng) {
+  let result = await
+      fetch(overrides + lng +'/translation.json', {
+          headers: {'Content-Type': 'application/json'},
+      });
+  let json = await result.json();
+  return json;
+}
+
+// handles translation cache promises
+async function cacheOverrides(overridesFile, lng) {
+  // use global var as cache
+  if (translationCache[lng] === undefined) {
+    // get translation.json for each lang
+    let response = fetchOverridesByLanguage(overridesFile, lng);
+    translationCache[lng] = response;
+    return response;
+  } else {
+    return translationCache[lng];
+  }
+}
 
 export class Translation extends DBPLitElement {
     constructor() {
@@ -40,17 +66,15 @@ export class Translation extends DBPLitElement {
       const en = {};
       de[this.key] = "";
       en[this.key] = "";
-
+      
       // create i18n instance with given translations
       this._i18n = createInstanceGivenResources(en, de);
-      let local = this;
-      if (this.langDir) {
-
-        // after init of overrides re-render page
-        setOverridesByFile(this._i18n, this, this.langDir, this.key).then(function(response) {
-            local.requestUpdate();
-        });
 
+      if (this.langDir) {
+        for(let lng of this._i18n.languages) {
+          cacheOverrides(this.langDir, lng);
+          setOverridesByPromise(this._i18n, this, translationCache);
+        }
       }
     }
 
-- 
GitLab