diff --git a/package.json b/package.json
index a302bf59e3465f6d90b4a42b5797bad23c52f4ee..42030b6c9f35d1e1c4fcd6243464d99d233bf1d2 100644
--- a/package.json
+++ b/package.json
@@ -11,6 +11,7 @@
   "scripts": {
     "test": "lerna run test",
     "build": "lerna run build",
+    "i18next": "lerna run i18next",
     "version-patch": "lerna version patch",
     "version-minor": "lerna version minor",
     "version": "lerna version",
diff --git a/packages/app-shell/i18next-scanner.config.js b/packages/app-shell/i18next-scanner.config.js
new file mode 100644
index 0000000000000000000000000000000000000000..aeb8fdb6532e6c951401ba91424e2a256353d391
--- /dev/null
+++ b/packages/app-shell/i18next-scanner.config.js
@@ -0,0 +1,16 @@
+module.exports = {
+    input: [
+        'src/*.js',
+    ],
+    output: './',
+    options: {
+        debug: false,
+        removeUnusedKeys: true,
+        func: {list: ['i18n.t', '_i18n.t']},
+        lngs: ['en','de'],
+        resource: {
+            loadPath: 'src/i18n/{{lng}}/{{ns}}.json',
+            savePath: 'src/i18n/{{lng}}/{{ns}}.json'
+        },
+    },
+}
diff --git a/packages/app-shell/package.json b/packages/app-shell/package.json
index ccecb0392a24def4c5f0e2398abde21091ee7221..d31a609a71c61c7e877534f16d7c369c47e0e79f 100644
--- a/packages/app-shell/package.json
+++ b/packages/app-shell/package.json
@@ -31,7 +31,8 @@
     "rollup-plugin-copy": "^3.1.0",
     "rollup-plugin-delete": "^2.0.0",
     "rollup-plugin-emit-ejs": "^3.1.0",
-    "rollup-plugin-serve": "^1.0.1"
+    "rollup-plugin-serve": "^1.0.1",
+    "i18next-scanner": "^3.0.0"
   },
   "dependencies": {
     "@dbp-toolkit/auth": "^0.2.2",
@@ -47,6 +48,7 @@
     "universal-router": "^9.0.1"
   },
   "scripts": {
+    "i18next": "i18next-scanner",
     "build": "npm run build-local",
     "build-local": "rollup -c",
     "build-test": "rollup -c --environment BUILD:test",
diff --git a/packages/app-shell/src/app-shell.js b/packages/app-shell/src/app-shell.js
index bf2bab5e86cee6158b619e9105c0aa600d3100cc..864ae5255ebe09aac5fa43f1b1446258b3398829 100644
--- a/packages/app-shell/src/app-shell.js
+++ b/packages/app-shell/src/app-shell.js
@@ -1,4 +1,4 @@
-import {createI18nInstance} from './i18n.js';
+import {createInstance} from './i18n.js';
 import {html, css} from 'lit-element';
 import {ScopedElementsMixin} from '@open-wc/scoped-elements';
 import {LanguageSelect} from '@dbp-toolkit/language-select';
@@ -15,18 +15,16 @@ import {appWelcomeMeta} from './dbp-app-shell-welcome.js';
 import {MatomoElement} from "@dbp-toolkit/matomo/src/matomo";
 import DBPLitElement from "@dbp-toolkit/common/dbp-lit-element";
 
-
-const i18n = createI18nInstance();
-
 /**
  * In case the application gets updated future dynamic imports might fail.
  * This sends a notification suggesting the user to reload the page.
  *
- * uage: importNotify(import('<path>'));
+ * usage: importNotify(import('<path>'));
  *
+ * @param i18n
  * @param {Promise} promise
  */
-const importNotify = async (promise) => {
+const importNotify = async (i18n, promise) => {
     try {
         return await promise;
     } catch (error) {
@@ -43,7 +41,6 @@ const importNotify = async (promise) => {
 export class AppShell extends ScopedElementsMixin(DBPLitElement) {
     constructor() {
         super();
-        this.lang = i18n.language;
         this.activeView = '';
         this.entryPointUrl = '';
         this.subtitle = '';
@@ -62,6 +59,8 @@ export class AppShell extends ScopedElementsMixin(DBPLitElement) {
         this.buildTime = '';
         this._loginStatus = 'unknown';
         this._roles = [];
+        this._i18n = createInstance();
+        this.lang = this._i18n.language;
 
         this.matomoUrl = '';
         this.matomoSiteId = -1;
@@ -271,7 +270,7 @@ export class AppShell extends ScopedElementsMixin(DBPLitElement) {
      */
     updateLangIfChanged(lang) {
         // in case the language is unknown, fall back to the default
-        if (!i18n.languages.includes(lang)) {
+        if (!this._i18n.languages.includes(lang)) {
             lang = this.lang;
         }
         if (this.lang !== lang) {
@@ -287,10 +286,9 @@ export class AppShell extends ScopedElementsMixin(DBPLitElement) {
         changedProperties.forEach((oldValue, propName) => {
             switch (propName) {
                 case 'lang':
-                    i18n.changeLanguage(this.lang);
+                    this._i18n.changeLanguage(this.lang);
                     // For screen readers
                     document.documentElement.setAttribute("lang", this.lang);
-                    i18n.changeLanguage(this.lang);
 
                     this.router.update();
                     this.subtitle = this.activeMetaDataText("short_name");
@@ -420,7 +418,7 @@ export class AppShell extends ScopedElementsMixin(DBPLitElement) {
             return;
         }
 
-        importNotify(import(metadata.module_src)).then(() => {
+        importNotify(this._i18n, import(metadata.module_src)).then(() => {
             updateFunc();
         }).catch((e) => {
             console.error(`Error loading ${ metadata.element }`);
@@ -836,6 +834,8 @@ export class AppShell extends ScopedElementsMixin(DBPLitElement) {
     }
 
     render() {
+        let i18n = this._i18n;
+
         const getSelectClasses = (name => {
             return classMap({selected: this.activeView === name});
         });
diff --git a/packages/app-shell/src/auth-menu-button.js b/packages/app-shell/src/auth-menu-button.js
index ce8e9fc1b076d8d498548afd7dfb22c17c53568a..a122cb825ba6139db687d2a379e319b1d10c32b4 100644
--- a/packages/app-shell/src/auth-menu-button.js
+++ b/packages/app-shell/src/auth-menu-button.js
@@ -1,4 +1,4 @@
-import {createI18nInstance} from './i18n.js';
+import {createInstance} from './i18n.js';
 import {html, css} from 'lit-element';
 import {unsafeHTML} from 'lit-html/directives/unsafe-html.js';
 import {ScopedElementsMixin} from '@open-wc/scoped-elements';
@@ -7,14 +7,12 @@ import {Icon} from '@dbp-toolkit/common';
 import {AdapterLitElement} from "@dbp-toolkit/provider/src/adapter-lit-element";
 import {LoginStatus} from "@dbp-toolkit/auth/src/util";
 
-
-const i18n = createI18nInstance();
-
 export class AuthMenuButton extends ScopedElementsMixin(AdapterLitElement) {
 
     constructor() {
         super();
-        this.lang = 'de';
+        this._i18n = createInstance();
+        this.lang = this._i18n.language;
         this.showImage = false;
         this.auth = {};
 
@@ -82,7 +80,7 @@ export class AuthMenuButton extends ScopedElementsMixin(AdapterLitElement) {
     update(changedProperties) {
         changedProperties.forEach((oldValue, propName) => {
             if (propName === "lang") {
-                i18n.changeLanguage(this.lang);
+                this._i18n.changeLanguage(this.lang);
             }
         });
 
@@ -246,6 +244,7 @@ export class AuthMenuButton extends ScopedElementsMixin(AdapterLitElement) {
     }
 
     renderLoggedIn() {
+        const i18n = this._i18n;
         const person = this.auth.person;
         const imageURL = (this.showImage && person && person.image) ? person.image : null;
 
@@ -270,6 +269,7 @@ export class AuthMenuButton extends ScopedElementsMixin(AdapterLitElement) {
     }
 
     renderLoggedOut() {
+        const i18n = this._i18n;
         let loginSVG = `
         <svg
            viewBox="0 0 100 100"
diff --git a/packages/app-shell/src/dbp-activity-example.js b/packages/app-shell/src/dbp-activity-example.js
index 850a73c289e514052d2fa347da420431a42a0a30..e126445bf47d4a4128e26348ce32b9dccaedd0b2 100644
--- a/packages/app-shell/src/dbp-activity-example.js
+++ b/packages/app-shell/src/dbp-activity-example.js
@@ -1,14 +1,13 @@
 import {html , LitElement} from 'lit-element';
-import {createI18nInstance} from './i18n.js';
+import {createInstance} from './i18n.js';
 import * as commonUtils from '@dbp-toolkit/common/utils';
 
-const i18n = createI18nInstance();
-
 class ActivityExample extends LitElement {
 
     constructor() {
         super();
-        this.lang = i18n.language;
+        this._i18n = createInstance();
+        this.lang = this._i18n.language;
     }
 
     static get properties() {
@@ -21,7 +20,7 @@ class ActivityExample extends LitElement {
         changedProperties.forEach((oldValue, propName) => {
             switch (propName) {
                 case "lang":
-                    i18n.changeLanguage(this.lang);
+                    this._i18n.changeLanguage(this.lang);
                     break;
             }
         });
@@ -30,6 +29,7 @@ class ActivityExample extends LitElement {
     }
 
     render() {
+        const i18n = this._i18n;
         return html`
             <h3>${i18n.t('activity-example.hello-world')}</h3>
             <ul>${(Array.from(Array(100).keys())).map(i => html`<li>${i18n.t('activity-example.hello-world') + ' ' + i}</li>`)}</ul>
diff --git a/packages/app-shell/src/dbp-app-shell-welcome.js b/packages/app-shell/src/dbp-app-shell-welcome.js
index 2397905ba095d39b3bc977a694c1eb151e58a55c..52acdf77cb64ccf5472709e67e33a35d31dca400 100644
--- a/packages/app-shell/src/dbp-app-shell-welcome.js
+++ b/packages/app-shell/src/dbp-app-shell-welcome.js
@@ -1,16 +1,15 @@
-import {createI18nInstance} from './i18n.js';
+import {createInstance} from './i18n.js';
 import {css, html, LitElement} from 'lit-element';
 import {ScopedElementsMixin} from '@open-wc/scoped-elements';
 import * as commonUtils from '@dbp-toolkit/common/utils';
 import * as commonStyles from '@dbp-toolkit/common/styles';
 
-const i18n = createI18nInstance();
-
 class AppShellWelcome extends ScopedElementsMixin(LitElement) {
 
     constructor() {
         super();
-        this.lang = i18n.language;
+        this._i18n = createInstance();
+        this.lang = this._i18n.language;
 
         this._onVisibilityChanged = this._onVisibilityChanged.bind(this);
     }
@@ -28,7 +27,7 @@ class AppShellWelcome extends ScopedElementsMixin(LitElement) {
     update(changedProperties) {
         changedProperties.forEach((oldValue, propName) => {
             if (propName === "lang") {
-                i18n.changeLanguage(this.lang);
+                this._i18n.changeLanguage(this.lang);
             }
         });
 
@@ -75,6 +74,7 @@ class AppShellWelcome extends ScopedElementsMixin(LitElement) {
     }
 
     render() {
+        const i18n = this._i18n;
         const app = AppShellWelcome._app;
         let itemTemplates = [];
 
diff --git a/packages/app-shell/src/i18n.js b/packages/app-shell/src/i18n.js
index 7bc3faba59eb4d9d4a7e1106ad44181b17d77ec4..0c6fedc883e4f02965df30acfb47fa37e11a268c 100644
--- a/packages/app-shell/src/i18n.js
+++ b/packages/app-shell/src/i18n.js
@@ -1,20 +1,8 @@
-import {createInstance} 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';
 
-const i18n = createInstance({en: en, de: de}, 'de', 'en');
-
-export function createI18nInstance () {
-    return i18n.cloneInstance();
+export function createInstance() {
+    return _createInstance({en: en, de: de}, 'de', 'en');
 }
-
-/**
- * Dummy function to mark strings as i18next keys for i18next-scanner
- *
- * @param {string} key
- * @returns {string} The key param as is
- */
-export function i18nKey(key) {
-    return key;
-}
\ No newline at end of file
diff --git a/packages/app-shell/src/i18n/de/translation.json b/packages/app-shell/src/i18n/de/translation.json
index bac3fc0fb57a6b6e8ce32746ef1bd4556f5837cd..3b959a1aa025175012d775fab70761dd5dee28fc 100644
--- a/packages/app-shell/src/i18n/de/translation.json
+++ b/packages/app-shell/src/i18n/de/translation.json
@@ -12,10 +12,10 @@
     "hello-world": "Hallo Welt"
   },
   "welcome": {
-      "headline": "Willkommen bei der Applikation '{{appname}}'."
+    "headline": "Willkommen bei der Applikation '{{appname}}'."
   },
   "login": "Einloggen",
   "logout": "Ausloggen",
   "page-not-found": "Die gewünschte Seite wurde nicht gefunden",
   "choose-from-menu": "Bitte wählen Sie eine Aktivität aus dem Menu."
-}
\ No newline at end of file
+}
diff --git a/packages/app-shell/src/i18n/en/translation.json b/packages/app-shell/src/i18n/en/translation.json
index 5a5c20a43596e8d667e64f6647716b11e4c0207f..ae4a137d9eb84ebbad052f1c5564228fbdaf133e 100644
--- a/packages/app-shell/src/i18n/en/translation.json
+++ b/packages/app-shell/src/i18n/en/translation.json
@@ -12,7 +12,7 @@
     "hello-world": "Hello World"
   },
   "welcome": {
-      "headline": "Welcome to the '{{appname}}' application."
+    "headline": "Welcome to the '{{appname}}' application."
   },
   "login": "Login",
   "logout": "Logout",
diff --git a/packages/auth/i18next-scanner.config.js b/packages/auth/i18next-scanner.config.js
index 0e6216b2e7dd8a8b3a0d95d9ef86f35c37ce5f5e..aeb8fdb6532e6c951401ba91424e2a256353d391 100644
--- a/packages/auth/i18next-scanner.config.js
+++ b/packages/auth/i18next-scanner.config.js
@@ -8,7 +8,6 @@ module.exports = {
         removeUnusedKeys: true,
         func: {list: ['i18n.t', '_i18n.t']},
         lngs: ['en','de'],
-        defaultNs: 'dbp-auth',
         resource: {
             loadPath: 'src/i18n/{{lng}}/{{ns}}.json',
             savePath: 'src/i18n/{{lng}}/{{ns}}.json'
diff --git a/packages/auth/src/auth-keycloak.js b/packages/auth/src/auth-keycloak.js
index f5b5ab718c3dbfce64c932754b5c59ebc3bc5520..60c3b1612748f004d1fd3946942f2fa28c4da372 100644
--- a/packages/auth/src/auth-keycloak.js
+++ b/packages/auth/src/auth-keycloak.js
@@ -20,7 +20,6 @@ import {AdapterLitElement} from "@dbp-toolkit/provider/src/adapter-lit-element";
 export class AuthKeycloak extends AdapterLitElement {
     constructor() {
         super();
-        this.lang = 'de';
         this.forceLogin = false;
         this.loadPerson = false;
         this.token = "";
@@ -33,6 +32,7 @@ export class AuthKeycloak extends AdapterLitElement {
         this._loginStatus = LoginStatus.UNKNOWN;
         this.requestedLoginStatus = LoginStatus.UNKNOWN;
         this._i18n = createInstance();
+        this.lang = this._i18n.language;
 
         // Keycloak config
         this.keycloakUrl = null;
diff --git a/packages/auth/src/dbp-auth-demo.js b/packages/auth/src/dbp-auth-demo.js
index 3b9170f60a77d3f063294497aea8d778bfe6014f..93aa4627427de5d07025f81ec9ab0b8e1b7371b7 100644
--- a/packages/auth/src/dbp-auth-demo.js
+++ b/packages/auth/src/dbp-auth-demo.js
@@ -10,11 +10,11 @@ import DBPLitElement from "@dbp-toolkit/common/dbp-lit-element";
 export class DbpAuthDemo extends ScopedElementsMixin(DBPLitElement) {
     constructor() {
         super();
-        this.lang = 'de';
         this.entryPointUrl = '';
         this.auth = {};
         this.noAuth = false;
         this._i18n = createInstance();
+        this.lang = this._i18n.language;
     }
 
     static get scopedElements() {
diff --git a/packages/auth/src/i18n.js b/packages/auth/src/i18n.js
index a54f51bc97ca386d30adb3282547870b7501c2af..fbc1b032f3c662e149547117a8df129be5262e99 100644
--- a/packages/auth/src/i18n.js
+++ b/packages/auth/src/i18n.js
@@ -1,10 +1,10 @@
 import {createInstance as _createInstance, setOverrides} from '@dbp-toolkit/common/i18next.js';
 
-import de from './i18n/de/dbp-auth.json';
-import en from './i18n/en/dbp-auth.json';
+import de from './i18n/de/translation.json';
+import en from './i18n/en/translation.json';
 
 export function createInstance() {
-    return _createInstance({en: en, de: de}, 'de', 'en', 'dbp-auth');
+    return _createInstance({en: en, de: de}, 'de', 'en');
 }
 
 export {setOverrides};
\ No newline at end of file
diff --git a/packages/auth/src/i18n/de/dbp-auth.json b/packages/auth/src/i18n/de/translation.json
similarity index 100%
rename from packages/auth/src/i18n/de/dbp-auth.json
rename to packages/auth/src/i18n/de/translation.json
diff --git a/packages/auth/src/i18n/en/dbp-auth.json b/packages/auth/src/i18n/en/translation.json
similarity index 100%
rename from packages/auth/src/i18n/en/dbp-auth.json
rename to packages/auth/src/i18n/en/translation.json
diff --git a/packages/auth/src/login-button.js b/packages/auth/src/login-button.js
index 63e7353d567094b24cb376bc7a76da93557a97da..55423562cbfb9275273f06811b789d824121889e 100644
--- a/packages/auth/src/login-button.js
+++ b/packages/auth/src/login-button.js
@@ -55,8 +55,8 @@ export class LoginButton extends ScopedElementsMixin(AdapterLitElement) {
 
     constructor() {
         super();
-        this.lang = 'de';
         this._i18n = createInstance();
+        this.lang = this._i18n.language;
         this.auth = {};
     }
 
diff --git a/packages/check-in-place-select/src/check-in-place-select.js b/packages/check-in-place-select/src/check-in-place-select.js
index f2ed817d4a7a974001c94afcdf20e9424a4472e0..992b6148f629c71e398f23be0d4982f816a0f2ac 100644
--- a/packages/check-in-place-select/src/check-in-place-select.js
+++ b/packages/check-in-place-select/src/check-in-place-select.js
@@ -25,7 +25,6 @@ export class CheckInPlaceSelect extends ScopedElementsMixin(AdapterLitElement) {
     constructor() {
         super();
         Object.assign(CheckInPlaceSelect.prototype, errorUtils.errorMixin);
-        this.lang = 'de';
         this.entryPointUrl = '';
         this.jsonld = null;
         this.$select = null;
@@ -42,6 +41,7 @@ export class CheckInPlaceSelect extends ScopedElementsMixin(AdapterLitElement) {
         this.showCapacity = false;
         this.auth = {};
         this._i18n = createInstance();
+        this.lang = this._i18n.language;
 
         this._onDocumentClicked = this._onDocumentClicked.bind(this);
     }
diff --git a/packages/check-in-place-select/src/dbp-check-in-place-select-demo.js b/packages/check-in-place-select/src/dbp-check-in-place-select-demo.js
index d77e85619122d1d1a74b5cca5c94c7f281b3b615..b56c85ab68a97bf534d7bc6c916ce0bcb922a7d1 100644
--- a/packages/check-in-place-select/src/dbp-check-in-place-select-demo.js
+++ b/packages/check-in-place-select/src/dbp-check-in-place-select-demo.js
@@ -5,11 +5,14 @@ import {AuthKeycloak, LoginButton} from '@dbp-toolkit/auth';
 import * as commonUtils from '@dbp-toolkit/common/utils';
 import * as commonStyles from '@dbp-toolkit/common/styles';
 import DBPLitElement from "@dbp-toolkit/common/dbp-lit-element";
+import {createInstance} from './i18n.js';
+
 
 export class CheckInPlaceSelectDemo extends ScopedElementsMixin(DBPLitElement) {
     constructor() {
         super();
-        this.lang = 'de';
+        this._i18n = createInstance();
+        this.lang = this._i18n.language;
         this.entryPointUrl = '';
         this.noAuth = false;
     }
diff --git a/packages/common/dbp-common-demo.js b/packages/common/dbp-common-demo.js
index 4e58093a0f163729582a7ac3a30c75b2b6f48d34..9a56ef03ec21d0d620844c2944453c36225b68e7 100644
--- a/packages/common/dbp-common-demo.js
+++ b/packages/common/dbp-common-demo.js
@@ -1,4 +1,4 @@
-import {i18n} from './i18n.js';
+import {createInstance} from './src/i18n.js';
 import {css, html, LitElement} from 'lit-element';
 import {ScopedElementsMixin} from '@open-wc/scoped-elements';
 import * as commonUtils from './utils.js';
@@ -8,7 +8,8 @@ import {getIconCSS, Icon, MiniSpinner, Button, LoadingButton, Spinner, InlineNot
 export class DbpCommonDemo extends ScopedElementsMixin(LitElement) {
     constructor() {
         super();
-        this.lang = 'de';
+        this._i18n = createInstance();
+        this.lang = this._i18n.language;
         this.noAuth = false;
     }
 
@@ -39,7 +40,7 @@ export class DbpCommonDemo extends ScopedElementsMixin(LitElement) {
 
     connectedCallback() {
         super.connectedCallback();
-        i18n.changeLanguage(this.lang);
+        this._i18n.changeLanguage(this.lang);
 
         this.updateComplete.then(()=>{
         });
diff --git a/packages/common/error.js b/packages/common/error.js
index aa61b9e25f7f3060b6ee5e09163f72844e739d33..f001f1747cc53f3fba0b001746260745e9379250 100644
--- a/packages/common/error.js
+++ b/packages/common/error.js
@@ -1,5 +1,5 @@
 import {send as notify} from './notification';
-import {i18n} from "./i18n";
+import {createInstance} from "./src/i18n";
 
 /**
  * Escapes html
@@ -39,14 +39,17 @@ export const errorMixin = {
      * @param textStatus
      * @param errorThrown
      * @param icon
+     * @param lang
      */
-    handleXhrError(jqXHR, textStatus, errorThrown, icon = "sad") {
+    handleXhrError(jqXHR, textStatus, errorThrown, icon = "sad", lang = "de") {
         // return if user aborted the request
         if (textStatus === "abort") {
             return;
         }
 
         let body;
+        const i18n = createInstance();
+        i18n.changeLanguage(lang);
 
         if (jqXHR.responseJSON !== undefined && jqXHR.responseJSON["hydra:description"] !== undefined) {
             // response is a JSON-LD
@@ -86,14 +89,17 @@ export const errorMixin = {
      * @param error
      * @param summary
      * @param icon
+     * @param lang
      */
-    handleFetchError: async function (error, summary = "", icon = "sad") {
+    handleFetchError: async function (error, summary = "", icon = "sad", lang = "de") {
         // return if user aborted the request
         if (error.name === "AbortError") {
             return;
         }
 
         let body;
+        const i18n = createInstance();
+        i18n.changeLanguage(lang);
 
         try {
             await error.json().then((json) => {
diff --git a/packages/common/i18n.js b/packages/common/i18n.js
deleted file mode 100644
index dc0125f75d796c81867d56e3c409936202ae00fe..0000000000000000000000000000000000000000
--- a/packages/common/i18n.js
+++ /dev/null
@@ -1,6 +0,0 @@
-import {createInstance} from './i18next.js';
-
-import de from './i18n/de/translation.json';
-import en from './i18n/en/translation.json';
-
-export const i18n = createInstance({en: en, de: de}, 'de', 'en');
\ No newline at end of file
diff --git a/packages/common/i18next-scanner.config.js b/packages/common/i18next-scanner.config.js
new file mode 100644
index 0000000000000000000000000000000000000000..773819264a14879dcd454bb9a5317ccdeec2e9d8
--- /dev/null
+++ b/packages/common/i18next-scanner.config.js
@@ -0,0 +1,17 @@
+module.exports = {
+    input: [
+        'src/*.js',
+        './*.js',
+    ],
+    output: './',
+    options: {
+        debug: false,
+        removeUnusedKeys: true,
+        func: {list: ['i18n.t', '_i18n.t']},
+        lngs: ['en','de'],
+        resource: {
+            loadPath: 'src/i18n/{{lng}}/{{ns}}.json',
+            savePath: 'src/i18n/{{lng}}/{{ns}}.json'
+        },
+    },
+}
diff --git a/packages/common/jsonld.js b/packages/common/jsonld.js
index 0a27bbfdaf6490239d2c73594960b85f63e0bc38..f74e38cf8b1b46881bde1376ce4472775f6d59d5 100644
--- a/packages/common/jsonld.js
+++ b/packages/common/jsonld.js
@@ -1,6 +1,6 @@
 import {send as notify} from './notification';
 import * as utils from "./utils";
-import {i18n} from "./i18n";
+import {createInstance} from "./src/i18n";
 
 export default class JSONLD {
     constructor(baseApiUrl, entities) {
@@ -43,9 +43,7 @@ export default class JSONLD {
     }
 
     static _initialize(apiUrl, successFnc, failureFnc, lang = 'de') {
-        if (lang !== 'de') {
-            i18n.changeLanguage(lang);
-        }
+        JSONLD._i18n.changeLanguage(lang);
 
         // if init api call was already successfully finished execute the success function
         if (JSONLD.instances[apiUrl] !== undefined) {
@@ -72,6 +70,7 @@ export default class JSONLD {
 
     static _doInitialization(apiUrl) {
         const xhr = new XMLHttpRequest();
+        const i18n = JSONLD._i18n;
         xhr.open("GET", apiUrl, true);
 
         xhr.onreadystatechange = function () {
@@ -170,6 +169,7 @@ export default class JSONLD {
      * @param message
      */
     static _executeFailureFunctions(apiUrl, message = "") {
+        const i18n = JSONLD._i18n;
         if (JSONLD.failureFunctions[apiUrl] !== undefined) {
             for (const fnc of JSONLD.failureFunctions[apiUrl]) {
                 if (typeof fnc == 'function') {
@@ -297,6 +297,7 @@ export default class JSONLD {
     }
 }
 
+JSONLD._i18n = createInstance();
 JSONLD.instances = {};
 JSONLD.successFunctions = {};
 JSONLD.failureFunctions = {};
diff --git a/packages/common/package.json b/packages/common/package.json
index d4ed6c5f0b8c3cd447d1a833b4b725028a58f995..c14f62c5b9bb4c9826e3206b7139506ad61ffaac 100644
--- a/packages/common/package.json
+++ b/packages/common/package.json
@@ -25,9 +25,11 @@
     "rollup": "^2.33.3",
     "rollup-plugin-copy": "^3.1.0",
     "rollup-plugin-delete": "^2.0.0",
-    "rollup-plugin-serve": "^1.0.1"
+    "rollup-plugin-serve": "^1.0.1",
+    "i18next-scanner": "^3.0.0"
   },
   "scripts": {
+    "i18next": "i18next-scanner",
     "clean": "rm dist/*",
     "build": "rollup -c",
     "build-test": "rollup -c --environment BUILD:test",
diff --git a/packages/common/src/i18n.js b/packages/common/src/i18n.js
new file mode 100644
index 0000000000000000000000000000000000000000..ebd734720b5a52bbd4008d0e503ca96f9d3fa068
--- /dev/null
+++ b/packages/common/src/i18n.js
@@ -0,0 +1,8 @@
+import {createInstance as _createInstance} from '../i18next.js';
+
+import de from './i18n/de/translation.json';
+import en from './i18n/en/translation.json';
+
+export function createInstance() {
+    return _createInstance({en: en, de: de}, 'de', 'en');
+}
\ No newline at end of file
diff --git a/packages/common/i18n/de/translation.json b/packages/common/src/i18n/de/translation.json
similarity index 100%
rename from packages/common/i18n/de/translation.json
rename to packages/common/src/i18n/de/translation.json
diff --git a/packages/common/i18n/en/translation.json b/packages/common/src/i18n/en/translation.json
similarity index 100%
rename from packages/common/i18n/en/translation.json
rename to packages/common/src/i18n/en/translation.json
diff --git a/packages/data-table-view/i18next-scanner.config.js b/packages/data-table-view/i18next-scanner.config.js
new file mode 100644
index 0000000000000000000000000000000000000000..aeb8fdb6532e6c951401ba91424e2a256353d391
--- /dev/null
+++ b/packages/data-table-view/i18next-scanner.config.js
@@ -0,0 +1,16 @@
+module.exports = {
+    input: [
+        'src/*.js',
+    ],
+    output: './',
+    options: {
+        debug: false,
+        removeUnusedKeys: true,
+        func: {list: ['i18n.t', '_i18n.t']},
+        lngs: ['en','de'],
+        resource: {
+            loadPath: 'src/i18n/{{lng}}/{{ns}}.json',
+            savePath: 'src/i18n/{{lng}}/{{ns}}.json'
+        },
+    },
+}
diff --git a/packages/data-table-view/src/data-table-view.js b/packages/data-table-view/src/data-table-view.js
index fb9690ba6da23b303106e15c712759a56c8e7b6f..609e642c9e5f28215595b4d8a446ee8c59688a9a 100644
--- a/packages/data-table-view/src/data-table-view.js
+++ b/packages/data-table-view/src/data-table-view.js
@@ -7,7 +7,7 @@ import bttn from 'datatables.net-buttons-dt';
 import bttn2 from 'datatables.net-buttons';
 import bttnHtml5 from 'datatables.net-buttons/js/buttons.html5.js';
 import bttnPrint from 'datatables.net-buttons/js/buttons.print.js';
-import {i18n} from './i18n';
+import {createInstance} from './i18n';
 import {css, html, unsafeCSS} from 'lit-element';
 import de from '../assets/datatables/i18n/German';
 import en from '../assets/datatables/i18n/English';
@@ -28,7 +28,8 @@ bttnPrint(window, $);
 export class DataTableView extends AdapterLitElement {
     constructor() {
         super();
-        this.lang = 'de';
+        this._i18n = createInstance();
+        this.lang = this._i18n.language;
         // datatable properties
         this.table = null;
         this.responsive = null;
@@ -100,6 +101,7 @@ export class DataTableView extends AdapterLitElement {
 
     set_datatable(data, languageChange = false) {
         const lang_obj = this.lang === 'de' ? de : en;
+        const i18n = this._i18n;
 
         if (typeof this.columns === 'undefined' || !this.columns.length) {
             if (data.length)
@@ -229,7 +231,7 @@ export class DataTableView extends AdapterLitElement {
 
         changedProperties.forEach((oldValue, propName) => {
             if (propName === "lang") {
-                i18n.changeLanguage(this.lang).catch(e => { console.log(e);});
+                this._i18n.changeLanguage(this.lang).catch(e => { console.log(e);});
                 languageChange = true;
             }
         });
diff --git a/packages/data-table-view/src/dbp-data-table-view-demo.js b/packages/data-table-view/src/dbp-data-table-view-demo.js
index dc2bb24d0398aab00880490fd4b0b16b14bf0ef0..7544fdc067d938fc90e3b9faedf1e68f7266c354 100644
--- a/packages/data-table-view/src/dbp-data-table-view-demo.js
+++ b/packages/data-table-view/src/dbp-data-table-view-demo.js
@@ -1,6 +1,6 @@
 import {AuthKeycloak, LoginButton} from '@dbp-toolkit/auth';
 import {DataTableView} from './data-table-view.js';
-import {i18n} from './i18n';
+import {createInstance} from './i18n';
 import {css, html} from 'lit-element';
 import {ScopedElementsMixin} from '@open-wc/scoped-elements';
 import * as commonUtils from '@dbp-toolkit/common/utils';
@@ -10,7 +10,8 @@ import DBPLitElement from "@dbp-toolkit/common/dbp-lit-element";
 export class DataTableViewDemo extends ScopedElementsMixin(DBPLitElement) {
     constructor() {
         super();
-        this.lang = 'de';
+        this._i18n = createInstance();
+        this.lang = this._i18n.language;
         this.entryPointUrl = '';
         this.noAuth = false;
     }
@@ -100,7 +101,7 @@ export class DataTableViewDemo extends ScopedElementsMixin(DBPLitElement) {
     update(changedProperties) {
         changedProperties.forEach((oldValue, propName) => {
             if (propName === "lang") {
-                i18n.changeLanguage(this.lang);
+                this._i18n.changeLanguage(this.lang);
             }
         });
 
diff --git a/packages/data-table-view/src/i18n.js b/packages/data-table-view/src/i18n.js
index a2380632e7095df7cc09dddf372598f5d6b5898c..975c1993e2a567940c74f8d957a6b2a018125548 100644
--- a/packages/data-table-view/src/i18n.js
+++ b/packages/data-table-view/src/i18n.js
@@ -1,29 +1,8 @@
-import i18next from 'i18next';
+import {createInstance as _createInstance} from '@dbp-toolkit/common/i18next.js';
 
 import de from './i18n/de/translation.json';
 import en from './i18n/en/translation.json';
 
-const i18n = i18next.createInstance();
-
-i18n.init({
-    lng: 'de',
-    fallbackLng: ['de'],
-    debug: false,
-    initImmediate: false, // Don't init async
-    resources: {
-        en: {translation: en},
-        de: {translation: de}
-    },
-});
-
-console.assert(i18n.isInitialized);
-
-function dateTimeFormat(date, options) {
-    return new Intl.DateTimeFormat(i18n.languages, options).format(date);
-}
-
-function numberFormat(number, options) {
-    return new Intl.NumberFormat(i18n.languages, options).format(number);
-}
-
-export {i18n, dateTimeFormat, numberFormat};
+export function createInstance() {
+    return _createInstance({en: en, de: de}, 'de', 'en');
+}
\ No newline at end of file
diff --git a/packages/data-table-view/src/i18n/de/translation.json b/packages/data-table-view/src/i18n/de/translation.json
index d1776ebc73f39cdfe749d64aa2357557c6399189..ed90a81bded1457b6812b1c1de10aa6e71d6b272 100644
--- a/packages/data-table-view/src/i18n/de/translation.json
+++ b/packages/data-table-view/src/i18n/de/translation.json
@@ -3,4 +3,4 @@
   "export-excel": "Excel Export",
   "export-csv": "CSV Export",
   "column-search-placeholder": "Nach {{fieldName}} suchen"
-}
\ No newline at end of file
+}
diff --git a/packages/data-table-view/src/i18n/en/translation.json b/packages/data-table-view/src/i18n/en/translation.json
index 33ea4a209861b14cd3c7e4c1a4902a6fab07bd89..0c0acdb39f4d0c3af06998f9cddfb426c23e2f21 100644
--- a/packages/data-table-view/src/i18n/en/translation.json
+++ b/packages/data-table-view/src/i18n/en/translation.json
@@ -3,4 +3,4 @@
   "export-excel": "Excel Export",
   "export-csv": "CSV Export",
   "column-search-placeholder": "Search for {{fieldName}}"
-}
\ No newline at end of file
+}
diff --git a/packages/file-handling/i18next-scanner.config.js b/packages/file-handling/i18next-scanner.config.js
index 8c277798414be902846c6eb4f0e95a19750cda39..aeb8fdb6532e6c951401ba91424e2a256353d391 100644
--- a/packages/file-handling/i18next-scanner.config.js
+++ b/packages/file-handling/i18next-scanner.config.js
@@ -6,6 +6,7 @@ module.exports = {
     options: {
         debug: false,
         removeUnusedKeys: true,
+        func: {list: ['i18n.t', '_i18n.t']},
         lngs: ['en','de'],
         resource: {
             loadPath: 'src/i18n/{{lng}}/{{ns}}.json',
diff --git a/packages/file-handling/src/clipboard.js b/packages/file-handling/src/clipboard.js
index 0526c4164f54c3b9cd1eda92fac03400454e395c..d488a8dd2d977bd3768c6e0cd415af82efbe6fd1 100644
--- a/packages/file-handling/src/clipboard.js
+++ b/packages/file-handling/src/clipboard.js
@@ -1,4 +1,4 @@
-import {i18n} from './i18n';
+import {createInstance} from './i18n';
 import {css, html} from 'lit-element';
 import {ScopedElementsMixin} from '@open-wc/scoped-elements';
 import * as commonUtils from '@dbp-toolkit/common/utils';
@@ -20,7 +20,8 @@ export class Clipboard extends ScopedElementsMixin(AdapterLitElement) {
 
     constructor() {
         super();
-        this.lang = 'de';
+        this._i18n = createInstance();
+        this.lang = this._i18n.language;
         this.allowedMimeTypes = '*/*';
         this.clipboardFiles = {files: ''};
         this.clipboardSelectBtnDisabled = true;
@@ -86,7 +87,7 @@ export class Clipboard extends ScopedElementsMixin(AdapterLitElement) {
         changedProperties.forEach((oldValue, propName) => {
             switch (propName) {
                 case "lang":
-                    i18n.changeLanguage(this.lang);
+                    this._i18n.changeLanguage(this.lang);
                     break;
                 case "clipboardFiles":
                     this.generateClipboardTable();
@@ -119,6 +120,7 @@ export class Clipboard extends ScopedElementsMixin(AdapterLitElement) {
 
 
     connectedCallback() {
+        const i18n = this._i18n;
         super.connectedCallback();
         const that = this;
         this.updateComplete.then(() => {
@@ -358,6 +360,7 @@ export class Clipboard extends ScopedElementsMixin(AdapterLitElement) {
      * @param files
      */
     async sendClipboardFiles(files) {
+        const i18n = this._i18n;
         for (let i = 0; i < files.length; i ++) {
             await this.sendFileEvent(files[i].file);
         }
@@ -384,6 +387,7 @@ export class Clipboard extends ScopedElementsMixin(AdapterLitElement) {
      * @param event
      */
     onReceiveBeforeUnload(event) {
+        const i18n = this._i18n;
 
         // we don't need to stop if there are no signed files
         if (this.clipboardFiles.files.length === 0) {
@@ -446,6 +450,8 @@ export class Clipboard extends ScopedElementsMixin(AdapterLitElement) {
      */
     saveFilesToClipboard()
     {
+        const i18n = this._i18n;
+
         //save it
         let data = {};
         let files = [];
@@ -476,6 +482,8 @@ export class Clipboard extends ScopedElementsMixin(AdapterLitElement) {
      * @param event
      */
     finishedSaveFilesToClipboard(event) {
+        const i18n = this._i18n;
+
         send({
             "summary": i18n.t('clipboard.saved-files-title', {count: event.detail.count}),
             "body": i18n.t('clipboard.saved-files-body', {count: event.detail.count}),
@@ -512,6 +520,8 @@ export class Clipboard extends ScopedElementsMixin(AdapterLitElement) {
      *
      */
     clearClipboard() {
+        const i18n = this._i18n;
+
         if (this.tabulatorTable && this.tabulatorTable.getSelectedData().length > 0) {
             let count = this.tabulatorTable.getSelectedData().length;
             this.tabulatorTable.deleteRow(this.tabulatorTable.getSelectedRows());
@@ -547,6 +557,7 @@ export class Clipboard extends ScopedElementsMixin(AdapterLitElement) {
      * @returns {html}
      */
     getAdditionalButtons() {
+        const i18n = this._i18n;
         let buttonsAreDisabled = this.clipboardFiles.files.length === 0 ? true : this.clipboardSelectBtnDisabled;
         return html`
             <div class="flex-container additional-button-container">
@@ -611,6 +622,7 @@ export class Clipboard extends ScopedElementsMixin(AdapterLitElement) {
      * @returns {html}
      */
     getClipboardSink() {
+        const i18n = this._i18n;
         const tabulatorCss = commonUtils.getAssetURL(pkgName, 'tabulator-tables/css/tabulator.min.css');
         return html`
             <div class="wrapper">
@@ -645,6 +657,7 @@ export class Clipboard extends ScopedElementsMixin(AdapterLitElement) {
      */
     getClipboardSource() {
         const tabulatorCss = commonUtils.getAssetURL(pkgName, 'tabulator-tables/css/tabulator.min.css');
+        const i18n = this._i18n;
         return html`
             <div class="wrapper">
                 <div class="content">
diff --git a/packages/file-handling/src/demo.js b/packages/file-handling/src/demo.js
index ede45f52aaf62783f43a612e66bf164678f0dcc0..e723a9a900f80ee620f469529223efbb5ef95dcd 100644
--- a/packages/file-handling/src/demo.js
+++ b/packages/file-handling/src/demo.js
@@ -1,4 +1,4 @@
-import {i18n} from './i18n';
+import {createInstance} from './i18n';
 import {html, LitElement} from 'lit-element';
 import {unsafeHTML} from 'lit-html/directives/unsafe-html.js';
 import {ScopedElementsMixin} from '@open-wc/scoped-elements';
@@ -9,7 +9,8 @@ import * as commonUtils from '@dbp-toolkit/common/utils';
 export class FileSourceDemo extends ScopedElementsMixin(LitElement) {
     constructor() {
         super();
-        this.lang = 'de';
+        this._i18n = createInstance();
+        this.lang = this._i18n.language;
         this.url = '';
         this.selectedFiles = [];
         this.selectedFilesCount = 0;
@@ -46,7 +47,7 @@ export class FileSourceDemo extends ScopedElementsMixin(LitElement) {
     update(changedProperties) {
         changedProperties.forEach((oldValue, propName) => {
             if (propName === "lang") {
-                i18n.changeLanguage(this.lang);
+                this._i18n.changeLanguage(this.lang);
             }
         });
 
@@ -77,6 +78,8 @@ export class FileSourceDemo extends ScopedElementsMixin(LitElement) {
     }
 
     render() {
+        const i18n = this._i18n;
+
         return html`
             <style>
                 dbp-file-source.clean {
diff --git a/packages/file-handling/src/file-sink.js b/packages/file-handling/src/file-sink.js
index b71f6b2c711cc7ae7c02b025cad74ee3f3d13003..4a46ff3028c4eed0f7368f52ab6fea24f6155a2d 100644
--- a/packages/file-handling/src/file-sink.js
+++ b/packages/file-handling/src/file-sink.js
@@ -1,4 +1,4 @@
-import {i18n} from './i18n';
+import {createInstance} from './i18n';
 import {css, html} from 'lit-element';
 import {ScopedElementsMixin} from '@open-wc/scoped-elements';
 import DBPLitElement from '@dbp-toolkit/common/dbp-lit-element';
@@ -22,7 +22,8 @@ export class FileSink extends ScopedElementsMixin(DbpFileHandlingLitElement) {
     constructor() {
         super();
         this.context = '';
-        this.lang = 'de';
+        this._i18n = createInstance();
+        this.lang = this._i18n.language;
         this.nextcloudAuthUrl = '';
         this.nextcloudWebDavUrl = '';
         this.nextcloudName ='Nextcloud';
@@ -127,7 +128,7 @@ export class FileSink extends ScopedElementsMixin(DbpFileHandlingLitElement) {
         changedProperties.forEach((oldValue, propName) => {
             switch (propName) {
                 case "lang":
-                    i18n.changeLanguage(this.lang);
+                    this._i18n.changeLanguage(this.lang);
                     break;
                 case "enabledTargets":
                     if (!this.hasEnabledDestination(this.activeTargets)) {
@@ -168,6 +169,7 @@ export class FileSink extends ScopedElementsMixin(DbpFileHandlingLitElement) {
     }
 
     finishedFileUpload(event) {
+        const i18n = this._i18n;
         this.sendDestination();
         MicroModal.close(this._('#modal-picker'));
         if (event.detail > 0) {
@@ -273,6 +275,7 @@ export class FileSink extends ScopedElementsMixin(DbpFileHandlingLitElement) {
     }
 
     getNextcloudHtml() {
+        const i18n = this._i18n;
         if (this.enabledTargets.includes('nextcloud') && this.nextcloudWebDavUrl !== "" && this.nextcloudAuthUrl !== "") {
             return html`
                 <dbp-nextcloud-file-picker id="nextcloud-file-picker"
@@ -383,7 +386,7 @@ export class FileSink extends ScopedElementsMixin(DbpFileHandlingLitElement) {
     }
 
     render() {
-
+        const i18n = this._i18n;
         return html`
             <vpu-notification lang="de" client-id="my-client-id"></vpu-notification>
             <div class="modal micromodal-slide" id="modal-picker" aria-hidden="true">
diff --git a/packages/file-handling/src/file-source.js b/packages/file-handling/src/file-source.js
index 7992983c3a2ca3613b2dfe57634cf69f89446131..4b572d188f19ed9ccc7978d64120327e93bda1fe 100644
--- a/packages/file-handling/src/file-source.js
+++ b/packages/file-handling/src/file-source.js
@@ -1,4 +1,4 @@
-import {i18n} from './i18n';
+import {createInstance} from './i18n';
 import {css, html} from 'lit-element';
 import {ScopedElementsMixin} from '@open-wc/scoped-elements';
 import DBPLitElement from '@dbp-toolkit/common/dbp-lit-element';
@@ -38,7 +38,8 @@ export class FileSource extends ScopedElementsMixin(DbpFileHandlingLitElement) {
     constructor() {
         super();
         this.context = '';
-        this.lang = 'de';
+        this._i18n = createInstance();
+        this.lang = this._i18n.language;
         this.nextcloudAuthUrl = '';
         this.nextcloudName ='Nextcloud';
         this.nextcloudWebDavUrl = '';
@@ -97,7 +98,7 @@ export class FileSource extends ScopedElementsMixin(DbpFileHandlingLitElement) {
         changedProperties.forEach((oldValue, propName) => {
             switch (propName) {
                 case "lang":
-                    i18n.changeLanguage(this.lang);
+                    this._i18n.changeLanguage(this.lang);
                     break;
                 case "enabledTargets":
                     if (!this.hasEnabledSource(this.activeTarget)) {
@@ -328,6 +329,7 @@ export class FileSource extends ScopedElementsMixin(DbpFileHandlingLitElement) {
 
         // no suitable files found
         if (filesToHandle.length === 0) {
+            const i18n = this._i18n;
             console.error('ZIP file does not contain any files of ' + this.allowedMimeTypes);
             //throw new Error('ZIP file does not contain any files of ' + this.allowedMimeTypes);
             notify({
@@ -585,6 +587,7 @@ export class FileSource extends ScopedElementsMixin(DbpFileHandlingLitElement) {
     }
 
     render() {
+        const i18n = this._i18n;
         let allowedMimeTypes = this.allowedMimeTypes;
 
         if (this.decompressZip && this.allowedMimeTypes !== "*/*") {
diff --git a/packages/file-handling/src/i18n.js b/packages/file-handling/src/i18n.js
index 498d9f037b0a5ca481ec8de5df24640900285808..975c1993e2a567940c74f8d957a6b2a018125548 100644
--- a/packages/file-handling/src/i18n.js
+++ b/packages/file-handling/src/i18n.js
@@ -1,6 +1,8 @@
-import {createInstance} 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';
 
-export const i18n = createInstance({en: en, de: de}, 'de', 'en');
\ No newline at end of file
+export function createInstance() {
+    return _createInstance({en: en, de: de}, 'de', 'en');
+}
\ No newline at end of file
diff --git a/packages/file-handling/src/nextcloud-file-picker.js b/packages/file-handling/src/nextcloud-file-picker.js
index 46c3ecb4d30521a712fe0d9bdd280f33b272c82a..1ac5ea7b13064172c6b1cf768ba06e5a1a36605b 100644
--- a/packages/file-handling/src/nextcloud-file-picker.js
+++ b/packages/file-handling/src/nextcloud-file-picker.js
@@ -1,4 +1,4 @@
-import {i18n} from './i18n';
+import {createInstance} from './i18n';
 import {css, html} from 'lit-element';
 import {ScopedElementsMixin} from '@open-wc/scoped-elements';
 import DBPLitElement from '@dbp-toolkit/common/dbp-lit-element';
@@ -19,7 +19,9 @@ import * as fileHandlingStyles from './styles';
 export class NextcloudFilePicker extends ScopedElementsMixin(DBPLitElement) {
     constructor() {
         super();
-        this.lang = 'de';
+        this._i18n = createInstance();
+        this.lang = this._i18n.language;
+        
         this.authUrl = '';
         this.webDavUrl = '';
         this.nextcloudName = 'Nextcloud';
@@ -37,7 +39,7 @@ export class NextcloudFilePicker extends ScopedElementsMixin(DBPLitElement) {
         this.loading = false;
         this._onReceiveWindowMessage = this.onReceiveWindowMessage.bind(this);
 
-        this.folderIsSelected = i18n.t('nextcloud-file-picker.load-in-folder');
+        this.folderIsSelected = this._i18n.t('nextcloud-file-picker.load-in-folder');
         this.generatedFilename = '';
         this.replaceFilename = '';
         this.customFilename = '';
@@ -97,7 +99,7 @@ export class NextcloudFilePicker extends ScopedElementsMixin(DBPLitElement) {
         changedProperties.forEach((oldValue, propName) => {
             switch (propName) {
                 case "lang":
-                    i18n.changeLanguage(this.lang);
+                    this._i18n.changeLanguage(this.lang);
                     break;
                 case "directoriesOnly":
                     if (this.directoriesOnly && this._("#select_all_wrapper")) {
@@ -136,6 +138,7 @@ export class NextcloudFilePicker extends ScopedElementsMixin(DBPLitElement) {
     connectedCallback() {
         super.connectedCallback();
         const that = this;
+        const i18n = this._i18n;
         this.updateComplete.then(() => {
             // see: https://developer.mozilla.org/en-US/docs/Web/API/Window/postMessage
             window.addEventListener('message', this._onReceiveWindowMessage);
@@ -375,6 +378,7 @@ export class NextcloudFilePicker extends ScopedElementsMixin(DBPLitElement) {
     }
 
     openFilePicker() {
+        const i18n = this._i18n;
         if (this.webDavClient === null) {
             this.loading = true;
             this.statusText = i18n.t('nextcloud-file-picker.auth-progress');
@@ -423,6 +427,7 @@ export class NextcloudFilePicker extends ScopedElementsMixin(DBPLitElement) {
      * @param path
      */
     loadDirectory(path) {
+        const i18n = this._i18n;
         if (typeof this.directoryPath === 'undefined' || this.directoryPath === undefined) {
             this.directoryPath = '';
         }
@@ -567,6 +572,7 @@ export class NextcloudFilePicker extends ScopedElementsMixin(DBPLitElement) {
      * @param fileData
      */
     downloadFile(fileData) {
+        const i18n = this._i18n;
         this.loading = true;
         this.statusText = "Loading " + fileData.filename + "...";
 
@@ -597,6 +603,7 @@ export class NextcloudFilePicker extends ScopedElementsMixin(DBPLitElement) {
      * @param directory
      */
     sendDirectory(directory) {
+        const i18n = this._i18n;
         this.tabulatorTable.deselectRow();
         let path;
 
@@ -621,6 +628,7 @@ export class NextcloudFilePicker extends ScopedElementsMixin(DBPLitElement) {
      * @param directory
      */
     uploadFiles(files, directory) {
+        const i18n = this._i18n;
         this.loading = true;
         this.statusText = i18n.t('nextcloud-file-picker.upload-to', {path: directory});
         this.fileList = files;
@@ -641,6 +649,7 @@ export class NextcloudFilePicker extends ScopedElementsMixin(DBPLitElement) {
      * @param directory
      */
     async uploadFile(directory) {
+        const i18n = this._i18n;
         if (this.abortUpload) {
             this.abortUpload = false;
             this.abortUploadButton = false;
@@ -707,6 +716,7 @@ export class NextcloudFilePicker extends ScopedElementsMixin(DBPLitElement) {
      *
      */
     async uploadFileAfterConflict() {
+        const i18n = this._i18n;
         if (this.abortUpload) {
             this.abortUpload = false;
             this.abortUploadButton = false;
@@ -856,6 +866,7 @@ export class NextcloudFilePicker extends ScopedElementsMixin(DBPLitElement) {
      * @param directory
      */
     replaceModalDialog(file, directory) {
+        const i18n = this._i18n;
         this.uploadFileObject = file;
         this.uploadFileDirectory = directory;
         let rights = this.checkRights(file);
@@ -964,6 +975,7 @@ export class NextcloudFilePicker extends ScopedElementsMixin(DBPLitElement) {
      * @returns {string} correct cancel text
      */
     getCancelText() {
+        const i18n = this._i18n;
         if (this.fileList.length > 1) {
             return i18n.t('nextcloud-file-picker.replace-cancel-all');
         }
@@ -991,6 +1003,7 @@ export class NextcloudFilePicker extends ScopedElementsMixin(DBPLitElement) {
      *
      */
     openAddFolderDialogue() {
+        const i18n = this._i18n;
         if (this._('.addRowAnimation')) {
             this._('.addRowAnimation').classList.remove('addRowAnimation');
         }
@@ -1010,6 +1023,7 @@ export class NextcloudFilePicker extends ScopedElementsMixin(DBPLitElement) {
      *
      */
     addFolder() {
+        const i18n = this._i18n;
         if (this._('#new-folder').value !== "") {
             let folderName = this._('#new-folder').value;
             if (typeof this.directoryPath === 'undefined') {
@@ -1090,6 +1104,7 @@ export class NextcloudFilePicker extends ScopedElementsMixin(DBPLitElement) {
      * @returns {string} clickable breadcrumb path
      */
     getBreadcrumb() {
+        const i18n = this._i18n;
         if (typeof this.directoryPath === 'undefined') {
             this.directoryPath = '';
         }
@@ -1596,6 +1611,7 @@ export class NextcloudFilePicker extends ScopedElementsMixin(DBPLitElement) {
     }
 
     render() {
+        const i18n = this._i18n;
         const tabulatorCss = commonUtils.getAssetURL(pkgName, 'tabulator-tables/css/tabulator.min.css');
 
         return html`
diff --git a/packages/knowledge-base-web-page-element-view/package.json b/packages/knowledge-base-web-page-element-view/package.json
index df0e937daa5052335d27d2f3600907b26fee8422..e9be74960f48f871226e7c9896cf6bb4e76eb86f 100644
--- a/packages/knowledge-base-web-page-element-view/package.json
+++ b/packages/knowledge-base-web-page-element-view/package.json
@@ -30,7 +30,8 @@
     "rollup-plugin-copy": "^3.1.0",
     "rollup-plugin-delete": "^2.0.0",
     "rollup-plugin-serve": "^1.0.1",
-    "rollup-plugin-terser": "^7.0.2"
+    "rollup-plugin-terser": "^7.0.2",
+    "i18next-scanner": "^3.0.0"
   },
   "dependencies": {
     "@dbp-toolkit/auth": "^0.2.2",
@@ -42,6 +43,7 @@
     "material-design-icons-svg": "^3.0.0"
   },
   "scripts": {
+    "i18next": "i18next-scanner",
     "clean": "rm dist/*",
     "build": "npm run build-local",
     "build-local": "rollup -c",
diff --git a/packages/knowledge-base-web-page-element-view/src/dbp-knowledge-base-web-page-element-view-demo.js b/packages/knowledge-base-web-page-element-view/src/dbp-knowledge-base-web-page-element-view-demo.js
index 717b3c1c4a495f4bb2ed6143bb1294aa0b81087a..4a739d9780f282b7fd1f62552d709619ce248829 100644
--- a/packages/knowledge-base-web-page-element-view/src/dbp-knowledge-base-web-page-element-view-demo.js
+++ b/packages/knowledge-base-web-page-element-view/src/dbp-knowledge-base-web-page-element-view-demo.js
@@ -1,4 +1,4 @@
-import {i18n} from './i18n';
+import {createInstance} from './i18n';
 import {css, html} from 'lit-element';
 import {ScopedElementsMixin} from '@open-wc/scoped-elements';
 import {AuthKeycloak, LoginButton} from '@dbp-toolkit/auth';
@@ -10,7 +10,8 @@ import DBPLitElement from "@dbp-toolkit/common/dbp-lit-element";
 export class KnowledgeBaseWebPageElementViewDemo extends ScopedElementsMixin(DBPLitElement) {
     constructor() {
         super();
-        this.lang = 'de';
+        this._i18n = createInstance();
+        this.lang = this._i18n.language;
         this.entryPointUrl = '';
         this.noAuth = false;
     }
@@ -35,7 +36,7 @@ export class KnowledgeBaseWebPageElementViewDemo extends ScopedElementsMixin(DBP
     update(changedProperties) {
         changedProperties.forEach((oldValue, propName) => {
             if (propName === "lang") {
-                i18n.changeLanguage(this.lang);
+                this._i18n.changeLanguage(this.lang);
             }
         });
 
diff --git a/packages/knowledge-base-web-page-element-view/src/i18n.js b/packages/knowledge-base-web-page-element-view/src/i18n.js
index 498d9f037b0a5ca481ec8de5df24640900285808..975c1993e2a567940c74f8d957a6b2a018125548 100644
--- a/packages/knowledge-base-web-page-element-view/src/i18n.js
+++ b/packages/knowledge-base-web-page-element-view/src/i18n.js
@@ -1,6 +1,8 @@
-import {createInstance} 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';
 
-export const i18n = createInstance({en: en, de: de}, 'de', 'en');
\ No newline at end of file
+export function createInstance() {
+    return _createInstance({en: en, de: de}, 'de', 'en');
+}
\ No newline at end of file
diff --git a/packages/knowledge-base-web-page-element-view/src/knowledge-base-web-page-element-view.js b/packages/knowledge-base-web-page-element-view/src/knowledge-base-web-page-element-view.js
index 9b34f065e3f921b2b545fc24db7d9753d728023f..57234041559bb04593f407fd1a153f1cb3faf271 100644
--- a/packages/knowledge-base-web-page-element-view/src/knowledge-base-web-page-element-view.js
+++ b/packages/knowledge-base-web-page-element-view/src/knowledge-base-web-page-element-view.js
@@ -1,4 +1,4 @@
-import {i18n} from './i18n';
+import {createInstance} from './i18n';
 import {html} from 'lit-element';
 import {ScopedElementsMixin} from '@open-wc/scoped-elements';
 import {MiniSpinner} from '@dbp-toolkit/common';
@@ -12,7 +12,8 @@ import {AdapterLitElement} from "@dbp-toolkit/provider/src/adapter-lit-element";
 export class KnowledgeBaseWebPageElementView extends ScopedElementsMixin(AdapterLitElement) {
     constructor() {
         super();
-        this.lang = 'de';
+        this._i18n = createInstance();
+        this.lang = this._i18n.language;
         this.value = '';
         this.html = '';
         this.entryPointUrl = '';
@@ -56,6 +57,8 @@ export class KnowledgeBaseWebPageElementView extends ScopedElementsMixin(Adapter
      * Loads the data from the web page element
      */
     loadWebPageElement() {
+        const i18n = this._i18n;
+
         if (this.auth.token === undefined || this.auth.token === "") {
             return;
         }
@@ -107,7 +110,7 @@ export class KnowledgeBaseWebPageElementView extends ScopedElementsMixin(Adapter
     update(changedProperties) {
         changedProperties.forEach((oldValue, propName) => {
             if (propName === "lang") {
-                i18n.changeLanguage(this.lang);
+                this._i18n.changeLanguage(this.lang);
             }
 
             switch(propName) {
diff --git a/packages/matomo/i18next-scanner.config.js b/packages/matomo/i18next-scanner.config.js
index 8c277798414be902846c6eb4f0e95a19750cda39..aeb8fdb6532e6c951401ba91424e2a256353d391 100644
--- a/packages/matomo/i18next-scanner.config.js
+++ b/packages/matomo/i18next-scanner.config.js
@@ -6,6 +6,7 @@ module.exports = {
     options: {
         debug: false,
         removeUnusedKeys: true,
+        func: {list: ['i18n.t', '_i18n.t']},
         lngs: ['en','de'],
         resource: {
             loadPath: 'src/i18n/{{lng}}/{{ns}}.json',
diff --git a/packages/matomo/src/dbp-matomo-demo.js b/packages/matomo/src/dbp-matomo-demo.js
index bf07bd0fe1ffe33d694511ecad22db5da9979d1b..cad9ec437c6e8d54517150ee67f4cbae2f4524de 100644
--- a/packages/matomo/src/dbp-matomo-demo.js
+++ b/packages/matomo/src/dbp-matomo-demo.js
@@ -1,4 +1,4 @@
-import {i18n} from './i18n.js';
+import {createInstance} from './i18n.js';
 import {css, html} from 'lit-element';
 import {ScopedElementsMixin} from '@open-wc/scoped-elements';
 import {AuthKeycloak, LoginButton} from '@dbp-toolkit/auth';
@@ -12,7 +12,8 @@ export class MatomoDemo extends ScopedElementsMixin(DBPLitElement) {
 
     constructor() {
         super();
-        this.lang = 'de';
+        this._i18n = createInstance();
+        this.lang = this._i18n.language;
         this.entryPointUrl = '';
         this.matomoUrl = '';
         this.matomoSiteId = -1;
@@ -38,9 +39,14 @@ export class MatomoDemo extends ScopedElementsMixin(DBPLitElement) {
         };
     }
 
-    connectedCallback() {
-        super.connectedCallback();
-        i18n.changeLanguage(this.lang);
+    update(changedProperties) {
+         changedProperties.forEach((oldValue, propName) => {
+            if (propName === "lang") {
+                this._i18n.changeLanguage(this.lang);
+            }
+        });
+
+        super.update(changedProperties);
     }
 
     track(action, message) {
diff --git a/packages/matomo/src/i18n.js b/packages/matomo/src/i18n.js
index 498d9f037b0a5ca481ec8de5df24640900285808..975c1993e2a567940c74f8d957a6b2a018125548 100644
--- a/packages/matomo/src/i18n.js
+++ b/packages/matomo/src/i18n.js
@@ -1,6 +1,8 @@
-import {createInstance} 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';
 
-export const i18n = createInstance({en: en, de: de}, 'de', 'en');
\ No newline at end of file
+export function createInstance() {
+    return _createInstance({en: en, de: de}, 'de', 'en');
+}
\ No newline at end of file
diff --git a/packages/matomo/src/i18n/de/translation.json b/packages/matomo/src/i18n/de/translation.json
index 87a8a87f09208414abfad579bfa3611cbcddc57b..0967ef424bce6791893e9a57bb952f80fd536e93 100644
--- a/packages/matomo/src/i18n/de/translation.json
+++ b/packages/matomo/src/i18n/de/translation.json
@@ -1,5 +1 @@
-{
-  "matomo": {
-
-  }
-}
\ No newline at end of file
+{}
diff --git a/packages/matomo/src/i18n/en/translation.json b/packages/matomo/src/i18n/en/translation.json
index 87a8a87f09208414abfad579bfa3611cbcddc57b..0967ef424bce6791893e9a57bb952f80fd536e93 100644
--- a/packages/matomo/src/i18n/en/translation.json
+++ b/packages/matomo/src/i18n/en/translation.json
@@ -1,5 +1 @@
-{
-  "matomo": {
-
-  }
-}
\ No newline at end of file
+{}
diff --git a/packages/notification/i18next-scanner.config.js b/packages/notification/i18next-scanner.config.js
index 8c277798414be902846c6eb4f0e95a19750cda39..aeb8fdb6532e6c951401ba91424e2a256353d391 100644
--- a/packages/notification/i18next-scanner.config.js
+++ b/packages/notification/i18next-scanner.config.js
@@ -6,6 +6,7 @@ module.exports = {
     options: {
         debug: false,
         removeUnusedKeys: true,
+        func: {list: ['i18n.t', '_i18n.t']},
         lngs: ['en','de'],
         resource: {
             loadPath: 'src/i18n/{{lng}}/{{ns}}.json',
diff --git a/packages/notification/src/dbp-notification-demo.js b/packages/notification/src/dbp-notification-demo.js
index 64d507b3c165cf586ead1baf9fffd378585b7fd7..8919e31f560935ff169f9b8109324a7ba1193b04 100644
--- a/packages/notification/src/dbp-notification-demo.js
+++ b/packages/notification/src/dbp-notification-demo.js
@@ -1,4 +1,4 @@
-import {i18n} from './i18n';
+import {createInstance} from './i18n';
 import {send as notify} from '@dbp-toolkit/common/notification';
 import {css, html, LitElement} from 'lit-element';
 import {ScopedElementsMixin} from '@open-wc/scoped-elements';
@@ -9,7 +9,8 @@ import * as commonStyles from "@dbp-toolkit/common/styles";
 export class NotificationDemo extends ScopedElementsMixin(LitElement) {
     constructor() {
         super();
-        this.lang = 'de';
+        this._i18n = createInstance();
+        this.lang = this._i18n.language;
     }
 
     static get scopedElements() {
@@ -24,13 +25,15 @@ export class NotificationDemo extends ScopedElementsMixin(LitElement) {
         };
     }
 
-    connectedCallback() {
-        super.connectedCallback();
-        i18n.changeLanguage(this.lang);
+    update(changedProperties) {
+        changedProperties.forEach((oldValue, propName) => {
+           if (propName === "lang") {
+               this._i18n.changeLanguage(this.lang);
+           }
+       });
 
-        this.updateComplete.then(()=>{
-        });
-    }
+       super.update(changedProperties);
+   }
 
     static get styles() {
         // language=css
@@ -42,6 +45,8 @@ export class NotificationDemo extends ScopedElementsMixin(LitElement) {
     }
 
     render() {
+        const i18n = this._i18n;
+
         return html`
             <section class="section">
                 <div class="container">
diff --git a/packages/notification/src/i18n.js b/packages/notification/src/i18n.js
index 498d9f037b0a5ca481ec8de5df24640900285808..975c1993e2a567940c74f8d957a6b2a018125548 100644
--- a/packages/notification/src/i18n.js
+++ b/packages/notification/src/i18n.js
@@ -1,6 +1,8 @@
-import {createInstance} 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';
 
-export const i18n = createInstance({en: en, de: de}, 'de', 'en');
\ No newline at end of file
+export function createInstance() {
+    return _createInstance({en: en, de: de}, 'de', 'en');
+}
\ No newline at end of file
diff --git a/packages/notification/src/notification.js b/packages/notification/src/notification.js
index 9faf5efda5e758cb2b349717bde53098b99e9f27..76a9c7a7ccf63d1cab0b46fea9ca5ff4e83a13ca 100644
--- a/packages/notification/src/notification.js
+++ b/packages/notification/src/notification.js
@@ -1,4 +1,4 @@
-import {i18n} from './i18n';
+import {createInstance} from './i18n';
 import {createUUID} from './utils';
 import {css, html} from 'lit-element';
 import DBPLitElement from '@dbp-toolkit/common/dbp-lit-element';
@@ -10,7 +10,8 @@ import * as commonStyles from '@dbp-toolkit/common/styles';
 export class Notification extends DBPLitElement {
     constructor() {
         super();
-        this.lang = 'de';
+        this._i18n = createInstance();
+        this.lang = this._i18n.language;
     }
 
     /**
@@ -25,7 +26,6 @@ export class Notification extends DBPLitElement {
 
     connectedCallback() {
         super.connectedCallback();
-        i18n.changeLanguage(this.lang);
         const that = this;
 
         window.addEventListener("dbp-notification-send", (e) => {
@@ -63,9 +63,6 @@ export class Notification extends DBPLitElement {
             // mark the event as handled
             e.preventDefault();
         });
-
-        this.updateComplete.then(()=>{
-        });
     }
 
     removeMessageId(messageElementId) {
diff --git a/packages/organization-select/i18next-scanner.config.js b/packages/organization-select/i18next-scanner.config.js
index 8c277798414be902846c6eb4f0e95a19750cda39..aeb8fdb6532e6c951401ba91424e2a256353d391 100644
--- a/packages/organization-select/i18next-scanner.config.js
+++ b/packages/organization-select/i18next-scanner.config.js
@@ -6,6 +6,7 @@ module.exports = {
     options: {
         debug: false,
         removeUnusedKeys: true,
+        func: {list: ['i18n.t', '_i18n.t']},
         lngs: ['en','de'],
         resource: {
             loadPath: 'src/i18n/{{lng}}/{{ns}}.json',
diff --git a/packages/organization-select/src/dbp-organization-select-demo.js b/packages/organization-select/src/dbp-organization-select-demo.js
index 1ece3ccbca35f1592f7ddcf21b7b928a7623b483..6d4898bc53fe8eca0390f39f08a5b65a24fb727c 100644
--- a/packages/organization-select/src/dbp-organization-select-demo.js
+++ b/packages/organization-select/src/dbp-organization-select-demo.js
@@ -1,4 +1,4 @@
-import {i18n} from './i18n.js';
+import {createInstance} from './i18n.js';
 import {css, html} from 'lit-element';
 import {ScopedElementsMixin} from '@open-wc/scoped-elements';
 import {OrganizationSelect} from './organization-select.js';
@@ -10,7 +10,8 @@ import DBPLitElement from "@dbp-toolkit/common/dbp-lit-element";
 export class OrganizationSelectDemo extends ScopedElementsMixin(DBPLitElement) {
     constructor() {
         super();
-        this.lang = 'de';
+        this._i18n = createInstance();
+        this.lang = this._i18n.language;
         this.entryPointUrl = '';
         this.noAuth = false;
     }
@@ -32,12 +33,11 @@ export class OrganizationSelectDemo extends ScopedElementsMixin(DBPLitElement) {
         };
     }
 
-    connectedCallback() {
-        super.connectedCallback();
-        i18n.changeLanguage(this.lang);
-
-        this.updateComplete.then(()=>{
-        });
+    update(changedProperties) {
+        if (changedProperties.has("lang")) {
+            this._i18n.changeLanguage(this.lang);
+        }
+        super.update(changedProperties);
     }
 
     static get styles() {
diff --git a/packages/organization-select/src/i18n.js b/packages/organization-select/src/i18n.js
index 498d9f037b0a5ca481ec8de5df24640900285808..975c1993e2a567940c74f8d957a6b2a018125548 100644
--- a/packages/organization-select/src/i18n.js
+++ b/packages/organization-select/src/i18n.js
@@ -1,6 +1,8 @@
-import {createInstance} 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';
 
-export const i18n = createInstance({en: en, de: de}, 'de', 'en');
\ No newline at end of file
+export function createInstance() {
+    return _createInstance({en: en, de: de}, 'de', 'en');
+}
\ No newline at end of file
diff --git a/packages/organization-select/src/i18n/de/translation.json b/packages/organization-select/src/i18n/de/translation.json
index 9a8c760673e85d97460be4170d00c17f070a56fc..bcef063e83ed380940cbb466442734eb7aebb3e0 100644
--- a/packages/organization-select/src/i18n/de/translation.json
+++ b/packages/organization-select/src/i18n/de/translation.json
@@ -1,7 +1,6 @@
 {
   "select-organization": {
     "placeholder": "Bitte wählen Sie ein Institut aus",
-    "loading": "Wird geladen...",
-    "load-error": "Fehler beim Laden der Organisation"
+    "loading": "Wird geladen..."
   }
 }
diff --git a/packages/organization-select/src/i18n/en/translation.json b/packages/organization-select/src/i18n/en/translation.json
index 75e626d77190b94982f148f69203b43e5f6788bb..ff54432a4ec79b0d3232c3c9a2ab45348cc544f0 100644
--- a/packages/organization-select/src/i18n/en/translation.json
+++ b/packages/organization-select/src/i18n/en/translation.json
@@ -1,7 +1,6 @@
 {
   "select-organization": {
     "placeholder": "Please select an organization",
-    "loading": "Loading...",
-    "load-error": "Error loading the organization"
+    "loading": "Loading..."
   }
 }
diff --git a/packages/organization-select/src/organization-select.js b/packages/organization-select/src/organization-select.js
index 578fb010fe32216d2bb8d3da1d99a034bbe52c63..d96c793701f8dad95ce2f355485c9d20c341ce32 100644
--- a/packages/organization-select/src/organization-select.js
+++ b/packages/organization-select/src/organization-select.js
@@ -1,7 +1,7 @@
 import $ from 'jquery';
 import select2 from 'select2';
 import select2CSSPath from 'select2/dist/css/select2.min.css';
-import {i18n} from './i18n.js';
+import {createInstance} from './i18n.js';
 import {css, html} from 'lit-element';
 import * as commonUtils from '@dbp-toolkit/common/utils';
 import * as commonStyles from '@dbp-toolkit/common/styles';
@@ -16,7 +16,8 @@ export class OrganizationSelect extends AdapterLitElement {
     constructor() {
         super();
         this.auth = {};
-        this.lang = i18n.language;
+        this._i18n = createInstance();
+        this.lang = this._i18n.language;
         this.entryPointUrl = '';
         this.jsonld = null;
         this.organizations = [];
@@ -93,6 +94,7 @@ export class OrganizationSelect extends AdapterLitElement {
     }
 
     async updateSelect2() {
+        const i18n = this._i18n;
         await this.updateComplete;
 
         const $select = this.$('#' + this.selectId);
@@ -181,7 +183,7 @@ export class OrganizationSelect extends AdapterLitElement {
         changedProperties.forEach((oldValue, propName) => {
             switch (propName) {
                 case "lang":
-                    i18n.changeLanguage(this.lang);
+                    this._i18n.changeLanguage(this.lang);
                     this.updateSelect2();
                     break;
                 case "value": {
diff --git a/packages/person-profile/i18next-scanner.config.js b/packages/person-profile/i18next-scanner.config.js
index 8c277798414be902846c6eb4f0e95a19750cda39..aeb8fdb6532e6c951401ba91424e2a256353d391 100644
--- a/packages/person-profile/i18next-scanner.config.js
+++ b/packages/person-profile/i18next-scanner.config.js
@@ -6,6 +6,7 @@ module.exports = {
     options: {
         debug: false,
         removeUnusedKeys: true,
+        func: {list: ['i18n.t', '_i18n.t']},
         lngs: ['en','de'],
         resource: {
             loadPath: 'src/i18n/{{lng}}/{{ns}}.json',
diff --git a/packages/person-profile/src/dbp-person-profile-demo.js b/packages/person-profile/src/dbp-person-profile-demo.js
index 25269ea1ae3cc082971921c2fb77da253935a5b7..dbce0a584baf5118edc368e140138b18ba918741 100644
--- a/packages/person-profile/src/dbp-person-profile-demo.js
+++ b/packages/person-profile/src/dbp-person-profile-demo.js
@@ -1,5 +1,5 @@
 import {AuthKeycloak, LoginButton} from '@dbp-toolkit/auth';
-import {i18n} from './i18n.js';
+import {createInstance} from './i18n.js';
 import {css, html} from 'lit-element';
 import {ScopedElementsMixin} from '@open-wc/scoped-elements';
 import DBPLitElement from '@dbp-toolkit/common/dbp-lit-element';
@@ -12,7 +12,8 @@ import {PersonSelect} from '@dbp-toolkit/person-select';
 export class PersonProfileDemo extends ScopedElementsMixin(DBPLitElement) {
     constructor() {
         super();
-        this.lang = 'de';
+        this._i18n = createInstance();
+        this.lang = this._i18n.language;
         this.entryPointUrl = '';
         this.person = '';
         this.selectedPerson = '';
@@ -42,6 +43,10 @@ export class PersonProfileDemo extends ScopedElementsMixin(DBPLitElement) {
     }
 
     update(changedProperties) {
+        if (changedProperties.has("lang")) {
+            this._i18n.changeLanguage(this.lang);
+        }
+
         changedProperties.forEach((oldValue, propName) => {
             switch (propName) {
                 case 'auth':
@@ -61,7 +66,6 @@ export class PersonProfileDemo extends ScopedElementsMixin(DBPLitElement) {
 
     connectedCallback() {
         super.connectedCallback();
-        i18n.changeLanguage(this.lang);
         const that = this;
 
         this.updateComplete.then(()=>{
diff --git a/packages/person-profile/src/i18n.js b/packages/person-profile/src/i18n.js
index 498d9f037b0a5ca481ec8de5df24640900285808..975c1993e2a567940c74f8d957a6b2a018125548 100644
--- a/packages/person-profile/src/i18n.js
+++ b/packages/person-profile/src/i18n.js
@@ -1,6 +1,8 @@
-import {createInstance} 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';
 
-export const i18n = createInstance({en: en, de: de}, 'de', 'en');
\ No newline at end of file
+export function createInstance() {
+    return _createInstance({en: en, de: de}, 'de', 'en');
+}
\ No newline at end of file
diff --git a/packages/person-profile/src/person-profile.js b/packages/person-profile/src/person-profile.js
index c8118ba5b4e7647664e2b81b7f8fc9c2ddc82356..4ac5576baa5649106d56ed507628894474261ea1 100644
--- a/packages/person-profile/src/person-profile.js
+++ b/packages/person-profile/src/person-profile.js
@@ -1,7 +1,7 @@
 
 import JSONLD from '@dbp-toolkit/common/jsonld';
 import {css, html} from 'lit-element';
-import {i18n} from './i18n.js';
+import {createInstance} from './i18n.js';
 import DBPLitElement from '@dbp-toolkit/common/dbp-lit-element';
 import * as commonStyles from '@dbp-toolkit/common/styles';
 
@@ -10,7 +10,8 @@ export class PersonProfile extends DBPLitElement {
 
     constructor() {
         super();
-        this.lang = 'de';
+        this._i18n = createInstance();
+        this.lang = this._i18n.language;
         this.entryPointUrl = '';
         this.jsonld = null;
         this.value = '';
@@ -29,18 +30,11 @@ export class PersonProfile extends DBPLitElement {
         };
     }
 
-    connectedCallback() {
-        super.connectedCallback();
-
-        this.updateComplete.then(()=>{
-        });
-    }
-
     update(changedProperties) {
         changedProperties.forEach((oldValue, propName) => {
             switch (propName) {
                 case "lang":
-                    i18n.changeLanguage(this.lang);
+                    this._i18n.changeLanguage(this.lang);
                     break;
                 case "entryPointUrl": {
                     const that = this;
@@ -83,6 +77,7 @@ export class PersonProfile extends DBPLitElement {
     }
 
     render() {
+        const i18n = this._i18n;
         let role = i18n.t('person-profile.unknown');
         if (this.person !== null && this.person.roles !== undefined) {
             // roles are only defined for self-disclosure
diff --git a/packages/person-select/i18next-scanner.config.js b/packages/person-select/i18next-scanner.config.js
index 8c277798414be902846c6eb4f0e95a19750cda39..aeb8fdb6532e6c951401ba91424e2a256353d391 100644
--- a/packages/person-select/i18next-scanner.config.js
+++ b/packages/person-select/i18next-scanner.config.js
@@ -6,6 +6,7 @@ module.exports = {
     options: {
         debug: false,
         removeUnusedKeys: true,
+        func: {list: ['i18n.t', '_i18n.t']},
         lngs: ['en','de'],
         resource: {
             loadPath: 'src/i18n/{{lng}}/{{ns}}.json',
diff --git a/packages/person-select/src/dbp-person-select-demo.js b/packages/person-select/src/dbp-person-select-demo.js
index affc7c0a2317a49fda553cf524dca9ec9b500059..9bc90931d9cea7323bc50a5cad05f3c543e2cd1f 100644
--- a/packages/person-select/src/dbp-person-select-demo.js
+++ b/packages/person-select/src/dbp-person-select-demo.js
@@ -1,4 +1,4 @@
-import {i18n} from './i18n.js';
+import {createInstance} from './i18n.js';
 import {css, html} from 'lit-element';
 import {ScopedElementsMixin} from '@open-wc/scoped-elements';
 import {PersonSelect} from './person-select.js';
@@ -10,7 +10,8 @@ import DBPLitElement from "@dbp-toolkit/common/dbp-lit-element";
 export class PersonSelectDemo extends ScopedElementsMixin(DBPLitElement) {
     constructor() {
         super();
-        this.lang = 'de';
+        this._i18n = createInstance();
+        this.lang = this._i18n.language;
         this.entryPointUrl = '';
         this.noAuth = false;
     }
@@ -32,14 +33,6 @@ export class PersonSelectDemo extends ScopedElementsMixin(DBPLitElement) {
         };
     }
 
-    connectedCallback() {
-        super.connectedCallback();
-        i18n.changeLanguage(this.lang);
-
-        this.updateComplete.then(()=>{
-        });
-    }
-
     static get styles() {
         // language=css
         return [
@@ -52,6 +45,13 @@ export class PersonSelectDemo extends ScopedElementsMixin(DBPLitElement) {
         ];
     }
 
+    update(changedProperties) {
+        if (changedProperties.has("lang")) {
+            this._i18n.changeLanguage(this.lang);
+        }
+        super.update(changedProperties);
+    }
+
     getAuthComponentHtml() {
         return this.noAuth ? html`<dbp-login-button subscribe="auth" lang="${this.lang}" show-image></dbp-login-button>` : html`
             <div class="container">
diff --git a/packages/person-select/src/i18n.js b/packages/person-select/src/i18n.js
index 498d9f037b0a5ca481ec8de5df24640900285808..975c1993e2a567940c74f8d957a6b2a018125548 100644
--- a/packages/person-select/src/i18n.js
+++ b/packages/person-select/src/i18n.js
@@ -1,6 +1,8 @@
-import {createInstance} 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';
 
-export const i18n = createInstance({en: en, de: de}, 'de', 'en');
\ No newline at end of file
+export function createInstance() {
+    return _createInstance({en: en, de: de}, 'de', 'en');
+}
\ No newline at end of file
diff --git a/packages/person-select/src/i18n/de/translation.json b/packages/person-select/src/i18n/de/translation.json
index b5a39b9b0233a12199919e4ada0143951c842bad..4528f9010fd698f94f26739d01e2d1eb9a6d6b41 100644
--- a/packages/person-select/src/i18n/de/translation.json
+++ b/packages/person-select/src/i18n/de/translation.json
@@ -1,7 +1,6 @@
 {
   "person-select": {
     "placeholder": "Bitte wählen Sie eine Person aus",
-    "error-summary": "Ein Fehler ist aufgetreten",
     "login-required": "Anmeldung erforderlich"
   }
 }
diff --git a/packages/person-select/src/i18n/en/translation.json b/packages/person-select/src/i18n/en/translation.json
index a89cdb1a16632a3b5255230cb5b33d93d2a28a4c..9bcb748c767c334de390e3c032250dd01f91c088 100644
--- a/packages/person-select/src/i18n/en/translation.json
+++ b/packages/person-select/src/i18n/en/translation.json
@@ -1,7 +1,6 @@
 {
   "person-select": {
     "placeholder": "Please select a person",
-    "error-summary": "An error occurred",
     "login-required": "Login required"
   }
 }
diff --git a/packages/person-select/src/person-select.js b/packages/person-select/src/person-select.js
index 67c7466650d0c0ce0cda1ce440c9454de18d6a52..68d96a1e9c14d1078e6a746e3a6aab4a639c56f7 100644
--- a/packages/person-select/src/person-select.js
+++ b/packages/person-select/src/person-select.js
@@ -6,7 +6,7 @@ import select2LangEn from './i18n/en/select2';
 import JSONLD from '@dbp-toolkit/common/jsonld';
 import {css, html} from 'lit-element';
 import {ScopedElementsMixin} from '@open-wc/scoped-elements';
-import {i18n} from './i18n.js';
+import {createInstance} from './i18n.js';
 import {Icon} from '@dbp-toolkit/common';
 import * as commonUtils from '@dbp-toolkit/common/utils';
 import * as commonStyles from '@dbp-toolkit/common/styles';
@@ -29,7 +29,8 @@ export class PersonSelect extends ScopedElementsMixin(AdapterLitElement) {
         super();
         Object.assign(PersonSelect.prototype, errorUtils.errorMixin);
         this.auth = {};
-        this.lang = 'de';
+        this._i18n = createInstance();
+        this.lang = this._i18n.language;
         this.entryPointUrl = '';
         this.jsonld = null;
         this.$select = null;
@@ -129,6 +130,7 @@ export class PersonSelect extends ScopedElementsMixin(AdapterLitElement) {
      * @param ignorePreset
      */
     initSelect2(ignorePreset = false) {
+        const i18n = this._i18n;
         const that = this;
         const $this = $(this);
 
@@ -155,7 +157,7 @@ export class PersonSelect extends ScopedElementsMixin(AdapterLitElement) {
             width: '100%',
             language: this.lang === "de" ? select2LangDe() : select2LangEn(),
             minimumInputLength: 2,
-            placeholder: i18n.t(this.authenticated() ? 'person-select.placeholder' : 'person-select.login-required'),
+            placeholder: this.authenticated() ? i18n.t('person-select.placeholder') : i18n.t('person-select.login-required'),
             dropdownParent: this.$('#person-select-dropdown'),
             ajax: {
                 delay: 500,
@@ -277,7 +279,7 @@ export class PersonSelect extends ScopedElementsMixin(AdapterLitElement) {
         changedProperties.forEach((oldValue, propName) => {
             switch (propName) {
                 case "lang":
-                    i18n.changeLanguage(this.lang);
+                    this._i18n.changeLanguage(this.lang);
 
                     if (this.select2IsInitialized()) {
                         // no other way to set an other language at runtime did work
@@ -361,6 +363,7 @@ export class PersonSelect extends ScopedElementsMixin(AdapterLitElement) {
     }
 
     render() {
+        const i18n = this._i18n;
         const select2CSS = commonUtils.getAssetURL(select2CSSPath);
         return html`
             <link rel="stylesheet" href="${select2CSS}">
diff --git a/packages/provider/i18next-scanner.config.js b/packages/provider/i18next-scanner.config.js
index 8c277798414be902846c6eb4f0e95a19750cda39..aeb8fdb6532e6c951401ba91424e2a256353d391 100644
--- a/packages/provider/i18next-scanner.config.js
+++ b/packages/provider/i18next-scanner.config.js
@@ -6,6 +6,7 @@ module.exports = {
     options: {
         debug: false,
         removeUnusedKeys: true,
+        func: {list: ['i18n.t', '_i18n.t']},
         lngs: ['en','de'],
         resource: {
             loadPath: 'src/i18n/{{lng}}/{{ns}}.json',
diff --git a/packages/provider/src/dbp-provider-demo.js b/packages/provider/src/dbp-provider-demo.js
index c47ca1852cf503078b12f2bc454dd5ffcb8a53f8..634c11fc7e0e86bb2d883e28f04b6638128ce0bb 100644
--- a/packages/provider/src/dbp-provider-demo.js
+++ b/packages/provider/src/dbp-provider-demo.js
@@ -1,4 +1,4 @@
-import {i18n} from './i18n.js';
+import {createInstance} from './i18n.js';
 import {css, html} from 'lit-element';
 import {ScopedElementsMixin} from '@open-wc/scoped-elements';
 import {AuthKeycloak, LoginButton} from '@dbp-toolkit/auth';
@@ -14,7 +14,8 @@ class ProviderDemo extends ScopedElementsMixin(DBPLitElement) {
 
     constructor() {
         super();
-        this.lang = 'de';
+        this._i18n = createInstance();
+        this.lang = this._i18n.language;
     }
 
     static get scopedElements() {
@@ -35,18 +36,12 @@ class ProviderDemo extends ScopedElementsMixin(DBPLitElement) {
         };
     }
 
-    connectedCallback() {
-        super.connectedCallback();
-        i18n.changeLanguage(this.lang);
-
-    }
-
     attributeChangedCallback(name, oldValue, newValue) {
         console.debug('ProviderDemo (' + this.id + ') attributeChangesCallback( ' + name + ', ' + oldValue + ', ' + newValue + ')');
         switch(name) {
             case 'lang':
                 this.lang = newValue;
-                i18n.changeLanguage(this.lang);
+                this._i18n.changeLanguage(this.lang);
                 break;
             default:
                 super.attributeChangedCallback(name, oldValue, newValue);
@@ -71,6 +66,7 @@ class ProviderDemo extends ScopedElementsMixin(DBPLitElement) {
     }
 
     render() {
+        const i18n = this._i18n;
         return html`
             <section class="section">
                 <p>${i18n.t('demo.provider_description', {id: "root", description: "is the top most in hierarchy"})}</p>
@@ -142,7 +138,8 @@ class DemoConsumer extends DBPLitElement {
     constructor() {
         super();
 
-        this.lang = 'de';
+        this._i18n = createInstance();
+        this.lang = this._i18n.language;
         this.entryPointUrl = '';
         // default values
         this.foo = 100;
@@ -157,7 +154,6 @@ class DemoConsumer extends DBPLitElement {
 
     connectedCallback() {
         super.connectedCallback();
-        i18n.changeLanguage(this.lang);
         console.debug('DemoConsumer(' + this.id + ') connectedCallback()');
         this.render();
     }
@@ -184,7 +180,7 @@ class DemoConsumer extends DBPLitElement {
         switch(name) {
             case 'lang':
                 this.lang = newValue;
-                i18n.changeLanguage(this.lang);
+                this._i18n.changeLanguage(this.lang);
                 break;
             case 'foo':
                 this.foo = parseInt(newValue);
@@ -209,6 +205,7 @@ class DemoConsumer extends DBPLitElement {
     }
 
     render() {
+        const i18n = this._i18n;
         if (! this.connected) {
             return `not connected!`;
         }
diff --git a/packages/provider/src/i18n.js b/packages/provider/src/i18n.js
index 498d9f037b0a5ca481ec8de5df24640900285808..975c1993e2a567940c74f8d957a6b2a018125548 100644
--- a/packages/provider/src/i18n.js
+++ b/packages/provider/src/i18n.js
@@ -1,6 +1,8 @@
-import {createInstance} 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';
 
-export const i18n = createInstance({en: en, de: de}, 'de', 'en');
\ No newline at end of file
+export function createInstance() {
+    return _createInstance({en: en, de: de}, 'de', 'en');
+}
\ No newline at end of file
diff --git a/packages/provider/src/i18n/de/translation.json b/packages/provider/src/i18n/de/translation.json
index 981c4287b852d1888e6e42792423d9799ae9fc83..650f83a0c7b12b219550dcf82b663ba8ebb5954a 100644
--- a/packages/provider/src/i18n/de/translation.json
+++ b/packages/provider/src/i18n/de/translation.json
@@ -1,7 +1,4 @@
 {
-  "de": "Deutsch",
-  "en": "Englisch",
-
   "demo": {
     "provider": "Anbieter",
     "consumer": "Verbraucher",
@@ -13,4 +10,4 @@
     "price": "Preis",
     "sum": "Summe"
   }
-}
\ No newline at end of file
+}
diff --git a/packages/provider/src/i18n/en/translation.json b/packages/provider/src/i18n/en/translation.json
index bc342774e83864c5cd6c4e4fda3c2f41c33847fa..e511b79f6a21db9fe5ea29cf912c4308604ba5ce 100644
--- a/packages/provider/src/i18n/en/translation.json
+++ b/packages/provider/src/i18n/en/translation.json
@@ -1,7 +1,4 @@
 {
-  "de": "German",
-  "en": "English",
-
   "demo": {
     "provider": "Provider",
     "consumer": "Consumer",
@@ -13,4 +10,4 @@
     "price": "Price",
     "sum": "sum"
   }
-}
\ No newline at end of file
+}
diff --git a/packages/qr-code-scanner/i18next-scanner.config.js b/packages/qr-code-scanner/i18next-scanner.config.js
index 8c277798414be902846c6eb4f0e95a19750cda39..aeb8fdb6532e6c951401ba91424e2a256353d391 100644
--- a/packages/qr-code-scanner/i18next-scanner.config.js
+++ b/packages/qr-code-scanner/i18next-scanner.config.js
@@ -6,6 +6,7 @@ module.exports = {
     options: {
         debug: false,
         removeUnusedKeys: true,
+        func: {list: ['i18n.t', '_i18n.t']},
         lngs: ['en','de'],
         resource: {
             loadPath: 'src/i18n/{{lng}}/{{ns}}.json',
diff --git a/packages/qr-code-scanner/src/dbp-qr-code-scanner-demo.js b/packages/qr-code-scanner/src/dbp-qr-code-scanner-demo.js
index 4b8bd63a9cd19c061033a41eda7c5e5246159706..2b78a7406b6baed80eb5ba6643882ad86abb6534 100644
--- a/packages/qr-code-scanner/src/dbp-qr-code-scanner-demo.js
+++ b/packages/qr-code-scanner/src/dbp-qr-code-scanner-demo.js
@@ -1,4 +1,4 @@
-import {i18n} from './i18n';
+import {createInstance} from './i18n';
 import {css, html, LitElement} from 'lit-element';
 import {ScopedElementsMixin} from '@open-wc/scoped-elements';
 import * as commonUtils from '@dbp-toolkit/common/utils';
@@ -8,7 +8,8 @@ import {QrCodeScanner} from './qr-code-scanner.js';
 export class QrCodeScannerDemo extends ScopedElementsMixin(LitElement) {
     constructor() {
         super();
-        this.lang = 'de';
+        this._i18n = createInstance();
+        this.lang = this._i18n.language;
     }
 
     static get scopedElements() {
@@ -23,12 +24,11 @@ export class QrCodeScannerDemo extends ScopedElementsMixin(LitElement) {
         };
     }
 
-    connectedCallback() {
-        super.connectedCallback();
-        i18n.changeLanguage(this.lang);
-
-        this.updateComplete.then(()=>{
-        });
+    update(changedProperties) {
+        if (changedProperties.has("lang")) {
+            this._i18n.changeLanguage(this.lang);
+        }
+        super.update(changedProperties);
     }
 
     static get styles() {
diff --git a/packages/qr-code-scanner/src/i18n.js b/packages/qr-code-scanner/src/i18n.js
index 498d9f037b0a5ca481ec8de5df24640900285808..975c1993e2a567940c74f8d957a6b2a018125548 100644
--- a/packages/qr-code-scanner/src/i18n.js
+++ b/packages/qr-code-scanner/src/i18n.js
@@ -1,6 +1,8 @@
-import {createInstance} 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';
 
-export const i18n = createInstance({en: en, de: de}, 'de', 'en');
\ No newline at end of file
+export function createInstance() {
+    return _createInstance({en: en, de: de}, 'de', 'en');
+}
\ No newline at end of file
diff --git a/packages/qr-code-scanner/src/i18n/de/translation.json b/packages/qr-code-scanner/src/i18n/de/translation.json
index da2f50d51d479a5681cf064b3728131613f33301..652c7eec581270a762169ee1e7115c00b779e48e 100644
--- a/packages/qr-code-scanner/src/i18n/de/translation.json
+++ b/packages/qr-code-scanner/src/i18n/de/translation.json
@@ -1,7 +1,6 @@
 {
   "no-camera-access": "Zugriff auf Kamera nicht möglich.",
   "check-access": "Bitte stellen Sie sicher, dass eine Webcam oder Kamera aktiviert ist und überprüfen Sie ob Ihr Browser die notwendigen Berechtigungen besitzt.",
-  "finished-scan": "Scannen abgeschlossen.",
   "loading-video": "Video laden ...",
   "no-qr-detected": "Kein QR-Code erkannt.",
   "no-support": "Ihr Browser unterstützt keine Videoaufnahmen.",
diff --git a/packages/qr-code-scanner/src/i18n/en/translation.json b/packages/qr-code-scanner/src/i18n/en/translation.json
index 59ef87c97203b8b1506cf3c56cdae413a319c3bb..cb653c89b4a8f597518943fa7142720cb52695a5 100644
--- a/packages/qr-code-scanner/src/i18n/en/translation.json
+++ b/packages/qr-code-scanner/src/i18n/en/translation.json
@@ -1,7 +1,6 @@
 {
   "no-camera-access": "Unable to access video stream.",
   "check-access": "Please make sure that a webcam or camera is activated and check whether your browser has the necessary authorizations.",
-  "finished-scan": "Finished scanning.",
   "loading-video": "⌛ Loading video...",
   "no-qr-detected": "No QR code detected.",
   "no-support": "Your browser does not support video recording.",
diff --git a/packages/qr-code-scanner/src/qr-code-scanner.js b/packages/qr-code-scanner/src/qr-code-scanner.js
index 59bda21bbe7d608217691e8b404110f4eb36a8bd..4b07ef0123111d86b55c814547fcb31836bb59bc 100644
--- a/packages/qr-code-scanner/src/qr-code-scanner.js
+++ b/packages/qr-code-scanner/src/qr-code-scanner.js
@@ -1,4 +1,4 @@
-import {i18n} from './i18n';
+import {createInstance} from './i18n';
 import {css, html, unsafeCSS} from 'lit-element';
 import DBPLitElement from '@dbp-toolkit/common/dbp-lit-element';
 import * as commonStyles from '@dbp-toolkit/common/styles';
@@ -33,9 +33,10 @@ function getPrimaryDevice(devices) {
  *
  * Moreimportant devices first.
  *
+ * @param i18n
  * @returns {Map<string,string>} the map of devices
  */
-async function getVideoDevices() {
+async function getVideoDevices(i18n) {
     let devices_map = new Map();
     if (navigator.mediaDevices
         && navigator.mediaDevices.enumerateDevices
@@ -135,7 +136,8 @@ class QRScanner {
 export class QrCodeScanner extends ScopedElementsMixin(DBPLitElement) {
     constructor() {
         super();
-        this.lang = 'de';
+        this._i18n = createInstance();
+        this.lang = this._i18n.language;
 
         this._askPermission = false;
         this._loading = false;
@@ -181,9 +183,8 @@ export class QrCodeScanner extends ScopedElementsMixin(DBPLitElement) {
 
     async connectedCallback() {
         super.connectedCallback();
-        i18n.changeLanguage(this.lang);
 
-        let devices = await getVideoDevices();
+        let devices = await getVideoDevices(this._i18n);
         this._activeCamera = getPrimaryDevice(devices) || '';
         this._devices = devices;
 
@@ -209,7 +210,7 @@ export class QrCodeScanner extends ScopedElementsMixin(DBPLitElement) {
         changedProperties.forEach((oldValue, propName) => {
             switch (propName) {
                 case "lang":
-                    i18n.changeLanguage(this.lang);
+                    this._i18n.changeLanguage(this.lang);
                     break;
             }
         });
@@ -232,6 +233,7 @@ export class QrCodeScanner extends ScopedElementsMixin(DBPLitElement) {
     }
 
     async _startScanning() {
+        const i18n = this._i18n;
         console.assert(this._lock.isLocked());
         await this.updateComplete;
 
@@ -488,6 +490,7 @@ export class QrCodeScanner extends ScopedElementsMixin(DBPLitElement) {
     }
 
     render() {
+        const i18n = this._i18n;
         let hasDevices = this._devices.size > 0;
         let showCanvas = this._videoRunning && !this._askPermission && !this._loading;
         let noSupportString = checkIosMobileSupport(this._devices) ? i18n.t('no-ios-support') : i18n.t('no-support');
diff --git a/packages/typescript-example/src/i18n.ts b/packages/typescript-example/src/i18n.ts
index 498d9f037b0a5ca481ec8de5df24640900285808..975c1993e2a567940c74f8d957a6b2a018125548 100644
--- a/packages/typescript-example/src/i18n.ts
+++ b/packages/typescript-example/src/i18n.ts
@@ -1,6 +1,8 @@
-import {createInstance} 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';
 
-export const i18n = createInstance({en: en, de: de}, 'de', 'en');
\ No newline at end of file
+export function createInstance() {
+    return _createInstance({en: en, de: de}, 'de', 'en');
+}
\ No newline at end of file
diff --git a/packages/typescript-example/src/typescript-example.ts b/packages/typescript-example/src/typescript-example.ts
index 60fe3c8c7fc3fed194fa1b63b65d11d1e4c48820..a7c6503ad91cc8541706dcd6470243f269517819 100644
--- a/packages/typescript-example/src/typescript-example.ts
+++ b/packages/typescript-example/src/typescript-example.ts
@@ -1,5 +1,5 @@
-import {html,LitElement,property} from 'lit-element';
-import {i18n} from './i18n';
+import {html,LitElement} from 'lit-element';
+import {createInstance} from './i18n';
 
 export class TypeScriptExample extends LitElement {
 
@@ -8,20 +8,20 @@ export class TypeScriptExample extends LitElement {
     constructor() {
         super();
 
-        this._i18n = i18n.cloneInstance();
+        this._i18n = createInstance();
+        this.lang = this._i18n.language;
     }
 
-    @property({type: String})
-    lang = '';
+    static get properties() {
+        return {
+          lang: {type: String}
+        };
+    }
 
     update(changedProperties) {
-        changedProperties.forEach((oldValue, propName) => {
-            switch (propName) {
-                case "lang":
-                    this._i18n.changeLanguage(this.lang);
-                    break;
-            }
-        });
+        if (changedProperties.has("lang")) {
+            this._i18n.changeLanguage(this.lang);
+        }
         super.update(changedProperties);
     }