Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions astro.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -18,4 +18,8 @@ export default defineConfig({
adapter: node({
mode: 'standalone',
}),
i18n: {
defaultLocale: 'en',
locales: ['en', 'de'],
},
});
14 changes: 12 additions & 2 deletions src/components/Calendar.vue
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,16 @@ import FullCalendar from '@fullcalendar/vue3';
import dayGridPlugin from '@fullcalendar/daygrid';
import iCalendarPlugin from '@fullcalendar/icalendar';
import listPlugin from '@fullcalendar/list';
import { getUiTranslations } from '../i18n/ui/ui-i18n-helper';

const props = defineProps({
locale: {
type: String,
default: 'en',
},
});

const t = getUiTranslations(props.locale);

// --- Popover State & Logic ---

Expand Down Expand Up @@ -162,13 +172,13 @@ const calendarOptions = computed(() => ({
url: '/api/get-calendar?source=pretix',
format: 'ics',
color: '#3788d8',
label: 'Workshops',
label: t.calendar.workshops,
},
{
url: '/api/get-calendar?source=events',
format: 'ics',
color: '#f89538',
label: 'Open Events',
label: t.calendar.openEvents,
},
],
headerToolbar: {
Expand Down
14 changes: 11 additions & 3 deletions src/components/Footer.astro
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
---
import { Icon } from 'astro-icon/components';
import { getUiTranslations } from '../i18n/ui/ui-i18n-helper';
import { getRelativeLocaleUrl } from 'astro:i18n';

const locale = Astro.currentLocale ?? 'en';
const t = getUiTranslations(locale);
---

<footer>
Expand Down Expand Up @@ -51,7 +56,7 @@ import { Icon } from 'astro-icon/components';
</div>

<div>
<span>Former channels:</span>
<span>{t.footer.formerChannels}</span>
<a href="https://twitter.com/munichmakerlab">
<Icon name="mdi:twitter" />
</a>
Expand All @@ -63,9 +68,12 @@ import { Icon } from 'astro-icon/components';
<div class="text">
Munich Maker Lab e.V.
<br />
<a href="imprint">Impressum/Imprint</a> - <a href="privacy">Datenschutzerklärung/Privacy Policy</a>
<a href={getRelativeLocaleUrl(locale, 'imprint')}>{t.footer.imprint}</a> - <a
href={getRelativeLocaleUrl(locale, 'privacy')}>{t.footer.privacyPolicy}</a
>
<br />
Edit this page on <a href="https://github.com/munichmakerlab/website">Github</a>
{t.footer.editOnGithub}
<a href="https://github.com/munichmakerlab/website">Github</a>
</div>
</footer>

Expand Down
51 changes: 51 additions & 0 deletions src/components/LanguageToggle.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
<template>
<a :href="otherLocaleUrl" class="language-toggle">
<span :class="{ active: props.locale === 'en' }">EN</span>
<span class="separator">|</span>
<span :class="{ active: props.locale === 'de' }">DE</span>
</a>
</template>

<script setup>
import { computed } from 'vue';

const props = defineProps({
locale: {
type: String,
required: true,
},
});

const otherLocaleUrl = computed(() => {
const path = window.location.pathname;
if (props.locale === 'en') {
return `/de${path}`;
}
return path.replace(/^\/de/, '') || '/';
});
</script>

<style scoped>
.language-toggle {
text-decoration: none;
color: inherit;
font-weight: 800;
cursor: pointer;
border: none;
background: none;
padding: 0;
}

.language-toggle span {
opacity: 0.5;
}

.language-toggle span.active {
opacity: 1;
}

.separator {
margin: 0 2px;
opacity: 0.5;
}
</style>
56 changes: 41 additions & 15 deletions src/components/Navbar.vue
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,20 @@
<HamburgerButton :isOpen="!isCollapsed" />
</div>
<div class="status-theme-controls show-mobile">
<LanguageToggle class="language-toggle-mobile" :locale="props.locale" />
<ThemeToggle class="theme-toggle-mobile" />
<Status v-if="doorStatus" :doorStatus="doorStatus" />
<Status v-if="doorStatus" :doorStatus="doorStatus" :locale="props.locale" />
</div>
</div>
<nav :class="isCollapsed ? 'collapsed' : ''">
<a class="logo" href="/">Munich Maker Lab</a>
<a class="logo" :href="getRelativeLocaleUrl(locale)">Munich Maker Lab</a>
<div class="links">
<a v-for="link in links" :key="link.path" :href="link.path">{{ link.name }}</a>
<div class="show-desktop">
<Status v-if="doorStatus" :doorStatus="doorStatus" />
<Status v-if="doorStatus" :doorStatus="doorStatus" :locale="props.locale" />
</div>
<ThemeToggle class="theme-toggle show-desktop" />
<LanguageToggle class="language-toggle show-desktop" :locale="props.locale" />
</div>
</nav>
</template>
Expand All @@ -24,7 +26,19 @@
import { ref, onMounted } from 'vue';
import Status from './Status.vue';
import ThemeToggle from './ThemeToggle.vue';
import LanguageToggle from './LanguageToggle.vue';
import HamburgerButton from './HamburgerButton.vue';
import { getRelativeLocaleUrl } from 'astro:i18n';
import { getUiTranslations } from '../i18n/ui/ui-i18n-helper';

const props = defineProps({
locale: {
type: String,
required: true,
},
});

const t = getUiTranslations(props.locale);

const doorStatus = ref(null);

Expand All @@ -35,27 +49,27 @@ onMounted(async () => {

const links = [
{
name: 'Home',
path: '/',
name: t.navbar.home,
path: `${getRelativeLocaleUrl(props.locale, '/')}`,
},
{
name: 'About',
path: '/about',
name: t.navbar.about,
path: `${getRelativeLocaleUrl(props.locale, '/about')}`,
},
{
name: 'Visit',
path: '/visit',
name: t.navbar.visit,
path: `${getRelativeLocaleUrl(props.locale, '/visit')}`,
},
{
name: 'Contact',
path: '/contact',
name: t.navbar.contact,
path: `${getRelativeLocaleUrl(props.locale, '/contact')}`,
},
{
name: 'Events',
path: '/events',
name: t.navbar.events,
path: `${getRelativeLocaleUrl(props.locale, '/events/')}`,
},
{
name: 'Wiki',
name: t.navbar.wiki,
path: 'https://wiki.munichmakerlab.de/',
},
];
Expand Down Expand Up @@ -124,6 +138,11 @@ const toggleCollapse = () => {
color: var(--fg);
margin-right: 4px;
}

.language-toggle-mobile {
color: var(--fg);
margin-right: 4px;
}
}

/* Desktop Menu */
Expand Down Expand Up @@ -156,19 +175,26 @@ const toggleCollapse = () => {

.links {
display: flex;
gap: 3vw;
gap: 2vw;
}

a {
text-decoration: none;
color: white;
align-self: flex-end;
white-space: nowrap;
}

.theme-toggle {
color: white;
align-self: flex-end;
filter: drop-shadow(1px 1px 0 #333333);
}

.language-toggle {
color: white;
align-self: flex-end;
filter: drop-shadow(1px 1px 0 #333333);
}
}
</style>
13 changes: 11 additions & 2 deletions src/components/Post.vue
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<template>
<div class="post">
<div class="post-date">
{{ new Date(post.created_at).toLocaleDateString('en-GB', dateOptions) }}
{{ new Date(post.created_at).toLocaleDateString(props.locale, dateOptions) }}
</div>
<div v-if="imageAttachments.length" :id="galleryId" :class="gridClass">
<a
Expand All @@ -25,7 +25,16 @@ import { computed, onMounted, onUnmounted } from 'vue';
import PhotoSwipeLightbox from 'photoswipe/lightbox';
import 'photoswipe/style.css';

const props = defineProps(['post']);
const props = defineProps({
post: {
type: Object,
required: true,
},
locale: {
type: String,
default: 'en',
},
});
const dateOptions = { year: 'numeric', month: 'long', day: 'numeric' };

const imageAttachments = computed(() => props.post.media_attachments.filter((a) => a.type === 'image'));
Expand Down
14 changes: 12 additions & 2 deletions src/components/Posts.vue
Original file line number Diff line number Diff line change
@@ -1,12 +1,22 @@
<template>
<div class="posts">
<Post v-for="post in posts" :post="post" :key="post.id" />
<a href="https://chaos.social/@munichmakerlab">See all Posts =></a>
<Post v-for="post in posts" :post="post" :key="post.id" :locale="props.locale" />
<a href="https://chaos.social/@munichmakerlab">{{ t.posts.seeAll }}</a>
</div>
</template>

<script setup>
import Post from './Post.vue';
import { getUiTranslations } from '../i18n/ui/ui-i18n-helper';

const props = defineProps({
locale: {
type: String,
default: 'en',
},
});

const t = getUiTranslations(props.locale);

const postsUrl = 'https://chaos.social/api/v1/accounts/111578979164883551/statuses';

Expand Down
17 changes: 10 additions & 7 deletions src/components/Status.vue
Original file line number Diff line number Diff line change
Expand Up @@ -6,25 +6,28 @@
<div class="modal-window">
<span class="modal-close">X</span>
<div :class="`tally ${doorStatus.door}`"></div>
{{
doorStatus.door === 'open'
? "The Space is currently open! You may come over and hang out. Keep in mind that there is no guarantee that people will be there for an extended period of time (unless it's currently the open thursday)."
: 'The Lab is currently closed. A member will need to come in and open it for visitors.'
}}
{{ doorStatus.door === 'open' ? t.status.open : t.status.closed }}
</div>
</div>
</template>

<script setup>
import { ref } from 'vue';
import { ref, computed } from 'vue';
import { getUiTranslations } from '../i18n/ui/ui-i18n-helper';

defineProps({
const props = defineProps({
doorStatus: {
type: Object,
required: true,
},
locale: {
type: String,
required: true,
},
});

const t = computed(() => getUiTranslations(props.locale));

const modalOpen = ref(false);

const openModal = () => {
Expand Down
30 changes: 30 additions & 0 deletions src/i18n/ui/de.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import type { Translations } from './ui-i18n-helper';

export const de: Translations = {
hello: 'Hallo',
status: {
open: 'Der Space ist derzeit geöffnet! Du kannst vorbeikommen und abhängen. Beachte, dass nicht garantiert ist, dass Leute für längere Zeit da sein werden (es sei denn, es ist gerade der offene Donnerstag).',
closed: 'Das Lab ist derzeit geschlossen. Ein Mitglied muss kommen und es für Besucher öffnen.',
},
calendar: {
workshops: 'Workshops',
openEvents: 'Offene Veranstaltungen',
},
posts: {
seeAll: 'Alle Beiträge ansehen =>',
},
navbar: {
home: 'Home',
about: 'Über uns',
visit: 'Besuch',
contact: 'Kontakt',
events: 'Events',
wiki: 'Wiki',
},
footer: {
formerChannels: 'Frühere Kanäle:',
imprint: 'Impressum',
privacyPolicy: 'Datenschutzerklärung',
editOnGithub: 'Seite bearbeiten auf',
},
};
28 changes: 28 additions & 0 deletions src/i18n/ui/en.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
export const en = {
hello: 'Hello',
status: {
open: "The Space is currently open! You may come over and hang out. Keep in mind that there is no guarantee that people will be there for an extended period of time (unless it's currently the open thursday).",
closed: 'The Lab is currently closed. A member will need to come in and open it for visitors.',
},
calendar: {
workshops: 'Workshops',
openEvents: 'Open Events',
},
posts: {
seeAll: 'See all Posts =>',
},
navbar: {
home: 'Home',
about: 'About',
visit: 'Visit',
contact: 'Contact',
events: 'Events',
wiki: 'Wiki',
},
footer: {
formerChannels: 'Former channels:',
imprint: 'Imprint',
privacyPolicy: 'Privacy Policy',
editOnGithub: 'Edit this page on',
},
} as const;
Loading