diff --git a/frontend/src/App.vue b/frontend/src/App.vue
index 1b80337..918cd48 100644
--- a/frontend/src/App.vue
+++ b/frontend/src/App.vue
@@ -1,10 +1,12 @@
-
-
+
+
+
diff --git a/frontend/src/api/fetchCourse.ts b/frontend/src/api/fetchCourse.ts
index 00974e4..b1e164b 100644
--- a/frontend/src/api/fetchCourse.ts
+++ b/frontend/src/api/fetchCourse.ts
@@ -6,7 +6,13 @@ export async function fetchCourse(): Promise {
const courses: string[] = [];
await fetch("/api/courses")
.then((response) => {
- return response.json();
+ //check if response type is json
+ const contentType = response.headers.get("content-type");
+ if (contentType && contentType.indexOf("application/json") !== -1) {
+ return response.json();
+ } else {
+ return [];
+ }
})
.then((coursesResponse) => {
coursesResponse.forEach((course: string) => courses.push(course));
diff --git a/frontend/src/components/LocaleSwitcher.vue b/frontend/src/components/LocaleSwitcher.vue
new file mode 100644
index 0000000..c2e0eaf
--- /dev/null
+++ b/frontend/src/components/LocaleSwitcher.vue
@@ -0,0 +1,39 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/frontend/src/components/MenuBar.vue b/frontend/src/components/MenuBar.vue
index fb8263c..be33bd1 100644
--- a/frontend/src/components/MenuBar.vue
+++ b/frontend/src/components/MenuBar.vue
@@ -1,45 +1,59 @@
@@ -48,4 +62,4 @@ const items = ref([
background-color: transparent;
border: none;
}
-
+
\ No newline at end of file
diff --git a/frontend/src/i18n/index.ts b/frontend/src/i18n/index.ts
index cf409a0..a048b1a 100644
--- a/frontend/src/i18n/index.ts
+++ b/frontend/src/i18n/index.ts
@@ -1,11 +1,55 @@
-import { createI18n } from 'vue-i18n'
-import messages from "./messages.ts";
+import { createI18n } from "vue-i18n";
+import { nextTick } from "vue";
+import defaultMessages from './translations/en.json'
-const i18n = createI18n({
- legacy: false,
- globalInjection: true,
- locale: 'en',
- messages,
-})
+export const supportedLocales= {
+ 'en': { name: 'English'},
+ 'de': { name: 'Deutsch'},
+}
+export let defaultLocale = 'en'
+// Private instance of VueI18n object
+let _i18n: any
+// Initializer
+function setup(options = { locale: defaultLocale }) {
+ _i18n = createI18n({
+ legacy: false,
+ locale: options.locale,
+ fallbackLocale: defaultLocale,
+ messages: { [defaultLocale]: defaultMessages },
+ })
+ setLocale(options.locale)
+ return _i18n
+}
-export default i18n
\ No newline at end of file
+// Sets the active locale.
+function setLocale(newLocale : any) {
+ _i18n.global.locale = newLocale
+ setDocumentAttributesFor(newLocale)
+}
+
+async function loadMessagesFor(locale: any) {
+ const messages = await import(
+ `./translations/${locale}.json`
+ )
+
+ _i18n.global.setLocaleMessage(locale, messages.default)
+
+ return nextTick()
+}
+
+function setDocumentAttributesFor(locale: any) {
+ const htmlElement = document.querySelector('html')
+
+ htmlElement?.setAttribute('lang', locale)
+}
+
+// Public interface
+export default {
+ // Expose the VueI18n instance via a getter
+ get vueI18n() {
+ return _i18n
+ },
+ setup,
+ setLocale,
+ loadMessagesFor,
+}
\ No newline at end of file
diff --git a/frontend/src/i18n/messages.ts b/frontend/src/i18n/messages.ts
index 3325aac..2f07201 100644
--- a/frontend/src/i18n/messages.ts
+++ b/frontend/src/i18n/messages.ts
@@ -1,18 +1,18 @@
export default {
- en: {
- createCalendar: 'Create Calendar',
- editCalendar: 'Edit Calendar',
- roomFinder: 'Room Finder',
- faq: 'FAQ',
- imprint: 'Imprint',
- privacy: 'Privacy',
+ en : {
+ createCalendar: "Create Calendar",
+ editCalendar: "Edit Calendar",
+ roomFinder: "Room Finder",
+ faq: "FAQ",
+ imprint: "Imprint",
+ privacy: "Privacy Policy",
},
- de: {
- createCalendar: 'Kalender erstellen',
- editCalendar: 'Kalender bearbeiten',
- roomFinder: 'Raumfinder',
- faq: 'FAQ',
- imprint: 'Impressum',
- privacy: 'Datenschutz',
+ de : {
+ createCalendar: "Kalender erstellen",
+ editCalendar: "Kalender bearbeiten",
+ roomFinder: "Raumfinder",
+ faq: "FAQ",
+ imprint: "Impressum",
+ privacy: "Datenschutz"
}
}
\ No newline at end of file
diff --git a/frontend/src/i18n/translations/de.json b/frontend/src/i18n/translations/de.json
new file mode 100644
index 0000000..93783bc
--- /dev/null
+++ b/frontend/src/i18n/translations/de.json
@@ -0,0 +1,8 @@
+{
+ "createCalendar": "Kalender erstellen",
+ "editCalendar": "Kalender bearbeiten",
+ "roomFinder": "Raumfinder",
+ "faq": "FAQ",
+ "imprint": "Impressum",
+ "privacy": "Datenschutz"
+}
\ No newline at end of file
diff --git a/frontend/src/i18n/translations/en.json b/frontend/src/i18n/translations/en.json
new file mode 100644
index 0000000..d9a1164
--- /dev/null
+++ b/frontend/src/i18n/translations/en.json
@@ -0,0 +1,8 @@
+{
+ "createCalendar": "Create Calendar",
+ "editCalendar": "Edit Calendar",
+ "roomFinder": "Room Finder",
+ "faq": "FAQ",
+ "imprint": "Imprint",
+ "privacy": "Privacy"
+}
\ No newline at end of file
diff --git a/frontend/src/main.ts b/frontend/src/main.ts
index 75c9915..328181a 100644
--- a/frontend/src/main.ts
+++ b/frontend/src/main.ts
@@ -35,12 +35,13 @@ import i18n from "./i18n";
const app = createApp(App);
const pinia = createPinia();
+i18n.setup();
+app.use(i18n.vueI18n);
app.use(PrimeVue);
app.use(router);
app.use(ToastService);
app.use(pinia);
app.use(DialogService);
-app.use(i18n);
app.component("Button", Button);
app.component("Menu", Menu);
app.component("Menubar", Menubar);
diff --git a/frontend/src/router/index.ts b/frontend/src/router/index.ts
index 95c4864..8e6ce2d 100644
--- a/frontend/src/router/index.ts
+++ b/frontend/src/router/index.ts
@@ -1,6 +1,5 @@
import { createRouter, createWebHistory } from "vue-router";
import Faq from "../components/FaqPage.vue";
-import CourseSelection from "../components/CourseSelection.vue";
import AdditionalModules from "../components/AdditionalModules.vue";
import CalendarLink from "../components/CalendarLink.vue";
import Imprint from "../components/ImprintPage.vue";
@@ -10,70 +9,89 @@ import RoomFinder from "../components/RoomFinder.vue";
import EditCalendarView from "../view/editCalendarView.vue";
import EditAdditionalModules from "../components/editCalendar/EditAdditionalModules.vue";
import EditModules from "../components/editCalendar/EditModules.vue";
+import CourseSelection from "../components/CourseSelection.vue";
+import i18n, { defaultLocale } from "../i18n";
const router = createRouter({
history: createWebHistory(import.meta.env.BASE_URL),
routes: [
{
path: "/",
- name: "course-selection",
- component: CourseSelection,
+ redirect: `/${defaultLocale}`,
},
{
- path: "/rooms",
- name: "room-finder",
- component: RoomFinder,
- },
- {
- path: "/faq",
- name: "faq",
- component: Faq,
- },
- {
- path: "/additional-modules",
- name: "additional-modules",
- component: AdditionalModules,
- },
- {
- path: "/edit-additional-modules",
- name: "edit-additional-modules",
- component: EditAdditionalModules,
- },
- {
- path: "/edit-calendar",
- name: "edit-calendar",
- component: EditModules,
- },
- {
- path: "/calendar-link",
- name: "calendar-link",
- component: CalendarLink,
- },
- {
- path: "/edit",
- name: "edit",
- component: EditCalendarView,
- },
- {
- path: "/privacy-policy",
- name: "privacy-policy",
- component: PrivacyPolicy,
- },
- {
- path: "/imprint",
- name: "imprint",
- component: Imprint,
- },
- {
- path: "/rename-modules",
- name: "rename-modules",
- component: RenameModules,
- },
- {
- path: "/:catchAll(.*)",
- redirect: "/",
+ path: "/:locale",
+ children: [
+ {
+ path: "",
+ name: "course-selection",
+ component: CourseSelection,
+ },
+ {
+ path: "rooms",
+ name: "room-finder",
+ component: RoomFinder,
+ },
+ {
+ path: "faq",
+ name: "faq",
+ component: Faq,
+ },
+ {
+ path: "additional-modules",
+ name: "additional-modules",
+ component: AdditionalModules,
+ },
+ {
+ path: "edit-additional-modules",
+ name: "edit-additional-modules",
+ component: EditAdditionalModules,
+ },
+ {
+ path: "edit-calendar",
+ name: "edit-calendar",
+ component: EditModules,
+ },
+ {
+ path: "calendar-link",
+ name: "calendar-link",
+ component: CalendarLink,
+ },
+ {
+ path: "edit",
+ name: "edit",
+ component: EditCalendarView,
+ },
+ {
+ path: "privacy-policy",
+ name: "privacy-policy",
+ component: PrivacyPolicy,
+ },
+ {
+ path: "imprint",
+ name: "imprint",
+ component: Imprint,
+ },
+ {
+ path: "rename-modules",
+ name: "rename-modules",
+ component: RenameModules,
+ },
+ ],
},
],
});
+router.beforeEach(async (to, from) => {
+ const newLocale = to.params.locale
+ const prevLocale = from.params.locale
+ // If the locale hasn't changed, do nothing
+ if (newLocale === prevLocale) {
+ return
+ }
+
+ await i18n.loadMessagesFor(newLocale)
+ i18n.setLocale(newLocale)
+})
+
export default router;
diff --git a/frontend/vite.config.ts b/frontend/vite.config.ts
index 3353390..59a9a80 100644
--- a/frontend/vite.config.ts
+++ b/frontend/vite.config.ts
@@ -1,9 +1,15 @@
import { defineConfig } from "vite";
import vue from "@vitejs/plugin-vue";
+import { fileURLToPath } from "node:url";
// https://vitejs.dev/config/
export default defineConfig({
plugins: [vue()],
+ resolve: {
+ alias: {
+ '@': fileURLToPath(new URL('./src', import.meta.url))
+ }
+ },
server: {
host: true,
port: 8000,