feat(landing): Add i18n

This commit is contained in:
2026-01-05 19:13:41 +01:00
parent a086763c80
commit 01df3e622e
17 changed files with 4049 additions and 406 deletions

View File

@@ -1,7 +1,7 @@
<template>
<UApp>
<!-- Skip link for accessibility -->
<a href="#main-content" class="skip-link"> Zum Hauptinhalt springen </a>
<a href="#main-content" class="skip-link"> {{ $t('common.skipToContent') }} </a>
<NuxtRouteAnnouncer />
@@ -40,6 +40,14 @@
/>
<template #right>
<USelectMenu
v-model="selectedLocale"
:items="localeItems"
class="w-[100px]"
:ui="{
base: 'text-sm'
}"
/>
<UColorModeButton
:ui="{
base: 'text-gray-600 dark:text-gray-300 hover:text-primary-600 dark:hover:text-primary-400'
@@ -49,7 +57,7 @@
to="#newsletter"
class="btn-gradient px-5 py-2.5 rounded-xl font-semibold shadow-lg shadow-primary-500/25 hover:shadow-primary-500/40 transition-shadow"
>
<span>Informiert bleiben</span>
<span>{{ $t('common.stayInformed') }}</span>
</UButton>
</template>
@@ -64,7 +72,7 @@
/>
<div class="mt-6 pt-6 border-t border-gray-200 dark:border-gray-800">
<UButton to="#newsletter" size="lg" block class="btn-gradient rounded-xl font-semibold">
Informiert bleiben
{{ $t('common.stayInformed') }}
</UButton>
</div>
</template>
@@ -90,7 +98,7 @@
<span class="font-heading text-xl font-bold text-gray-900 dark:text-white"> LegalConsentHub </span>
</NuxtLink>
<p class="text-gray-600 dark:text-gray-400 max-w-sm mb-6">
Digitale Mitbestimmung für IT- und KI-Systeme. Strukturierte Prozesse, revisionssichere Dokumentation.
{{ $t('footer.brandDescription') }}
</p>
<div class="flex items-center gap-3">
<UButton
@@ -115,7 +123,7 @@
<!-- Links column -->
<div>
<h4 class="font-heading font-bold text-gray-900 dark:text-white mb-4">Navigation</h4>
<h4 class="font-heading font-bold text-gray-900 dark:text-white mb-4">{{ $t('common.navigation') }}</h4>
<ul class="space-y-3">
<li v-for="item in navigationItems" :key="item.label">
<NuxtLink
@@ -130,7 +138,7 @@
<!-- Legal column -->
<div>
<h4 class="font-heading font-bold text-gray-900 dark:text-white mb-4">Rechtliches</h4>
<h4 class="font-heading font-bold text-gray-900 dark:text-white mb-4">{{ $t('common.legal') }}</h4>
<ul class="space-y-3">
<li v-for="item in footerLinks" :key="item.label">
<NuxtLink
@@ -148,16 +156,16 @@
<div class="mt-12 pt-8 border-t border-gray-200 dark:border-gray-800">
<div class="flex flex-col sm:flex-row justify-between items-center gap-4">
<p class="text-sm text-gray-500 dark:text-gray-400">
© {{ new Date().getFullYear() }} LegalConsentHub. Alle Rechte vorbehalten.
© {{ new Date().getFullYear() }} LegalConsentHub. {{ $t('common.allRightsReserved') }}
</p>
<div class="flex items-center gap-6 text-sm text-gray-500 dark:text-gray-400">
<div class="flex items-center gap-2">
<UIcon name="i-lucide-server" class="w-4 h-4" />
<span>Hosted in Germany</span>
<span>{{ $t('common.hostedInGermany') }}</span>
</div>
<div class="flex items-center gap-2">
<UIcon name="i-lucide-shield-check" class="w-4 h-4" />
<span>DSGVO-konform</span>
<span>{{ $t('common.gdprCompliant') }}</span>
</div>
</div>
</div>
@@ -170,6 +178,26 @@
<script setup lang="ts">
import type { NavigationMenuItem } from '@nuxt/ui'
const { t, locale, locales, setLocale } = useI18n()
// Locale selector items
const localeItems = computed(() =>
(locales.value as Array<{ code: string; name: string }>).map((l) => ({
label: l.name,
value: l.code
}))
)
// Selected locale for the dropdown
const selectedLocale = computed({
get: () => localeItems.value.find((l) => l.value === locale.value),
set: (item) => {
if (item) {
setLocale(item.value as 'en' | 'de')
}
}
})
// Track scroll position for header styling
const isScrolled = ref(false)
@@ -188,34 +216,34 @@ onMounted(() => {
const navigationItems = computed<NavigationMenuItem[]>(() => [
{
label: 'Für Betriebsräte',
label: t('nav.forWorksCouncils'),
to: '#betriebsraete'
},
{
label: 'Für Unternehmen',
label: t('nav.forCompanies'),
to: '#unternehmen'
},
{
label: 'Features',
label: t('nav.features'),
to: '#features'
},
{
label: 'Kontakt',
label: t('nav.contact'),
to: '#kontakt'
}
])
const footerLinks = computed<NavigationMenuItem[]>(() => [
{
label: 'Impressum',
label: t('footer.imprint'),
to: '/impressum'
},
{
label: 'Datenschutz',
label: t('footer.privacy'),
to: '/datenschutz'
},
{
label: 'AGB',
label: t('footer.terms'),
to: '/agb'
}
])