feat(landing): Add i18n
This commit is contained in:
@@ -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'
|
||||
}
|
||||
])
|
||||
|
||||
Reference in New Issue
Block a user