diff --git a/README.md b/README.md
index 2ea0ba3a980e9c416e284576522d6eb8b8400eb4..52c91eafcbfde87468e92a8304fea499bb2c933f 100644
--- a/README.md
+++ b/README.md
@@ -35,7 +35,7 @@ the version number in its `package.json` is higher than the version number on np
 | `unsubscribe`                 | Reserved for future use                                                           |
 | `auth`                        | Authentication information, set by the authentication component                   |
 | `lang`                        | Currently selected language, set by the language selector                         |
-| `lang-file`                   | Location of the i18n language file where all required i18n translations are       |
+| `lang-dir`                    | Location of the i18n language file where all required i18n translations are       |
 | `entry-point-url`             | Entry point url for all api requests                                              |
 | `requested-login-status`      | Used by the login buttons to trigger a login in auth components                   |
 | `initial-file-handling-state` | Used by the file-handling component to sync file source/sink at first time open   |
diff --git a/packages/app-shell/src/app-shell.js b/packages/app-shell/src/app-shell.js
index 53397c4e4edd3ae6a8c8d12aaa31d53ecf9276f0..0c7d2a8805f13dafeeabff56f604b1d3a618fcb9 100644
--- a/packages/app-shell/src/app-shell.js
+++ b/packages/app-shell/src/app-shell.js
@@ -74,7 +74,7 @@ export class AppShell extends ScopedElementsMixin(DBPLitElement) {
         this.initateOpenMenu = false;
 
         this.auth = {};
-        this.langFile = '';
+        this.langDir = '';
     }
 
     static get scopedElements() {
@@ -272,7 +272,7 @@ export class AppShell extends ScopedElementsMixin(DBPLitElement) {
             buildTime: {type: String, attribute: 'build-time'},
             env: {type: String},
             auth: {type: Object},
-            langFile: {type: String, attribute: 'lang-file'},
+            langDir: {type: String, attribute: 'lang-dir'},
         };
     }
 
diff --git a/packages/common/dbp-common-demo.js b/packages/common/dbp-common-demo.js
index 5f5b9bc0f94bd8b218ca979e82d531b869e46193..f9e6ac69f43615471c7a23b7cafc8dd91ab12d83 100644
--- a/packages/common/dbp-common-demo.js
+++ b/packages/common/dbp-common-demo.js
@@ -15,13 +15,15 @@ import {
     Translation,
 } from './index.js';
 
+
+
 export class DbpCommonDemo extends ScopedElementsMixin(LitElement) {
     constructor() {
         super();
         this._i18n = createInstance();
         this.lang = this._i18n.language;
         this.noAuth = false;
-        this.langFile = '';
+        this.langDir = '';
     }
 
     static get scopedElements() {
@@ -47,7 +49,7 @@ export class DbpCommonDemo extends ScopedElementsMixin(LitElement) {
         return {
             lang: {type: String},
             noAuth: {type: Boolean, attribute: 'no-auth'},
-            langFile: {type: String, attribute: 'lang-file'},
+            langDir: {type: String, attribute: 'lang-dir'},
         };
     }
 
@@ -302,7 +304,9 @@ html {
                         </dbp-translated>
                     </div>
                     <div class="control" id="dbp-translation-demo">
-                        <dbp-translation key="toolkit-showcase" subscribe="lang, lang-file"></dbp-translation>
+                        <dbp-translation key="toolkit-showcase" subscribe="lang, lang-dir"></dbp-translation>
+                        <dbp-translation key="toolkit-showcase-link" var='{"link1": "https://www.i18next.com/translation-function/interpolation"}' subscribe="lang, lang-dir" unsafe></dbp-translation>
+                        <dbp-translation key="abc" subscribe="lang, lang-dir"></dbp-translation>
                     </div>
                 </div>
             </section>
diff --git a/packages/common/i18next.js b/packages/common/i18next.js
index 2b9244b3608c23c74e0123a7b4076c3363346981..d72b9abcc272045f9d50fff1928d33f6eb8358fa 100644
--- a/packages/common/i18next.js
+++ b/packages/common/i18next.js
@@ -124,3 +124,35 @@ export function setOverrides(i18n, element, overrides) {
     }
     i18n.setDefaultNamespace(hasOverrides ? overrideNamespace : namespace);
 }
+
+/**
+ * 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 {object} overrides - The override data as promise
+ */
+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.
+
+    // The scoped mixin saves the real tag name under data-tag-name
+    let tagName = ((element.dataset && element.dataset.tagName) || element.tagName).toLowerCase();
+    let namespace = i18n.options.fallbackNS;
+    let overrideNamespace = getOverrideNamespace(namespace);
+    let hasOverrides = false;
+    for (let lng of i18n.languages) {
+        overrides[lng] = await overrides[lng];
+        i18n.removeResourceBundle(lng, overrideNamespace);
+        if (overrides[lng] === undefined || overrides[lng][tagName] === undefined) continue;
+        let resources = overrides[lng][tagName];
+        hasOverrides = true;
+        i18n.addResourceBundle(lng, overrideNamespace, resources);
+    }
+    i18n.setDefaultNamespace(hasOverrides ? overrideNamespace : namespace);
+    element.requestUpdate();
+}
diff --git a/packages/common/src/i18n.js b/packages/common/src/i18n.js
index 0374a825419d2f2dea5fd68c5b9b0f76c019b9bb..1db56149c8772428260cc630cbcd4559b37d2eba 100644
--- a/packages/common/src/i18n.js
+++ b/packages/common/src/i18n.js
@@ -1,4 +1,4 @@
-import {createInstance as _createInstance} 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';
@@ -7,25 +7,8 @@ export function createInstance() {
     return _createInstance({en: en, de: de}, 'de', 'en');
 }
 
-export async function createInstanceAsync(langFile) {
-    // check if a path to language files is given
-    if(langFile) {
-      // request german lang file asynchronously
-      let result = await
-          fetch(langFile + 'de/translation.json', {
-              headers: {'Content-Type': 'application/json'},
-          });
-      const dynDe = await result.json();
-
-      // request english lang file asynchronously
-      result = await
-          fetch(langFile + 'en/translation.json', {
-              headers: {'Content-Type': 'application/json'},
-          });
-      const dynEn = await result.json();
-
-      return _createInstance({en: dynEn, de: dynDe}, 'de', 'en');
-    }
-
+export function createInstanceGivenResources(en, de) {
     return _createInstance({en: en, de: de}, 'de', 'en');
 }
+
+export {setOverridesByPromise};
diff --git a/packages/common/src/i18n/de/translation.json b/packages/common/src/i18n/de/translation.json
index b9daed00bc4e840bf1e885e4cff6f5a5e9c4d229..51cf793c6cb4108b18d8cab47b63959663ec8590 100644
--- a/packages/common/src/i18n/de/translation.json
+++ b/packages/common/src/i18n/de/translation.json
@@ -7,6 +7,5 @@
         "api-documentation-server": "Verbindung zum apiDocumentation API Server {{apiDocUrl}} fehlgeschlagen!",
         "error-api-server": "Verbindung zum API Server {{apiUrl}} fehlgeschlagen!",
         "error-hydra-documentation-url-not-set": "Hydra apiDocumentation URL wurden für server {{apiUrl}} nicht gesetzt!"
-    },
-    "toolkit-showcase": "Dieser Text wird mithilfe von i18n Englisch wenn man die Sprache auf Englisch stellt."
+    }
 }
diff --git a/packages/common/src/i18n/en/translation.json b/packages/common/src/i18n/en/translation.json
index 1e17839ab74d17ebb29bd8bf73c721a13533280a..e1036a6580fd180af131a4c2744c8c4fef2745fb 100644
--- a/packages/common/src/i18n/en/translation.json
+++ b/packages/common/src/i18n/en/translation.json
@@ -7,6 +7,5 @@
         "api-documentation-server": "Connection to apiDocumentation server {{apiDocUrl}} failed!",
         "error-api-server": "Connection to api server {{apiUrl}} failed!",
         "error-hydra-documentation-url-not-set": "Hydra apiDocumentation url was not set for server {{apiUrl}}!"
-    },
-    "toolkit-showcase": "This text will be translated to german using i18n when the user changes the language to german."
+    }
 }
diff --git a/packages/common/src/translation.js b/packages/common/src/translation.js
index 034978f3163b3fe1d63718f81b1219fcd7ef26be..07bb756e091f3df29ceb010ade2caf7805de8ad5 100644
--- a/packages/common/src/translation.js
+++ b/packages/common/src/translation.js
@@ -1,14 +1,42 @@
 import {css, html} from 'lit';
-import {until} from 'lit/directives/until.js';
+import {unsafeHTML} from 'lit/directives/unsafe-html.js';
 import DBPLitElement from '../dbp-lit-element';
-import {createInstanceAsync} 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() {
         super();
         this.key = '';
         this.lang = '';
-        this.langFile = '';
+        this.interpolation = '';
+        this.langDir = '';
+        this.unsafe = false;
     }
 
     static get properties() {
@@ -16,7 +44,9 @@ export class Translation extends DBPLitElement {
             ...super.properties,
             key: {type: String},
             lang: {type: String},
-            langFile: {type: String, attribute: 'lang-file'},
+            interpolation: {type: Object, attribute: 'var'},
+            unsafe: {type: Boolean, attribute: 'unsafe'},
+            langDir: {type: String, attribute: 'lang-dir'},
         };
     }
 
@@ -31,7 +61,21 @@ export class Translation extends DBPLitElement {
 
     connectedCallback() {
       super.connectedCallback();
-      this._i18n = createInstanceAsync(this.langFile);
+      // init objects with empty string as value for key
+      const de = {};
+      const en = {};
+      de[this.key] = "";
+      en[this.key] = "";
+
+      // create i18n instance with given translations
+      this._i18n = createInstanceGivenResources(en, de);
+
+      if (this.langDir) {
+        for(let lng of this._i18n.languages) {
+          cacheOverrides(this.langDir, lng);
+          setOverridesByPromise(this._i18n, this, translationCache);
+        }
+      }
     }
 
     update(changedProperties) {
@@ -39,10 +83,7 @@ export class Translation extends DBPLitElement {
         changedProperties.forEach((oldValue, propName) => {
             switch (propName) {
                 case 'lang':
-
-                    this._i18n.then(function(response) {
-                      response.changeLanguage(lang);
-                    });
+                    this._i18n.changeLanguage(lang);
                     break;
             }
         });
@@ -51,17 +92,28 @@ export class Translation extends DBPLitElement {
     }
 
     render() {
-        // save global key in local variable for async use
-        let key = this.key;
+        // request to i18n translation
+        const translation = (() => {
+          if (this.interpolation && this.unsafe)
+            return unsafeHTML(this._i18n.t(this.key, this.interpolation));
+          else if (this.interpolation)
+            return this._i18n.t(this.key, this.interpolation);
+          else
+            return this._i18n.t(this.key);
+        })();
 
-        // async request to i18n translation
-        const translation = this._i18n.then(function(response){
-          return response.t(key);
-        });
+        // if translation == "" key was not found
+        let key = "";
+        if (translation != "") {
+          key = unsafeHTML("<!-- key: " + this.key + "-->");
+        } else {
+          key = unsafeHTML("<!-- key \"" + this.key + "\" not found! -->");
+        }
 
-        // load translation text when available, otherweise display "Loading.."
+        // load translation text
         return html`
-            ${until(translation, html`<span>Loading..</span>`)}
+            ${key}
+            ${translation}
         `;
     }
 }
diff --git a/toolkit-showcase/assets/common.metadata.json b/toolkit-showcase/assets/common.metadata.json
index 51e4892cb53180deb82a6224e9dd0c836c9f6452..8cad700454234b68cd4b1e0c803d4be0d77daa39 100644
--- a/toolkit-showcase/assets/common.metadata.json
+++ b/toolkit-showcase/assets/common.metadata.json
@@ -14,5 +14,5 @@
         "de": "Gemeinsame Web Components",
         "en": "Common web components"
     },
-    "subscribe": "lang,entry-point-url,lang-file"
+    "subscribe": "lang,entry-point-url,lang-dir"
 }
diff --git a/toolkit-showcase/assets/dbp-toolkit-showcase.html.ejs b/toolkit-showcase/assets/dbp-toolkit-showcase.html.ejs
index 89c2a191d9e98c2d5aa3b01bde70137b38f8b17c..07b213117747aed86247d1a50c87cd681e226cf3 100644
--- a/toolkit-showcase/assets/dbp-toolkit-showcase.html.ejs
+++ b/toolkit-showcase/assets/dbp-toolkit-showcase.html.ejs
@@ -113,7 +113,7 @@
 <<%= name %>
     provider-root
     lang="de"
-    lang-file="<%= getPrivateUrl('i18n/') %>"
+    lang-dir="<%= getPrivateUrl('translation-overrides/') %>"
     entry-point-url="<%= entryPointURL %>"
     nextcloud-auth-url="<%= nextcloudWebAppPasswordURL %>"
     nextcloud-web-dav-url="<%= nextcloudWebDavURL %>"
diff --git a/toolkit-showcase/assets/translation-overrides/de/translation.json b/toolkit-showcase/assets/translation-overrides/de/translation.json
new file mode 100644
index 0000000000000000000000000000000000000000..27d226ddd06de5cf6471160a27d98a31f25a8f79
--- /dev/null
+++ b/toolkit-showcase/assets/translation-overrides/de/translation.json
@@ -0,0 +1,6 @@
+{
+    "dbp-translation": {
+      "toolkit-showcase": "Dieser Text wird mithilfe von i18n aus einer benutzerdefinierten Sprachdatei gelesen und ins Englische übersetzt wenn man die Sprache auf Englisch stellt.",
+      "toolkit-showcase-link": "Es können sogar links mittels <a href=\"{{- link1}}\">interpolation</a> und escaping dargestellt werden."
+    }
+}
diff --git a/toolkit-showcase/assets/translation-overrides/en/translation.json b/toolkit-showcase/assets/translation-overrides/en/translation.json
new file mode 100644
index 0000000000000000000000000000000000000000..e3cd5c3858abaac1396241f2235a71fdb2f17d86
--- /dev/null
+++ b/toolkit-showcase/assets/translation-overrides/en/translation.json
@@ -0,0 +1,6 @@
+{
+    "dbp-translation": {
+      "toolkit-showcase": "This text will be translated to german using i18n with a user defined language file when the language is changed to german.",
+      "toolkit-showcase-link": "Furthermore its possible to display links through <a href=\"{{- link1}}\">interpolation</a> and escaping."
+    }
+}
diff --git a/toolkit-showcase/rollup.config.js b/toolkit-showcase/rollup.config.js
index 1a85c45ac58362d43c3a8968ce7c6152323f7211..5320e77ed687b0b881ccfab0f897f88527849982 100644
--- a/toolkit-showcase/rollup.config.js
+++ b/toolkit-showcase/rollup.config.js
@@ -168,7 +168,7 @@ Dependencies:
                     {src: 'assets/icon-*.png', dest: 'dist/' + (await getDistPath(pkg.name))},
                     {src: 'assets/apple-*.png', dest: 'dist/' + (await getDistPath(pkg.name))},
                     {src: 'assets/safari-*.svg', dest: 'dist/' + (await getDistPath(pkg.name))},
-                    {src: 'src/i18n', dest: 'dist/' + (await getDistPath(pkg.name))},
+                    {src: 'assets/translation-overrides', dest: 'dist/' + (await getDistPath(pkg.name))},
                     {
                         src: 'assets/manifest.json',
                         dest: 'dist',
diff --git a/toolkit-showcase/src/dbp-common-demo-activity.js b/toolkit-showcase/src/dbp-common-demo-activity.js
index 6735845541387b0098d6f61bf329470508bf84c3..2f959f9a7ee9886da423cdd9b444ea17ab58a477 100644
--- a/toolkit-showcase/src/dbp-common-demo-activity.js
+++ b/toolkit-showcase/src/dbp-common-demo-activity.js
@@ -13,7 +13,7 @@ class DbpCommonDemoActivity extends ScopedElementsMixin(AdapterLitElement) {
         super();
         this.lang = 'en';
         this.entryPointUrl = '';
-        this.langFile = '';
+        this.langDir = '';
     }
 
     static get scopedElements() {
@@ -26,7 +26,7 @@ class DbpCommonDemoActivity extends ScopedElementsMixin(AdapterLitElement) {
         return {
             ...super.properties,
             lang: {type: String},
-            langFile: {type: String, attribute: 'lang-file'},
+            langDir: {type: String, attribute: 'lang-dir'},
             entryPointUrl: {type: String, attribute: 'entry-point-url'},
         };
     }
@@ -65,7 +65,7 @@ class DbpCommonDemoActivity extends ScopedElementsMixin(AdapterLitElement) {
             <dbp-common-demo
                 id="demo"
                 lang="${this.lang}"
-                lang-file="${this.langFile}"
+                lang-dir="${this.langDir}"
                 entry-point-url="${this.entryPointUrl}"></dbp-common-demo>
         `;
     }
diff --git a/toolkit-showcase/src/i18n/de/translation.json b/toolkit-showcase/src/i18n/de/translation.json
deleted file mode 100644
index d51b20bd684577823c83c44264231d626cbcfdbf..0000000000000000000000000000000000000000
--- a/toolkit-showcase/src/i18n/de/translation.json
+++ /dev/null
@@ -1,3 +0,0 @@
-{
-    "toolkit-showcase": "Dieser Text wird mithilfe von i18n aus einer benutzerdefinierten Sprachdatei gelesen und ins Englische übersetzt wenn man die Sprache auf Englisch stellt."
-}
diff --git a/toolkit-showcase/src/i18n/en/translation.json b/toolkit-showcase/src/i18n/en/translation.json
deleted file mode 100644
index a2a415677f590d5467181ffe68644925ca542ee6..0000000000000000000000000000000000000000
--- a/toolkit-showcase/src/i18n/en/translation.json
+++ /dev/null
@@ -1,3 +0,0 @@
-{
-    "toolkit-showcase": "This text will be translated to german using i18n with a user defined language file when the language is changed to german."
-}