diff --git a/aleksis/core/assets/components/BrandLogo.vue b/aleksis/core/assets/components/BrandLogo.vue
index fa7fce53bb190360615599b5ba0604d9535ef721..8d32dd0c22382b1047df9150a8e3d0c247197a4f 100644
--- a/aleksis/core/assets/components/BrandLogo.vue
+++ b/aleksis/core/assets/components/BrandLogo.vue
@@ -1,7 +1,7 @@
 <template>
   <img
     :src="sitePreferences.themeLogo.url"
-    :alt="sitePreferences.generalTitle + ' – Logo'"
+    :alt="sitePreferences.generalTitle + ' – ' + $t('base.logo')"
     class="fullsize"
   />
 </template>
diff --git a/aleksis/core/assets/components/Error404.vue b/aleksis/core/assets/components/Error404.vue
index 79160f5d4a8abb5bc359c47e11907339bfa7eeee..017f53174179ce346ab40956a8c05d2ff1ea17b4 100644
--- a/aleksis/core/assets/components/Error404.vue
+++ b/aleksis/core/assets/components/Error404.vue
@@ -5,9 +5,9 @@
   >
     <h1 class="text-h2">{{ $t("network_errors.error_404") }}</h1>
     <div>{{ $t("network_errors.page_not_found") }}</div>
-    <v-btn color="secondary" :to="{ name: 'dashboard' }">{{
-      $t("network_errors.take_me_back")
-    }}</v-btn>
+    <v-btn color="secondary" :to="{ name: 'dashboard' }">
+      {{ $t("network_errors.take_me_back") }}
+    </v-btn>
   </div>
 </template>
 
diff --git a/aleksis/core/assets/components/about/AboutAleksis.vue b/aleksis/core/assets/components/about/AboutAleksis.vue
index 2f39581d430a06b57bec0a9367983023ddbb9f95..74ba7a0152dba8059039c3681868fa3e69dde239 100644
--- a/aleksis/core/assets/components/about/AboutAleksis.vue
+++ b/aleksis/core/assets/components/about/AboutAleksis.vue
@@ -13,12 +13,12 @@
         </v-card-text>
         <v-spacer></v-spacer>
         <v-card-actions>
-          <v-btn text color="primary" href="https://aleksis.org/">{{
-            $t("about.website_of_aleksis")
-          }}</v-btn>
-          <v-btn text color="primary" href="https://edugit.org/AlekSIS/">{{
-            $t("about.source_code")
-          }}</v-btn>
+          <v-btn text color="primary" href="https://aleksis.org/">
+            {{ $t("about.website_of_aleksis") }}
+          </v-btn>
+          <v-btn text color="primary" href="https://edugit.org/AlekSIS/">
+            {{ $t("about.source_code") }}
+          </v-btn>
         </v-card-actions>
       </v-card>
     </v-col>
@@ -30,19 +30,19 @@
             {{ $t("about.licence_information_1") }}
           </p>
           <p>
-            <v-chip color="green" text-color="white" small>{{
-              $t("about.free_open_source_licence")
-            }}</v-chip>
-            <v-chip color="orange" text-color="white" small>{{
-              $t("about.other_licence")
-            }}</v-chip>
+            <v-chip color="green" text-color="white" small>
+              {{ $t("about.free_open_source_licence") }}
+            </v-chip>
+            <v-chip color="orange" text-color="white" small>
+              {{ $t("about.other_licence") }}
+            </v-chip>
           </p>
         </v-card-text>
         <v-spacer></v-spacer>
         <v-card-actions>
-          <v-btn text color="primary" href="https://eupl.eu">{{
-            $t("about.full_licence_text")
-          }}</v-btn>
+          <v-btn text color="primary" href="https://eupl.eu">
+            {{ $t("about.full_licence_text") }}
+          </v-btn>
           <v-btn
             text
             color="primary"
diff --git a/aleksis/core/assets/components/about/InstalledAppCard.vue b/aleksis/core/assets/components/about/InstalledAppCard.vue
index 796808abd127324caf48d71e5e79afcc24da8380..99f63dfd0af39e33a8da7f4e3289883baa16a580 100644
--- a/aleksis/core/assets/components/about/InstalledAppCard.vue
+++ b/aleksis/core/assets/components/about/InstalledAppCard.vue
@@ -13,9 +13,9 @@
         <v-row v-if="app.licence" class="mb-2">
           <v-col cols="6">
             {{ $t("about.licenced_under") }} <br />
-            <strong class="text-body-1 black--text">{{
-              app.licence.verboseName
-            }}</strong>
+            <strong class="text-body-1 black--text">
+              {{ app.licence.verboseName }}
+            </strong>
           </v-col>
           <v-col cols="6">
             {{ $t("about.licence_type") }} <br />
@@ -75,7 +75,7 @@
 
       <v-card-actions v-if="app.urls.length !== 0">
         <v-btn text color="primary" @click="reveal = true">
-          Show copyright
+          {{ $t("about.show_copyright") }}
         </v-btn>
         <v-btn
           v-for="url in app.urls"
@@ -98,9 +98,9 @@
               <v-col cols="12" v-if="app.copyrights.length !== 0">
                 <span v-for="(copyright, index) in app.copyrights" :key="index">
                   Copyright © {{ copyright.years }}
-                  <a :href="'mailto:' + copyright.email">{{
-                    copyright.name
-                  }}</a>
+                  <a :href="'mailto:' + copyright.email">
+                    {{ copyright.name }}
+                  </a>
                   <br />
                 </span>
               </v-col>
@@ -108,7 +108,9 @@
           </v-card-text>
           <v-spacer></v-spacer>
           <v-card-actions class="pt-0">
-            <v-btn text color="primary" @click="reveal = false"> Close </v-btn>
+            <v-btn text color="primary" @click="reveal = false">{{
+              $t("actions.close")
+            }}</v-btn>
           </v-card-actions>
         </v-card>
       </v-expand-transition>
diff --git a/aleksis/core/assets/components/generic/ListView.vue b/aleksis/core/assets/components/generic/ListView.vue
index 7a78a7643b2f08846f341677eb82074eda31013e..bc68b2dbf9f5a5dea29a792cab497ffe74931b3e 100644
--- a/aleksis/core/assets/components/generic/ListView.vue
+++ b/aleksis/core/assets/components/generic/ListView.vue
@@ -20,9 +20,7 @@ export default {
   components: {
     DetailView,
   },
-}
+};
 </script>
 
-<style scoped>
-
-</style>
+<style scoped></style>
diff --git a/aleksis/core/assets/components/person/AdditionalImage.vue b/aleksis/core/assets/components/person/AdditionalImage.vue
index 5ea3479bb42ebcac6211874c022454c7677b8968..f483705806bb5eb718ccf136a4773b4a5bac7130 100644
--- a/aleksis/core/assets/components/person/AdditionalImage.vue
+++ b/aleksis/core/assets/components/person/AdditionalImage.vue
@@ -27,7 +27,7 @@
     <v-list>
       <v-list-item>
         <v-list-item-icon>
-          <v-icon> mdi-image-off-outline </v-icon>
+          <v-icon>mdi-image-off-outline</v-icon>
         </v-list-item-icon>
 
         <v-list-item-content>
diff --git a/aleksis/core/assets/components/person/PersonActions.vue b/aleksis/core/assets/components/person/PersonActions.vue
index 2b0bc7bc6e55d985b6c66c3d7b9dbc92b13344b4..9e9518c9a67e6bc95ee2bd09258e6f80798c76f5 100644
--- a/aleksis/core/assets/components/person/PersonActions.vue
+++ b/aleksis/core/assets/components/person/PersonActions.vue
@@ -1,36 +1,36 @@
 <template>
   <ApolloQuery :query="require('./personActions.graphql')" :variables="{ id }">
     <template #default="{ result: { error, data, loading } }">
-      <v-skeleton-loader v-if="loading" type="actions"/>
+      <v-skeleton-loader v-if="loading" type="actions" />
       <template v-else-if="data && data.person && data.person.id">
         <v-btn
-            v-if="data.person.canEditPerson"
-            color="primary"
-            :to="{ name: 'core.editPerson', params: { id: data.person.id } }"
+          v-if="data.person.canEditPerson"
+          color="primary"
+          :to="{ name: 'core.editPerson', params: { id: data.person.id } }"
         >
           <v-icon left>$edit</v-icon>
           {{ $t("actions.edit") }}
         </v-btn>
         <v-btn
-            v-if="data.person.canChangePersonPreferences"
-            color="secondary"
-            outlined
-            text
-            :to="{
-              name: 'core.preferencesPersonByPk',
-              params: { pk: data.person.id },
-            }"
+          v-if="data.person.canChangePersonPreferences"
+          color="secondary"
+          outlined
+          text
+          :to="{
+            name: 'core.preferencesPersonByPk',
+            params: { pk: data.person.id },
+          }"
         >
           <v-icon left>$preferences</v-icon>
           {{ $t("preferences.person.change_preferences") }}
         </v-btn>
 
         <v-menu
-            v-if="
-              data.person.canImpersonatePerson ||
-              data.person.canInvitePerson ||
-              data.person.canDeletePerson
-            "
+          v-if="
+            data.person.canImpersonatePerson ||
+            data.person.canInvitePerson ||
+            data.person.canDeletePerson
+          "
         >
           <template #activator="{ on, attrs }">
             <v-btn outlined text v-bind="attrs" v-on="on">
@@ -39,57 +39,54 @@
           </template>
           <v-list>
             <v-list-item
-                v-if="data.person.canImpersonatePerson"
-                :to="{
-                  name: 'impersonate.impersonateByUserPk',
-                  params: { uid: data.person.userid },
-                  query: { next: $route.path },
-                }"
+              v-if="data.person.canImpersonatePerson"
+              :to="{
+                name: 'impersonate.impersonateByUserPk',
+                params: { uid: data.person.userid },
+                query: { next: $route.path },
+              }"
             >
               <v-list-item-icon>
                 <v-icon>mdi-account-box-outline</v-icon>
               </v-list-item-icon>
               <v-list-item-content>
-                <v-list-item-title>{{
-                    $t("person.impersonation.impersonate")
-                  }}
+                <v-list-item-title>
+                  {{ $t("person.impersonation.impersonate") }}
                 </v-list-item-title>
               </v-list-item-content>
             </v-list-item>
 
             <v-list-item
-                v-if="data.person.canInvitePerson"
-                :to="{
-                  name: 'core.invitePerson',
-                  params: { id: data.person.id },
-                }"
+              v-if="data.person.canInvitePerson"
+              :to="{
+                name: 'core.invitePerson',
+                params: { id: data.person.id },
+              }"
             >
               <v-list-item-icon>
                 <v-icon>mdi-account-plus-outline</v-icon>
               </v-list-item-icon>
               <v-list-item-content>
-                <v-list-item-title>{{
-                    $t("person.invite")
-                  }}
+                <v-list-item-title>
+                  {{ $t("person.invite") }}
                 </v-list-item-title>
               </v-list-item-content>
             </v-list-item>
 
             <v-list-item
-                v-if="data.person.canDeletePerson"
-                :to="{
-                  name: 'core.deletePerson',
-                  params: { id: data.person.id },
-                }"
-                class="error--text"
+              v-if="data.person.canDeletePerson"
+              :to="{
+                name: 'core.deletePerson',
+                params: { id: data.person.id },
+              }"
+              class="error--text"
             >
               <v-list-item-icon>
                 <v-icon color="error">mdi-delete</v-icon>
               </v-list-item-icon>
               <v-list-item-content>
-                <v-list-item-title>{{
-                    $t("person.delete")
-                  }}
+                <v-list-item-title>
+                  {{ $t("person.delete") }}
                 </v-list-item-title>
               </v-list-item-content>
             </v-list-item>
@@ -112,6 +109,4 @@ export default {
 };
 </script>
 
-<style scoped>
-
-</style>
+<style scoped></style>
diff --git a/aleksis/core/assets/components/person/PersonOverview.vue b/aleksis/core/assets/components/person/PersonOverview.vue
index d7990c3ff6f17fb7df7e3f60cb30f0f24c5a4451..43fe4620f2414bbecb6abf7207aed01cf04311a5 100644
--- a/aleksis/core/assets/components/person/PersonOverview.vue
+++ b/aleksis/core/assets/components/person/PersonOverview.vue
@@ -82,38 +82,54 @@
                   </v-list-item>
                   <v-divider inset />
 
-                  <v-list-item :href="'tel:' + data.person.phoneNumber">
+                  <v-list-item
+                    :href="
+                      data.person.phoneNumber
+                        ? 'tel:' + data.person.phoneNumber
+                        : ''
+                    "
+                  >
                     <v-list-item-icon>
                       <v-icon> mdi-phone-outline</v-icon>
                     </v-list-item-icon>
 
                     <v-list-item-content>
-                      <v-list-item-title
-                        >{{ data.person.phoneNumber || "–" }}
+                      <v-list-item-title>
+                        {{ data.person.phoneNumber || "–" }}
                       </v-list-item-title>
-                      <v-list-item-subtitle
-                        >{{ $t("person.home") }}
+                      <v-list-item-subtitle>
+                        {{ $t("person.home") }}
                       </v-list-item-subtitle>
                     </v-list-item-content>
                   </v-list-item>
 
-                  <v-list-item :href="'tel:' + data.person.mobileNumber">
+                  <v-list-item
+                    :href="
+                      data.person.mobileNumber
+                        ? 'tel:' + data.person.mobileNumber
+                        : ''
+                    "
+                  >
                     <v-list-item-action></v-list-item-action>
 
                     <v-list-item-content>
-                      <v-list-item-title
-                        >{{ data.person.mobileNumber || "–" }}
+                      <v-list-item-title>
+                        {{ data.person.mobileNumber || "–" }}
                       </v-list-item-title>
-                      <v-list-item-subtitle
-                        >{{ $t("person.mobile") }}
+                      <v-list-item-subtitle>
+                        {{ $t("person.mobile") }}
                       </v-list-item-subtitle>
                     </v-list-item-content>
                   </v-list-item>
                   <v-divider inset />
 
-                  <v-list-item :href="'mailto:' + data.person.email">
+                  <v-list-item
+                    :href="
+                      data.person.email ? 'mailto:' + data.person.email : ''
+                    "
+                  >
                     <v-list-item-icon>
-                      <v-icon> mdi-email-outline</v-icon>
+                      <v-icon>mdi-email-outline</v-icon>
                     </v-list-item-icon>
 
                     <v-list-item-content>
diff --git a/aleksis/core/assets/messages/en.json b/aleksis/core/assets/messages/en.json
index b2679b64a49563ff4a9491cfe891ef4d6ecfe6f5..d4a5e52784afd429cced438b0380faf5a421104a 100644
--- a/aleksis/core/assets/messages/en.json
+++ b/aleksis/core/assets/messages/en.json
@@ -16,7 +16,8 @@
     "other_licence": "Other Licence",
     "proprietary": "Proprietary",
     "source_code": "Source Code",
-    "website_of_aleksis": "Website of AlekSIS"
+    "website_of_aleksis": "Website of AlekSIS",
+    "show_copyright": "Show copyright"
   },
   "accounts": {
     "change_password": {
@@ -49,7 +50,8 @@
   "actions": {
     "back": "Back",
     "search": "Search",
-    "edit": "Edit"
+    "edit": "Edit",
+    "close": "Close"
   },
   "administration": {
     "backend_admin": {
@@ -74,7 +76,8 @@
     "person_is_dummy": "Your administrator account is not linked to any person. Therefore, a dummy person has been linked to your account.",
     "privacy_policy": "Privacy Policy",
     "user_not_linked_to_person": "Your user account is not linked to a person. This means you cannot access any school-related information. Please contact the managers of AlekSIS at your school.",
-    "no_permission": "You have no permission to view this page. Please login with an other account."
+    "no_permission": "You have no permission to view this page. Please login with an other account.",
+    "logo": "Logo"
   },
   "celery_progress": {
     "error_message": "The operation couldn't be finished successfully.",
diff --git a/aleksis/core/templates/core/base.html b/aleksis/core/templates/core/base.html
index faa21b8662f21d986162a03b321f22de6289f99f..8adfdd6a0f9cdcbbd25dc088969ccd1a5fe252e1 100644
--- a/aleksis/core/templates/core/base.html
+++ b/aleksis/core/templates/core/base.html
@@ -82,6 +82,33 @@
       window.parent.postMessage({height: $(document).height()});
     };
     window.onresize = documentResizePostMessage;
+
+    function findLink(el) {
+      if (el.href) {
+        return el.href;
+      } else if (el.parentElement) {
+        return findLink(el.parentElement);
+      } else {
+        return null;
+      }
+    };
+
+    function clickCallback(e) {
+      const link = findLink(e.target);
+      if (link == null) {
+        return;
+      }
+
+      const newUrl = new URL(link);
+      const currentUrl = new URL(window.location.href);
+      if(newUrl.origin !== currentUrl.origin) {
+        console.debug("External link clicked. Redirecting to " + link + " in new tab.");
+        e.preventDefault();
+        window.open(link, '_blank');
+      }
+    };
+
+    document.addEventListener('click', clickCallback, false);
   })
 </script>
 </body>
diff --git a/aleksis/core/util/frontend_helpers.py b/aleksis/core/util/frontend_helpers.py
index 7805829f06b522c77d767990e83d549195429e7d..606ca372cea1c14641632125dcee346e73e00daf 100644
--- a/aleksis/core/util/frontend_helpers.py
+++ b/aleksis/core/util/frontend_helpers.py
@@ -34,7 +34,7 @@ def write_vite_values(out_path: str) -> dict[str, Any]:
             vite_values["appDetails"][app]["name"] = app.split(".")[-1]
             vite_values["appDetails"][app]["assetDir"] = path
             vite_values["appDetails"][app]["hasMessages"] = os.path.exists(
-                os.path.join(path, "messages.json")
+                os.path.join(path, "messages", "en.json")
             )
     # Add core entrypoint
     vite_values["coreAssetDir"] = os.path.join(settings.BASE_DIR, "aleksis", "core", "assets")