diff --git a/aleksis/core/assets/app.js b/aleksis/core/assets/app.js
index daf30dfdb6323cc53ec582702f0964b307014cff..31555d16d8de40cbe514e484c8b19374830d110f 100644
--- a/aleksis/core/assets/app.js
+++ b/aleksis/core/assets/app.js
@@ -7,6 +7,25 @@ import ApolloClient from 'apollo-boost'
 import VueApollo from 'vue-apollo'
 
 import "./css/global.scss"
+import VueI18n from 'vue-i18n'
+
+import messages from "./messages.json"
+
+Vue.use(VueI18n)
+
+const i18n = new VueI18n({
+    locale: JSON.parse(document.getElementById("current-language").textContent),
+    fallbackLocale: "en",
+    availableLocales: JSON.parse(document.getElementById("language-info-list").textContent),
+    messages
+});
+
+// Using this function, apps can register their locale files
+i18n.registerLocale = function (messages) {
+    for (let locale in messages) {
+        i18n.mergeLocaleMessage(locale, messages[locale]);
+    }
+};
 
 Vue.use(Vuetify)
 Vue.use(VueRouter)
@@ -96,8 +115,10 @@ const app = new Vue({
         "notification-list": NotificationList,
         "sidenav-search": SidenavSearch,
     },
-    router
+    router,
+    i18n
 })
 
 window.app = app;
 window.router = router;
+window.i18n = i18n;
diff --git a/aleksis/core/assets/components/CacheNotification.vue b/aleksis/core/assets/components/CacheNotification.vue
index 4491615e6c7b4f3b42187c9a4ba9c0b66bbff4fd..d636a056cab92f3464a602d9a02af923197c2a35 100644
--- a/aleksis/core/assets/components/CacheNotification.vue
+++ b/aleksis/core/assets/components/CacheNotification.vue
@@ -1,6 +1,6 @@
 <template>
   <message-box :value="cache" type="warning">
-    {{ this.$root.django.gettext('This page may contain outdated information since there is no internet connection.') }}
+    {{ $t('alerts.page_cached') }}
   </message-box>
 </template>
 
diff --git a/aleksis/core/assets/components/notifications/NotificationItem.vue b/aleksis/core/assets/components/notifications/NotificationItem.vue
index 0388d075815d86dd02cfc8e7c50abb1eee9a1335..2035cbd69d664c59d63ab95cd39571b27842d74e 100644
--- a/aleksis/core/assets/components/notifications/NotificationItem.vue
+++ b/aleksis/core/assets/components/notifications/NotificationItem.vue
@@ -22,7 +22,7 @@
 
         <v-list-item-action v-if="notification.link">
           <v-btn text :href="notification.link">
-            {{ $root.django.gettext('More information →') }}
+            {{ $t('notifications.more_information') }} →
           </v-btn>
         </v-list-item-action>
 
diff --git a/aleksis/core/assets/messages.json b/aleksis/core/assets/messages.json
new file mode 100644
index 0000000000000000000000000000000000000000..34c7dab8773a125d28657391f9e75d33d271e2b3
--- /dev/null
+++ b/aleksis/core/assets/messages.json
@@ -0,0 +1,21 @@
+{
+  "en": {
+    "notifications":  {
+      "more_information": "More information",
+      "no_notifications": "No notifications available yet."
+    },
+    "alerts": {
+      "page_cached": "This page may contain outdated information since there is no internet connection."
+    }
+  },
+  "de": {
+    "notifications": {
+      "more_information": "Mehr Informationen",
+      "no_notifications": "Keine Benachrichtigungen verfügbar."
+    },
+    "alerts": {
+      "page_cached": "Diese Seite enthält vielleicht veraltete Informationen, da es keine Internetverbindung gibt."
+    }
+  }
+}
+
diff --git a/aleksis/core/settings.py b/aleksis/core/settings.py
index 60f93440760af81bf2f2c5bd46613e366cb52ff5..0440d3424e77315fba6329b99ec91f7dd5e86d07 100644
--- a/aleksis/core/settings.py
+++ b/aleksis/core/settings.py
@@ -579,6 +579,7 @@ YARN_INSTALLED_APPS = [
     "webpack@^5.73.0",
     "webpack-bundle-tracker@^1.6.0",
     "webpack-cli@^4.10.0",
+    "vue-i18n@8",
 ]
 
 merge_app_settings("YARN_INSTALLED_APPS", YARN_INSTALLED_APPS, True)