From 3e1214d13bf2b5d8fc5a131a417e71d3f6961fdd Mon Sep 17 00:00:00 2001 From: masterElmar <18119527+masterElmar@users.noreply.github.com> Date: Tue, 14 Nov 2023 23:22:56 +0100 Subject: [PATCH 1/7] feat:#60 added first example localization --- frontend/package-lock.json | 61 +++++++++++++++++++++++++++++ frontend/package.json | 1 + frontend/src/components/MenuBar.vue | 14 ++++--- frontend/src/i18n/index.ts | 11 ++++++ frontend/src/i18n/messages.ts | 18 +++++++++ frontend/src/main.ts | 2 + 6 files changed, 101 insertions(+), 6 deletions(-) create mode 100644 frontend/src/i18n/index.ts create mode 100644 frontend/src/i18n/messages.ts diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 1434fd0..651a182 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -18,6 +18,7 @@ "primeicons": "^6.0.1", "primevue": "^3.32.2", "vue": "^3.3.4", + "vue-i18n": "^9.4.1", "vue-router": "^4.2.4" }, "devDependencies": { @@ -584,6 +585,47 @@ "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==", "dev": true }, + "node_modules/@intlify/core-base": { + "version": "9.4.1", + "resolved": "https://registry.npmjs.org/@intlify/core-base/-/core-base-9.4.1.tgz", + "integrity": "sha512-WIwx+elsZbxSMxRG5+LC+utRohFvmZMoDevfKOfnYMLbpCjCSavqTfHJAtfsY6ruowzqXeKkeLhRHbYbjoJx5g==", + "dependencies": { + "@intlify/message-compiler": "9.4.1", + "@intlify/shared": "9.4.1" + }, + "engines": { + "node": ">= 16" + }, + "funding": { + "url": "https://github.com/sponsors/kazupon" + } + }, + "node_modules/@intlify/message-compiler": { + "version": "9.4.1", + "resolved": "https://registry.npmjs.org/@intlify/message-compiler/-/message-compiler-9.4.1.tgz", + "integrity": "sha512-aN2N+dUx320108QhH51Ycd2LEpZ+NKbzyQ2kjjhqMcxhHdxtOnkgdx+MDBhOy/CObwBmhC3Nygzc6hNlfKvPNw==", + "dependencies": { + "@intlify/shared": "9.4.1", + "source-map-js": "^1.0.2" + }, + "engines": { + "node": ">= 16" + }, + "funding": { + "url": "https://github.com/sponsors/kazupon" + } + }, + "node_modules/@intlify/shared": { + "version": "9.4.1", + "resolved": "https://registry.npmjs.org/@intlify/shared/-/shared-9.4.1.tgz", + "integrity": "sha512-A51elBmZWf1FS80inf/32diO9DeXoqg9GR9aUDHFcfHoNDuT46Q+fpPOdj8jiJnSHSBh8E1E+6qWRhAZXdK3Ng==", + "engines": { + "node": ">= 16" + }, + "funding": { + "url": "https://github.com/sponsors/kazupon" + } + }, "node_modules/@jridgewell/gen-mapping": { "version": "0.3.3", "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz", @@ -3525,6 +3567,25 @@ "eslint": ">=6.0.0" } }, + "node_modules/vue-i18n": { + "version": "9.4.1", + "resolved": "https://registry.npmjs.org/vue-i18n/-/vue-i18n-9.4.1.tgz", + "integrity": "sha512-vnQyYE9LBuNOqPpETIcCaGnAyLEqfeIvDcyZ9T+WBCWFTqWw1J8FuF1jfeDwpHBi5JKgAwgXyq1mt8jp/x/GPA==", + "dependencies": { + "@intlify/core-base": "9.4.1", + "@intlify/shared": "9.4.1", + "@vue/devtools-api": "^6.5.0" + }, + "engines": { + "node": ">= 16" + }, + "funding": { + "url": "https://github.com/sponsors/kazupon" + }, + "peerDependencies": { + "vue": "^3.0.0" + } + }, "node_modules/vue-router": { "version": "4.2.4", "resolved": "https://registry.npmjs.org/vue-router/-/vue-router-4.2.4.tgz", diff --git a/frontend/package.json b/frontend/package.json index 12358ed..fcf1f21 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -21,6 +21,7 @@ "primeicons": "^6.0.1", "primevue": "^3.32.2", "vue": "^3.3.4", + "vue-i18n": "^9.4.1", "vue-router": "^4.2.4" }, "devDependencies": { diff --git a/frontend/src/components/MenuBar.vue b/frontend/src/components/MenuBar.vue index a3b0ec7..fb8263c 100644 --- a/frontend/src/components/MenuBar.vue +++ b/frontend/src/components/MenuBar.vue @@ -1,34 +1,36 @@ 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, From 00399c32d9b102849193de95da40ad9b0e027165 Mon Sep 17 00:00:00 2001 From: masterelmar <18119527+masterElmar@users.noreply.github.com> Date: Wed, 15 Nov 2023 12:46:56 +0100 Subject: [PATCH 3/7] feat:#60 added localization switch --- frontend/package-lock.json | 89 +++++++++++++++++++++ frontend/package.json | 1 + frontend/src/components/CourseSelection.vue | 13 +-- frontend/src/components/LocaleSwitcher.vue | 64 ++++++++------- frontend/src/components/MenuBar.vue | 30 +++---- frontend/src/i18n/index.ts | 29 +++---- frontend/src/i18n/translations/de.json | 9 ++- frontend/src/i18n/translations/en.json | 9 ++- frontend/src/main.ts | 4 +- frontend/src/router/index.ts | 37 +++------ frontend/src/store/localeStore.ts | 17 ++++ 11 files changed, 204 insertions(+), 98 deletions(-) create mode 100644 frontend/src/store/localeStore.ts diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 651a182..6c1bdde 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -13,6 +13,7 @@ "@fullcalendar/interaction": "^6.1.9", "@fullcalendar/timegrid": "^6.1.9", "@fullcalendar/vue3": "^6.1.9", + "@vueuse/core": "^10.6.1", "pinia": "^2.1.6", "primeflex": "^3.3.1", "primeicons": "^6.0.1", @@ -770,6 +771,11 @@ "integrity": "sha512-7aqorHYgdNO4DM36stTiGO3DvKoex9TQRwsJU6vMaFGyqpBA1MNZkz+PG3gaNUPpTAOYhT1WR7M1JyA3fbS9Cw==", "dev": true }, + "node_modules/@types/web-bluetooth": { + "version": "0.0.20", + "resolved": "https://registry.npmjs.org/@types/web-bluetooth/-/web-bluetooth-0.0.20.tgz", + "integrity": "sha512-g9gZnnXVq7gM7v3tJCWV/qw7w+KeOlSHAhgF9RytFyifW6AF61hdT2ucrYhPq9hLs5JIryeupHV3qGk95dH9ow==" + }, "node_modules/@typescript-eslint/eslint-plugin": { "version": "6.7.0", "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.7.0.tgz", @@ -1164,6 +1170,89 @@ "@vue/language-core": "1.8.8" } }, + "node_modules/@vueuse/core": { + "version": "10.6.1", + "resolved": "https://registry.npmjs.org/@vueuse/core/-/core-10.6.1.tgz", + "integrity": "sha512-Pc26IJbqgC9VG1u6VY/xrXXfxD33hnvxBnKrLlA2LJlyHII+BSrRoTPJgGYq7qZOu61itITFUnm6QbacwZ4H8Q==", + "dependencies": { + "@types/web-bluetooth": "^0.0.20", + "@vueuse/metadata": "10.6.1", + "@vueuse/shared": "10.6.1", + "vue-demi": ">=0.14.6" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, + "node_modules/@vueuse/core/node_modules/vue-demi": { + "version": "0.14.6", + "resolved": "https://registry.npmjs.org/vue-demi/-/vue-demi-0.14.6.tgz", + "integrity": "sha512-8QA7wrYSHKaYgUxDA5ZC24w+eHm3sYCbp0EzcDwKqN3p6HqtTCGR/GVsPyZW92unff4UlcSh++lmqDWN3ZIq4w==", + "hasInstallScript": true, + "bin": { + "vue-demi-fix": "bin/vue-demi-fix.js", + "vue-demi-switch": "bin/vue-demi-switch.js" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + }, + "peerDependencies": { + "@vue/composition-api": "^1.0.0-rc.1", + "vue": "^3.0.0-0 || ^2.6.0" + }, + "peerDependenciesMeta": { + "@vue/composition-api": { + "optional": true + } + } + }, + "node_modules/@vueuse/metadata": { + "version": "10.6.1", + "resolved": "https://registry.npmjs.org/@vueuse/metadata/-/metadata-10.6.1.tgz", + "integrity": "sha512-qhdwPI65Bgcj23e5lpGfQsxcy0bMjCAsUGoXkJ7DsoeDUdasbZ2DBa4dinFCOER3lF4gwUv+UD2AlA11zdzMFw==", + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, + "node_modules/@vueuse/shared": { + "version": "10.6.1", + "resolved": "https://registry.npmjs.org/@vueuse/shared/-/shared-10.6.1.tgz", + "integrity": "sha512-TECVDTIedFlL0NUfHWncf3zF9Gc4VfdxfQc8JFwoVZQmxpONhLxFrlm0eHQeidHj4rdTPL3KXJa0TZCk1wnc5Q==", + "dependencies": { + "vue-demi": ">=0.14.6" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, + "node_modules/@vueuse/shared/node_modules/vue-demi": { + "version": "0.14.6", + "resolved": "https://registry.npmjs.org/vue-demi/-/vue-demi-0.14.6.tgz", + "integrity": "sha512-8QA7wrYSHKaYgUxDA5ZC24w+eHm3sYCbp0EzcDwKqN3p6HqtTCGR/GVsPyZW92unff4UlcSh++lmqDWN3ZIq4w==", + "hasInstallScript": true, + "bin": { + "vue-demi-fix": "bin/vue-demi-fix.js", + "vue-demi-switch": "bin/vue-demi-switch.js" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + }, + "peerDependencies": { + "@vue/composition-api": "^1.0.0-rc.1", + "vue": "^3.0.0-0 || ^2.6.0" + }, + "peerDependenciesMeta": { + "@vue/composition-api": { + "optional": true + } + } + }, "node_modules/@webassemblyjs/ast": { "version": "1.11.6", "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.11.6.tgz", diff --git a/frontend/package.json b/frontend/package.json index fcf1f21..e6cd731 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -16,6 +16,7 @@ "@fullcalendar/interaction": "^6.1.9", "@fullcalendar/timegrid": "^6.1.9", "@fullcalendar/vue3": "^6.1.9", + "@vueuse/core": "^10.6.1", "pinia": "^2.1.6", "primeflex": "^3.3.1", "primeicons": "^6.0.1", diff --git a/frontend/src/components/CourseSelection.vue b/frontend/src/components/CourseSelection.vue index d2c1b15..178b8be 100644 --- a/frontend/src/components/CourseSelection.vue +++ b/frontend/src/components/CourseSelection.vue @@ -1,11 +1,14 @@ \ No newline at end of file + diff --git a/frontend/src/components/MenuBar.vue b/frontend/src/components/MenuBar.vue index be33bd1..ae2129e 100644 --- a/frontend/src/components/MenuBar.vue +++ b/frontend/src/components/MenuBar.vue @@ -1,58 +1,50 @@ diff --git a/frontend/src/i18n/index.ts b/frontend/src/i18n/index.ts index a048b1a..747e9f4 100644 --- a/frontend/src/i18n/index.ts +++ b/frontend/src/i18n/index.ts @@ -1,23 +1,25 @@ import { createI18n } from "vue-i18n"; -import { nextTick } from "vue"; -import defaultMessages from './translations/en.json' +import en from './translations/en.json' +import de from './translations/de.json' +import localeStore from "../store/localeStore.ts"; 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 }) { +function setup() { _i18n = createI18n({ legacy: false, - locale: options.locale, - fallbackLocale: defaultLocale, - messages: { [defaultLocale]: defaultMessages }, + locale: localeStore().locale, + fallbackLocale: "en", + messages: { + en, + de + }, }) - setLocale(options.locale) return _i18n } @@ -27,16 +29,6 @@ function setLocale(newLocale : any) { 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') @@ -51,5 +43,4 @@ export default { }, setup, setLocale, - loadMessagesFor, } \ No newline at end of file diff --git a/frontend/src/i18n/translations/de.json b/frontend/src/i18n/translations/de.json index 93783bc..f4d6c68 100644 --- a/frontend/src/i18n/translations/de.json +++ b/frontend/src/i18n/translations/de.json @@ -4,5 +4,12 @@ "roomFinder": "Raumfinder", "faq": "FAQ", "imprint": "Impressum", - "privacy": "Datenschutz" + "privacy": "Datenschutz", + "english": "Englisch", + "german": "Deutsch", + "courseSelection": { + "winterSemester": "Wintersemester", + "summerSemester": "Sommersemester", + "selectCourse": "Bitte wähle eine Gruppe und das Semester aus" + } } \ No newline at end of file diff --git a/frontend/src/i18n/translations/en.json b/frontend/src/i18n/translations/en.json index d9a1164..4746e46 100644 --- a/frontend/src/i18n/translations/en.json +++ b/frontend/src/i18n/translations/en.json @@ -4,5 +4,12 @@ "roomFinder": "Room Finder", "faq": "FAQ", "imprint": "Imprint", - "privacy": "Privacy" + "privacy": "Privacy", + "english": "English", + "german": "German", + "courseSelection": { + "winterSemester": "winter semester", + "summerSemester": "summer semester", + "selectCourse": "Please select a course and semester" + } } \ No newline at end of file diff --git a/frontend/src/main.ts b/frontend/src/main.ts index 328181a..3c4bc9b 100644 --- a/frontend/src/main.ts +++ b/frontend/src/main.ts @@ -35,13 +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); +i18n.setup(); +app.use(i18n.vueI18n); 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 8e6ce2d..7bf3038 100644 --- a/frontend/src/router/index.ts +++ b/frontend/src/router/index.ts @@ -10,75 +10,66 @@ 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"; +import i18n from "../i18n"; const router = createRouter({ history: createWebHistory(import.meta.env.BASE_URL), routes: [ - { - path: "/", - redirect: `/${defaultLocale}`, - }, - { - path: "/:locale", - children: [ { - path: "", + path: "/", name: "course-selection", component: CourseSelection, }, { - path: "rooms", + path: "/rooms", name: "room-finder", component: RoomFinder, }, { - path: "faq", + path: "/faq", name: "faq", component: Faq, }, { - path: "additional-modules", + path: "/additional-modules", name: "additional-modules", component: AdditionalModules, }, { - path: "edit-additional-modules", + path: "/edit-additional-modules", name: "edit-additional-modules", component: EditAdditionalModules, }, { - path: "edit-calendar", + path: "/edit-calendar", name: "edit-calendar", component: EditModules, }, { - path: "calendar-link", + path: "/calendar-link", name: "calendar-link", component: CalendarLink, }, { - path: "edit", + path: "/edit", name: "edit", component: EditCalendarView, }, { - path: "privacy-policy", + path: "/privacy-policy", name: "privacy-policy", component: PrivacyPolicy, }, { - path: "imprint", + path: "/imprint", name: "imprint", component: Imprint, }, { - path: "rename-modules", + path: "/rename-modules", name: "rename-modules", component: RenameModules, - }, - ], - }, + } ], }); @@ -89,8 +80,6 @@ router.beforeEach(async (to, from) => { if (newLocale === prevLocale) { return } - - await i18n.loadMessagesFor(newLocale) i18n.setLocale(newLocale) }) diff --git a/frontend/src/store/localeStore.ts b/frontend/src/store/localeStore.ts new file mode 100644 index 0000000..c67cb4f --- /dev/null +++ b/frontend/src/store/localeStore.ts @@ -0,0 +1,17 @@ +import { defineStore } from "pinia"; +import { useLocalStorage } from "@vueuse/core" + +const localeStore = defineStore("localeStore", { + state: () => { + return { + locale: useLocalStorage('locale', "en"), //useLocalStorage takes in a key of 'count' and default value of 0 + }; + }, + actions: { + setLocale(locale: string) { + this.locale = locale; + }, + }, +}); + +export default localeStore; From 7e261438d53a24d7369eaff7ec37509429c23942 Mon Sep 17 00:00:00 2001 From: masterElmar <18119527+masterElmar@users.noreply.github.com> Date: Wed, 15 Nov 2023 17:46:25 +0100 Subject: [PATCH 4/7] feat:#60 added localization for more pages --- .gitignore | 3 +- .idea/workspace.xml | 50 ++++++------------ frontend/index.html | 2 +- frontend/public/htwk.svg | 7 +++ frontend/public/htwkalender.svg | 30 +++++++++++ frontend/src/components/CourseSelection.vue | 24 +++++---- frontend/src/components/MenuBar.vue | 28 +++++++--- frontend/src/components/ModuleInformation.vue | 6 +-- frontend/src/components/ModuleSelection.vue | 16 +++--- frontend/src/components/RoomOccupation.vue | 23 +++++--- frontend/src/i18n/translations/de.json | 42 +++++++++++++-- frontend/src/i18n/translations/en.json | 52 ++++++++++++++++--- frontend/src/router/index.ts | 10 ++-- .../AdditionalModules.vue | 25 ++++----- ...tCalendarView.vue => EditCalendarView.vue} | 17 +++--- .../src/{components => view}/ImprintPage.vue | 0 .../{components => view}/PrivacyPolicy.vue | 0 .../src/{components => view}/RoomFinder.vue | 15 ++++-- 18 files changed, 236 insertions(+), 114 deletions(-) create mode 100644 frontend/public/htwk.svg create mode 100644 frontend/public/htwkalender.svg rename frontend/src/{components => view}/AdditionalModules.vue (88%) rename frontend/src/view/{editCalendarView.vue => EditCalendarView.vue} (81%) rename frontend/src/{components => view}/ImprintPage.vue (100%) rename frontend/src/{components => view}/PrivacyPolicy.vue (100%) rename frontend/src/{components => view}/RoomFinder.vue (68%) diff --git a/.gitignore b/.gitignore index 2ba9c4f..278bf8a 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ .idea/ .vscode/ .DS_Store - +workspace.xml +**/.idea/ \ No newline at end of file diff --git a/.idea/workspace.xml b/.idea/workspace.xml index 2b15ac5..9a8e47e 100644 --- a/.idea/workspace.xml +++ b/.idea/workspace.xml @@ -5,47 +5,24 @@ + + + - - - - - - - - - - - - - + - - + - - - - + + - - - - - - + + - - - - - - - - + + + + + diff --git a/frontend/index.html b/frontend/index.html index a4c3e3f..4aad534 100644 --- a/frontend/index.html +++ b/frontend/index.html @@ -2,7 +2,7 @@ - + HTWKalender diff --git a/frontend/public/htwk.svg b/frontend/public/htwk.svg new file mode 100644 index 0000000..cef9566 --- /dev/null +++ b/frontend/public/htwk.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/frontend/public/htwkalender.svg b/frontend/public/htwkalender.svg new file mode 100644 index 0000000..e0c98e5 --- /dev/null +++ b/frontend/public/htwkalender.svg @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/frontend/src/components/CourseSelection.vue b/frontend/src/components/CourseSelection.vue index 178b8be..24a1c03 100644 --- a/frontend/src/components/CourseSelection.vue +++ b/frontend/src/components/CourseSelection.vue @@ -7,8 +7,7 @@ import { import ModuleSelection from "./ModuleSelection.vue"; import { Module } from "../model/module.ts"; import { useI18n } from "vue-i18n"; -const { t } = useI18n({ useScope: 'global' }) - +const { t } = useI18n({ useScope: "global" }); const courses = async () => { return await fetchCourse(); @@ -16,10 +15,12 @@ const courses = async () => { const selectedCourse: Ref<{ name: string }> = ref({ name: "" }); const countries: Ref<{ name: string }[]> = ref([]); -const semesters: ComputedRef<{ name: string; value: string }[]> = computed(() =>[ - { name: t('courseSelection.winterSemester'), value: "ws" }, - { name: t('courseSelection.summerSemester'), value: "ss" }, -]); +const semesters: ComputedRef<{ name: string; value: string }[]> = computed( + () => [ + { name: t("courseSelection.winterSemester"), value: "ws" }, + { name: t("courseSelection.summerSemester"), value: "ss" }, + ], +); const selectedSemester: Ref<{ name: string; value: string }> = ref( semesters.value[0], @@ -46,7 +47,7 @@ async function getModules() {

- Welcome to HTWKalender + {{$t("courseSelection.headline")}} -
{{ $t('courseSelection.selectCourse') }}
+
{{ $t("courseSelection.subTitle") }}

@@ -76,7 +78,7 @@ async function getModules() { :options="semesters" class="w-full md:w-25rem mx-2" option-label="name" - placeholder="Select a Semester" + :placeholder="$t('courseSelection.semesterDropDown')" @change="getModules()" >
@@ -91,4 +93,4 @@ async function getModules() {
- + \ No newline at end of file diff --git a/frontend/src/components/MenuBar.vue b/frontend/src/components/MenuBar.vue index ae2129e..c2a4827 100644 --- a/frontend/src/components/MenuBar.vue +++ b/frontend/src/components/MenuBar.vue @@ -8,40 +8,52 @@ const items = computed(() => [ { label: t("createCalendar"), icon: "pi pi-fw pi-plus", - to: "/", + route: "/", }, { label: t("editCalendar"), icon: "pi pi-fw pi-pencil", - to: "/edit", + route: "/edit", }, { label: t("roomFinder"), icon: "pi pi-fw pi-calendar", - to: `rooms`, + route: `rooms`, }, { label: t("faq"), icon: "pi pi-fw pi-book", - to: `faq`, + route: `faq`, }, { label: t("imprint"), icon: "pi pi-fw pi-id-card", - to: `imprint`, + route: `imprint`, }, { label: t("privacy"), icon: "pi pi-fw pi-exclamation-triangle", - to: `privacy-policy`, + route: `privacy-policy`, }, ]);