full site update
This commit is contained in:
BIN
src/.DS_Store
vendored
BIN
src/.DS_Store
vendored
Binary file not shown.
BIN
src/components/.DS_Store
vendored
Normal file
BIN
src/components/.DS_Store
vendored
Normal file
Binary file not shown.
@@ -1,5 +1,8 @@
|
||||
---
|
||||
import { t } from '../utils/i18n';
|
||||
import { getLangFromUrl, useTranslations, localizePath } from '../utils/i18n';
|
||||
|
||||
const lang = getLangFromUrl(Astro.url);
|
||||
const t = await useTranslations(lang);
|
||||
---
|
||||
|
||||
<section class="py-20 bg-gradient-to-br from-primary via-primary to-secondary text-primary-foreground relative overflow-hidden">
|
||||
@@ -25,7 +28,7 @@ import { t } from '../utils/i18n';
|
||||
<!-- CTA button -->
|
||||
<div class="flex flex-col sm:flex-row gap-4 justify-center items-center">
|
||||
<a
|
||||
href="/contact"
|
||||
href={localizePath("/contact", lang)}
|
||||
class="bg-background text-foreground hover:bg-background/90 px-8 py-4 text-lg font-semibold rounded-xl shadow-lg hover:shadow-xl transition-all duration-300 hover:scale-105 inline-flex items-center group"
|
||||
>
|
||||
{t('cta.button')}
|
||||
@@ -53,4 +56,4 @@ import { t } from '../utils/i18n';
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</section>
|
@@ -1,5 +1,8 @@
|
||||
---
|
||||
import { t } from '../utils/i18n';
|
||||
import { getLangFromUrl, useTranslations } from '../utils/i18n';
|
||||
|
||||
const lang = getLangFromUrl(Astro.url);
|
||||
const t = await useTranslations(lang);
|
||||
---
|
||||
|
||||
<section class="py-20 bg-background">
|
||||
@@ -219,4 +222,4 @@ import { t } from '../utils/i18n';
|
||||
});
|
||||
}
|
||||
});
|
||||
</script>
|
||||
</script>
|
@@ -1,6 +1,9 @@
|
||||
---
|
||||
import { NAVIGATION } from '../site.config';
|
||||
import { t } from '../utils/i18n';
|
||||
import { getLangFromUrl, useTranslations } from '../utils/i18n';
|
||||
|
||||
const lang = getLangFromUrl(Astro.url);
|
||||
const t = await useTranslations(lang);
|
||||
---
|
||||
|
||||
<footer class="bg-secondary-900 text-secondary-100 pt-16 pb-8">
|
||||
|
@@ -2,7 +2,10 @@
|
||||
import { NAVIGATION } from '../site.config';
|
||||
import ThemeToggle from './ThemeToggle.astro';
|
||||
import LanguageSwitcher from './LanguageSwitcher.astro';
|
||||
import { t } from '../utils/i18n';
|
||||
import { getLangFromUrl, useTranslations, localizePath } from '../utils/i18n';
|
||||
|
||||
const lang = getLangFromUrl(Astro.url);
|
||||
const t = await useTranslations(lang);
|
||||
---
|
||||
|
||||
<header class="sticky top-0 z-50 w-full border-b border-border/40 bg-background/95 backdrop-blur supports-[backdrop-filter]:bg-background/60">
|
||||
@@ -10,7 +13,7 @@ import { t } from '../utils/i18n';
|
||||
<div class="flex h-16 items-center justify-between">
|
||||
<!-- Logo -->
|
||||
<div class="flex items-center">
|
||||
<a href="/" class="flex items-center space-x-2">
|
||||
<a href={localizePath("/", lang)} class="flex items-center space-x-2">
|
||||
<div class="h-8 w-8 flex items-center justify-center">
|
||||
<img
|
||||
src="/images/TIBER365.png"
|
||||
@@ -26,7 +29,7 @@ import { t } from '../utils/i18n';
|
||||
<div class="hidden md:flex items-center space-x-6">
|
||||
{NAVIGATION.map((item) => (
|
||||
<a
|
||||
href={item.href}
|
||||
href={item.type === 'external' ? item.href : localizePath(item.href, lang)}
|
||||
target={item.type === 'external' ? '_blank' : undefined}
|
||||
rel={item.type === 'external' ? 'noopener noreferrer' : undefined}
|
||||
class="text-sm font-medium text-muted-foreground hover:text-foreground transition-colors relative group"
|
||||
@@ -69,7 +72,7 @@ import { t } from '../utils/i18n';
|
||||
<div class="px-2 pt-2 pb-3 space-y-1">
|
||||
{NAVIGATION.map((item) => (
|
||||
<a
|
||||
href={item.href}
|
||||
href={item.type === 'external' ? item.href : localizePath(item.href, lang)}
|
||||
target={item.type === 'external' ? '_blank' : undefined}
|
||||
rel={item.type === 'external' ? 'noopener noreferrer' : undefined}
|
||||
class="block px-3 py-2 text-base font-medium text-muted-foreground hover:text-foreground hover:bg-accent rounded-md transition-colors"
|
||||
@@ -116,4 +119,4 @@ import { t } from '../utils/i18n';
|
||||
});
|
||||
}
|
||||
});
|
||||
</script>
|
||||
</script>
|
@@ -1,37 +1,35 @@
|
||||
---
|
||||
import { t } from '../utils/i18n';
|
||||
import { Trans } from 'astro-i18next/components';
|
||||
import i18next from 'i18next';
|
||||
import { getLangFromUrl, useTranslations, localizePath } from '../utils/i18n';
|
||||
|
||||
// Log the locale for debugging
|
||||
console.log('Hero component locale:', i18next.language);
|
||||
const lang = getLangFromUrl(Astro.url);
|
||||
const t = await useTranslations(lang);
|
||||
---
|
||||
|
||||
<section class="relative min-h-[calc(100vh-4rem)] flex items-center justify-center bg-gradient-to-br from-background via-background to-muted overflow-hidden">
|
||||
<div class="container-custom relative z-10">
|
||||
<div class="flex flex-col items-center justify-center w-full animate-on-scroll">
|
||||
<h1 class="text-4xl sm:text-5xl lg:text-6xl font-display font-bold text-foreground mb-6 text-center">
|
||||
{t('hero.title', 'en')}
|
||||
{t('hero.title')}
|
||||
</h1>
|
||||
<p class="text-lg sm:text-xl text-muted-foreground mb-8 max-w-2xl mx-auto text-center">
|
||||
{t('hero.subtitle', 'en')}
|
||||
{t('hero.subtitle')}
|
||||
</p>
|
||||
<div class="flex flex-col sm:flex-row gap-4 justify-center mb-8">
|
||||
<a
|
||||
href="/contact"
|
||||
href={localizePath("/contact", lang)}
|
||||
class="btn-primary px-8 py-4 text-lg font-semibold rounded-xl shadow-lg hover:shadow-xl transition-all duration-300 hover:scale-105"
|
||||
>
|
||||
{t('hero.cta.primary', 'en')}
|
||||
{t('hero.cta.primary')}
|
||||
</a>
|
||||
<a
|
||||
href="/services"
|
||||
href={localizePath("/services", lang)}
|
||||
class="btn-outline px-8 py-4 text-lg font-semibold rounded-xl transition-all duration-300 hover:scale-105"
|
||||
>
|
||||
{t('hero.cta.secondary', 'en')}
|
||||
{t('hero.cta.secondary')}
|
||||
</a>
|
||||
</div>
|
||||
<p class="mt-8 text-sm text-muted-foreground text-center">
|
||||
{t('hero.trusted', 'en')}
|
||||
{t('hero.trusted')}
|
||||
</p>
|
||||
<!-- Service Icons Row -->
|
||||
<div class="flex justify-center gap-6 mt-6 mb-4 text-3xl opacity-80">
|
||||
@@ -58,4 +56,4 @@ console.log('Hero component locale:', i18next.language);
|
||||
background-image: radial-gradient(circle, rgba(var(--color-foreground) / 0.1) 1px, transparent 1px);
|
||||
background-size: 30px 30px;
|
||||
}
|
||||
</style>
|
||||
</style>
|
@@ -1,7 +0,0 @@
|
||||
import { LanguageSelector } from "astro-i18next/components";
|
||||
|
||||
<LanguageSelector
|
||||
showFlag={true}
|
||||
class="bg-white dark:bg-gray-800 text-gray-800 dark:text-white px-4 py-2 rounded-md border border-gray-300 dark:border-gray-600"
|
||||
languageMapping={{ en: "English", nl: "Nederlands", it: "Italiano" }}
|
||||
/>
|
@@ -1,21 +1,23 @@
|
||||
---
|
||||
import { LANGUAGES } from '../site.config';
|
||||
import { localizePath } from 'astro-i18next';
|
||||
import { getLangFromUrl, languages, localizePath } from '../utils/i18n';
|
||||
|
||||
const { currentLocale } = Astro;
|
||||
const { pathname } = Astro.url;
|
||||
const currentLang = getLangFromUrl(Astro.url);
|
||||
const currentPath = Astro.url.pathname;
|
||||
|
||||
// Remove the current locale from the path to get the base path
|
||||
const basePath = currentPath.replace(/^\/[a-z]{2}(\/|$)/, '/').replace(/\/$/, '') || '/';
|
||||
---
|
||||
|
||||
<select
|
||||
class="language-selector bg-white dark:bg-gray-800 text-gray-800 dark:text-white px-4 py-2 rounded-md border border-gray-300 dark:border-gray-600"
|
||||
onchange="window.location.href = this.value"
|
||||
>
|
||||
{Object.entries(LANGUAGES).map(([code, name]) => (
|
||||
{Object.entries(languages).map(([code, { name }]) => (
|
||||
<option
|
||||
value={localizePath(pathname, code)}
|
||||
selected={code === currentLocale}
|
||||
value={localizePath(basePath, code as any)}
|
||||
selected={code === currentLang}
|
||||
>
|
||||
{name}
|
||||
</option>
|
||||
))}
|
||||
</select>
|
||||
</select>
|
@@ -1,21 +1,71 @@
|
||||
---
|
||||
import LanguageSelector from './LanguageSelector.astro';
|
||||
import { getLangFromUrl, languages, localizePath } from '../utils/i18n';
|
||||
|
||||
const currentLang = getLangFromUrl(Astro.url);
|
||||
const currentPath = Astro.url.pathname;
|
||||
|
||||
// Remove the current locale from the path to get the base path
|
||||
const basePath = currentPath.replace(/^\/[a-z]{2}(\/|$)/, '/').replace(/\/$/, '') || '/';
|
||||
---
|
||||
|
||||
<div class="relative inline-block text-left">
|
||||
<LanguageSelector />
|
||||
<div class="relative inline-block text-left" id="language-switcher">
|
||||
<button
|
||||
type="button"
|
||||
class="inline-flex items-center justify-center p-2 rounded-md text-muted-foreground hover:text-foreground hover:bg-accent focus:outline-none focus:ring-2 focus:ring-primary"
|
||||
id="language-menu-button"
|
||||
aria-expanded="false"
|
||||
aria-haspopup="true"
|
||||
>
|
||||
<span class="mr-2">{languages[currentLang]?.flag || '🌐'}</span>
|
||||
<span class="hidden sm:inline">{languages[currentLang]?.name || 'Language'}</span>
|
||||
<svg class="ml-1 h-4 w-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7"/>
|
||||
</svg>
|
||||
</button>
|
||||
|
||||
<div
|
||||
class="hidden absolute right-0 z-10 mt-2 w-48 origin-top-right rounded-md bg-background shadow-lg ring-1 ring-border"
|
||||
id="language-menu"
|
||||
role="menu"
|
||||
aria-orientation="vertical"
|
||||
aria-labelledby="language-menu-button"
|
||||
>
|
||||
<div class="py-1" role="none">
|
||||
{Object.entries(languages).map(([lang, { name, flag }]) => (
|
||||
<a
|
||||
href={localizePath(basePath, lang as any)}
|
||||
class={`flex items-center px-4 py-2 text-sm hover:bg-accent transition-colors ${
|
||||
lang === currentLang ? 'bg-accent text-foreground font-medium' : 'text-muted-foreground'
|
||||
}`}
|
||||
role="menuitem"
|
||||
>
|
||||
<span class="mr-3">{flag}</span>
|
||||
{name}
|
||||
</a>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
:global(.language-selector-wrapper) {
|
||||
@apply relative;
|
||||
}
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
const button = document.getElementById('language-menu-button');
|
||||
const menu = document.getElementById('language-menu');
|
||||
|
||||
:global(.language-selector) {
|
||||
@apply inline-flex items-center justify-center p-2 rounded-md text-muted-foreground hover:text-foreground hover:bg-accent focus:outline-none focus:ring-2 focus:ring-primary;
|
||||
}
|
||||
if (button && menu) {
|
||||
button.addEventListener('click', () => {
|
||||
const isExpanded = button.getAttribute('aria-expanded') === 'true';
|
||||
button.setAttribute('aria-expanded', (!isExpanded).toString());
|
||||
menu.classList.toggle('hidden');
|
||||
});
|
||||
|
||||
:global(.language-selector-flag) {
|
||||
@apply mr-2;
|
||||
}
|
||||
</style>
|
||||
// Close menu when clicking outside
|
||||
document.addEventListener('click', (e) => {
|
||||
if (!button?.contains(e.target as Node) && !menu?.contains(e.target as Node)) {
|
||||
button?.setAttribute('aria-expanded', 'false');
|
||||
menu?.classList.add('hidden');
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
</script>
|
@@ -1,6 +1,9 @@
|
||||
---
|
||||
import { SERVICES } from '@config';
|
||||
import { t } from '../utils/i18n';
|
||||
import { getLangFromUrl, useTranslations, localizePath } from '../utils/i18n';
|
||||
|
||||
const lang = getLangFromUrl(Astro.url);
|
||||
const t = await useTranslations(lang);
|
||||
---
|
||||
|
||||
<section id="services" class="py-20 bg-muted/30">
|
||||
@@ -52,7 +55,7 @@ import { t } from '../utils/i18n';
|
||||
<!-- Learn more link -->
|
||||
<div class="mt-6">
|
||||
<a
|
||||
href={`/services#${service.id}`}
|
||||
href={localizePath(`/services#${service.id}`, lang)}
|
||||
class="inline-flex items-center text-primary hover:text-primary/80 font-medium text-sm group-hover:translate-x-1 transition-all duration-200"
|
||||
>
|
||||
Learn more
|
||||
@@ -68,7 +71,7 @@ import { t } from '../utils/i18n';
|
||||
<!-- CTA section -->
|
||||
<div class="text-center animate-on-scroll">
|
||||
<a
|
||||
href="/services"
|
||||
href={localizePath("/services", lang)}
|
||||
class="btn-primary px-8 py-4 text-lg font-semibold rounded-xl shadow-lg hover:shadow-xl transition-all duration-300 hover:scale-105 inline-flex items-center group"
|
||||
>
|
||||
{t('services.viewAll')}
|
||||
@@ -78,4 +81,4 @@ import { t } from '../utils/i18n';
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</section>
|
@@ -1,6 +1,9 @@
|
||||
---
|
||||
import { TESTIMONIALS } from '../site.config';
|
||||
import { t } from '../utils/i18n';
|
||||
import { getLangFromUrl, useTranslations } from '../utils/i18n';
|
||||
|
||||
const lang = getLangFromUrl(Astro.url);
|
||||
const t = await useTranslations(lang);
|
||||
---
|
||||
|
||||
<section class="py-20 bg-background">
|
||||
@@ -76,4 +79,4 @@ import { t } from '../utils/i18n';
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</section>
|
10
src/content/config.ts
Normal file
10
src/content/config.ts
Normal file
@@ -0,0 +1,10 @@
|
||||
import { defineCollection, z } from 'astro:content';
|
||||
|
||||
const i18n = defineCollection({
|
||||
type: 'data',
|
||||
schema: z.record(z.string(), z.any())
|
||||
});
|
||||
|
||||
export const collections = {
|
||||
i18n
|
||||
};
|
156
src/content/i18n/de.json
Normal file
156
src/content/i18n/de.json
Normal file
@@ -0,0 +1,156 @@
|
||||
{
|
||||
"meta": {
|
||||
"title": "Tiber365 - Professionelle IT-Services",
|
||||
"description": "Professionelle IT-Services für Freelancer und kleine Unternehmen. Microsoft 365 Support, Netzwerklösungen, Webhosting und maßgeschneiderte IT-Projekte.",
|
||||
"keywords": "IT-Services, Microsoft 365, Netzwerk, Webhosting, Automatisierung, IT für kleine Unternehmen"
|
||||
},
|
||||
"nav": {
|
||||
"home": "Startseite",
|
||||
"services": "Dienstleistungen",
|
||||
"about": "Über uns",
|
||||
"contact": "Kontakt",
|
||||
"blog": "Blog",
|
||||
"support": "Support",
|
||||
"language": "Sprache",
|
||||
"theme": {
|
||||
"toggle": "Theme wechseln"
|
||||
}
|
||||
},
|
||||
"hero": {
|
||||
"title": "Professionelle IT-Services für Ihr Unternehmen",
|
||||
"subtitle": "Wir unterstützen Freelancer und kleine Unternehmen mit zuverlässigem Microsoft 365 Support, Netzwerklösungen, Webhosting und maßgeschneiderten IT-Projekten.",
|
||||
"trusted": "Vertraut von Unternehmen in ganz Italien",
|
||||
"cta": {
|
||||
"primary": "Heute starten",
|
||||
"secondary": "Unsere Services ansehen"
|
||||
}
|
||||
},
|
||||
"services": {
|
||||
"title": "Unsere Dienstleistungen",
|
||||
"subtitle": "Umfassende IT-Lösungen maßgeschneidert für kleine Unternehmen und Freelancer",
|
||||
"viewAll": "Alle Services anzeigen",
|
||||
"microsoft365": {
|
||||
"title": "Microsoft 365 Support",
|
||||
"description": "Komplette Microsoft 365 Einrichtung, Migration und fortlaufender Support für Ihr Unternehmen.",
|
||||
"features": {
|
||||
"migrations": "E-Mail & Daten-Migrationen",
|
||||
"apps": "Office Apps Konfiguration",
|
||||
"teams": "Microsoft Teams Einrichtung",
|
||||
"sharepoint": "SharePoint Zusammenarbeit",
|
||||
"admin": "Admin-Portal Verwaltung"
|
||||
}
|
||||
},
|
||||
"management": {
|
||||
"title": "Vollständiges M365 Management",
|
||||
"description": "Lassen Sie uns Ihre gesamte Microsoft 365 Umgebung mit proaktivem Management verwalten.",
|
||||
"features": {
|
||||
"automation": "Automatisierte Workflows",
|
||||
"monitoring": "24/7 System-Überwachung",
|
||||
"maintenance": "Regelmäßige Wartung",
|
||||
"optimization": "Leistungsoptimierung"
|
||||
}
|
||||
},
|
||||
"networking": {
|
||||
"title": "Netzwerk & Infrastruktur",
|
||||
"description": "Professionelle Netzwerklösungen mit Ubiquiti und UniFi Geräten.",
|
||||
"features": {
|
||||
"ubiquiti": "Ubiquiti/UniFi Spezialisten",
|
||||
"infrastructure": "Netzwerk-Infrastruktur",
|
||||
"security": "Netzwerk-Sicherheit",
|
||||
"monitoring": "Verkehrs-Überwachung"
|
||||
}
|
||||
},
|
||||
"hosting": {
|
||||
"title": "Webhosting & Verwaltung",
|
||||
"description": "Zuverlässiges Webhosting mit vollständiger Verwaltung und Wartung inklusive.",
|
||||
"features": {
|
||||
"webhosting": "Zuverlässiges Webhosting",
|
||||
"domains": "Domain-Verwaltung",
|
||||
"ssl": "SSL-Zertifikate",
|
||||
"backup": "Automatisierte Backups"
|
||||
}
|
||||
},
|
||||
"custom": {
|
||||
"title": "Maßgeschneiderte IT-Projekte",
|
||||
"description": "Maßgeschneiderte IT-Lösungen speziell für Ihre Geschäftsanforderungen entwickelt.",
|
||||
"features": {
|
||||
"consultation": "IT-Beratung",
|
||||
"development": "Individuelle Entwicklung",
|
||||
"integration": "System-Integration",
|
||||
"support": "Fortlaufender Support"
|
||||
}
|
||||
}
|
||||
},
|
||||
"testimonials": {
|
||||
"title": "Was unsere Kunden sagen",
|
||||
"subtitle": "Glauben Sie nicht nur uns - sehen Sie, was unsere zufriedenen Kunden zu sagen haben",
|
||||
"1": {
|
||||
"name": "Marco Rossi",
|
||||
"company": "Freelance Designer",
|
||||
"content": "Tiber365 hat unsere Microsoft 365 Einrichtung transformiert. Professioneller Service und exzellenter Support!"
|
||||
},
|
||||
"2": {
|
||||
"name": "Sofia Bianchi",
|
||||
"company": "Kleinunternehmerin",
|
||||
"content": "Ihre Netzwerklösungen sind erstklassig. Unser Büro läuft dank ihrer Expertise reibungslos."
|
||||
},
|
||||
"3": {
|
||||
"name": "Giuseppe Verdi",
|
||||
"company": "Berater",
|
||||
"content": "Zuverlässiges Webhosting und großartiger Kundenservice. Kann Tiber365 wärmstens empfehlen!"
|
||||
}
|
||||
},
|
||||
"about": {
|
||||
"title": "Über uns",
|
||||
"subtitle": "Ihr vertrauensvoller IT-Partner",
|
||||
"description": "Wir sind spezialisiert auf umfassende IT-Services für Freelancer und kleine Unternehmen.",
|
||||
"mission": "Unsere Mission ist es, Technologie für Sie arbeiten zu lassen, nicht gegen Sie.",
|
||||
"experience": "Jahre Erfahrung",
|
||||
"clients": "Zufriedene Kunden",
|
||||
"projects": "Abgeschlossene Projekte"
|
||||
},
|
||||
"blog": {
|
||||
"title": "Blog",
|
||||
"description": "Neueste Erkenntnisse, Tipps und Updates aus der Welt der IT und Microsoft 365",
|
||||
"readMore": "Weiterlesen",
|
||||
"backToBlog": "Zurück zum Blog",
|
||||
"error": "Entschuldigung, wir konnten die Blog-Beiträge nicht laden. Bitte versuchen Sie es später erneut.",
|
||||
"noPosts": "Keine Blog-Beiträge gefunden."
|
||||
},
|
||||
"contact": {
|
||||
"title": "Kontakt aufnehmen",
|
||||
"subtitle": "Bereit, Ihre IT-Infrastruktur zu transformieren? Lassen Sie uns sprechen!",
|
||||
"info": {
|
||||
"email": "info@tiber365.it",
|
||||
"phone": "+39 123 456 7890",
|
||||
"address": "Rom, Italien"
|
||||
},
|
||||
"form": {
|
||||
"name": "Name",
|
||||
"email": "E-Mail",
|
||||
"company": "Unternehmen",
|
||||
"service": "Service",
|
||||
"message": "Nachricht",
|
||||
"send": "Nachricht senden"
|
||||
}
|
||||
},
|
||||
"cta": {
|
||||
"title": "Bereit zu starten?",
|
||||
"subtitle": "Lassen Sie uns besprechen, wie wir Ihre IT-Infrastruktur transformieren können.",
|
||||
"button": "Heute kontaktieren"
|
||||
},
|
||||
"footer": {
|
||||
"description": "Professionelle IT-Services für Freelancer und kleine Unternehmen.",
|
||||
"copyright": "© 2024 Tiber365. Alle Rechte vorbehalten.",
|
||||
"links": {
|
||||
"contact": "Kontakt",
|
||||
"privacy": "Datenschutz",
|
||||
"terms": "Nutzungsbedingungen"
|
||||
}
|
||||
},
|
||||
"404": {
|
||||
"title": "Seite nicht gefunden",
|
||||
"description": "Entschuldigung, wir konnten die gesuchte Seite nicht finden.",
|
||||
"button": "Zur Startseite"
|
||||
}
|
||||
}
|
156
src/content/i18n/en.json
Normal file
156
src/content/i18n/en.json
Normal file
@@ -0,0 +1,156 @@
|
||||
{
|
||||
"site": {
|
||||
"title": "Tiber365",
|
||||
"description": "Your trusted partner in digital transformation"
|
||||
},
|
||||
"nav": {
|
||||
"home": "Home",
|
||||
"about": "About",
|
||||
"services": "Services",
|
||||
"blog": "Blog",
|
||||
"support": "Support",
|
||||
"contact": "Contact"
|
||||
},
|
||||
"meta": {
|
||||
"title": "Tiber365",
|
||||
"description": "Your trusted partner in digital transformation",
|
||||
"keywords": "digital transformation, IT services, consulting"
|
||||
},
|
||||
"hero": {
|
||||
"title": "Professional IT Services for Your Business",
|
||||
"subtitle": "Empowering freelancers and small businesses with reliable Microsoft 365 support, networking solutions, web hosting, and custom IT projects.",
|
||||
"trusted": "Trusted by businesses across Italy",
|
||||
"cta": {
|
||||
"primary": "Get Started Today",
|
||||
"secondary": "View Our Services"
|
||||
}
|
||||
},
|
||||
"services": {
|
||||
"title": "Our Services",
|
||||
"subtitle": "Comprehensive IT solutions tailored for small businesses and freelancers",
|
||||
"viewAll": "View All Services",
|
||||
"microsoft365": {
|
||||
"title": "Microsoft 365 Support",
|
||||
"description": "Complete Microsoft 365 setup, migration, and ongoing support for your business.",
|
||||
"features": {
|
||||
"migrations": "Email & data migrations",
|
||||
"apps": "Office apps configuration",
|
||||
"teams": "Microsoft Teams setup",
|
||||
"sharepoint": "SharePoint collaboration",
|
||||
"admin": "Admin portal management"
|
||||
}
|
||||
},
|
||||
"management": {
|
||||
"title": "Full M365 Management",
|
||||
"description": "Let us handle your entire Microsoft 365 environment with proactive management.",
|
||||
"features": {
|
||||
"automation": "Automated workflows",
|
||||
"monitoring": "24/7 system monitoring",
|
||||
"maintenance": "Regular maintenance",
|
||||
"optimization": "Performance optimization"
|
||||
}
|
||||
},
|
||||
"networking": {
|
||||
"title": "Networking & Infrastructure",
|
||||
"description": "Professional networking solutions using Ubiquiti and UniFi equipment.",
|
||||
"features": {
|
||||
"ubiquiti": "Ubiquiti/UniFi specialists",
|
||||
"infrastructure": "Network infrastructure",
|
||||
"security": "Network security",
|
||||
"monitoring": "Traffic monitoring"
|
||||
}
|
||||
},
|
||||
"hosting": {
|
||||
"title": "Web Hosting & Management",
|
||||
"description": "Reliable web hosting with full management and maintenance included.",
|
||||
"features": {
|
||||
"webhosting": "Reliable web hosting",
|
||||
"domains": "Domain management",
|
||||
"ssl": "SSL certificates",
|
||||
"backup": "Automated backups"
|
||||
}
|
||||
},
|
||||
"custom": {
|
||||
"title": "Custom IT Projects",
|
||||
"description": "Tailored IT solutions designed specifically for your business needs.",
|
||||
"features": {
|
||||
"consultation": "IT consultation",
|
||||
"development": "Custom development",
|
||||
"integration": "System integration",
|
||||
"support": "Ongoing support"
|
||||
}
|
||||
}
|
||||
},
|
||||
"testimonials": {
|
||||
"title": "What Our Clients Say",
|
||||
"subtitle": "Don't just take our word for it - see what our satisfied clients have to say",
|
||||
"1": {
|
||||
"name": "Marco Rossi",
|
||||
"company": "Freelance Designer",
|
||||
"content": "Tiber365 transformed our Microsoft 365 setup. Professional service and excellent support!"
|
||||
},
|
||||
"2": {
|
||||
"name": "Sofia Bianchi",
|
||||
"company": "Small Business Owner",
|
||||
"content": "Their networking solutions are top-notch. Our office runs smoothly thanks to their expertise."
|
||||
},
|
||||
"3": {
|
||||
"name": "Giuseppe Verdi",
|
||||
"company": "Consultant",
|
||||
"content": "Reliable web hosting and great customer service. Highly recommend Tiber365!"
|
||||
}
|
||||
},
|
||||
"about": {
|
||||
"title": "About Us",
|
||||
"subtitle": "Your trusted IT partner",
|
||||
"description": "We specialize in providing comprehensive IT services to freelancers and small businesses.",
|
||||
"mission": "Our mission is to make technology work for you, not against you.",
|
||||
"experience": "Years of Experience",
|
||||
"clients": "Happy Clients",
|
||||
"projects": "Projects Completed"
|
||||
},
|
||||
"blog": {
|
||||
"title": "Blog",
|
||||
"description": "Latest insights, tips, and updates from the world of IT and Microsoft 365",
|
||||
"readMore": "Read more",
|
||||
"backToBlog": "Back to Blog",
|
||||
"error": "Sorry, we couldn't load the blog posts at this time. Please try again later.",
|
||||
"noPosts": "No blog posts found."
|
||||
},
|
||||
"contact": {
|
||||
"title": "Get In Touch",
|
||||
"subtitle": "Ready to transform your IT infrastructure? Let's talk!",
|
||||
"info": {
|
||||
"email": "info@tiber365.it",
|
||||
"phone": "+39 123 456 7890",
|
||||
"address": "Rome, Italy"
|
||||
},
|
||||
"form": {
|
||||
"name": "Name",
|
||||
"email": "Email",
|
||||
"company": "Company",
|
||||
"service": "Service",
|
||||
"message": "Message",
|
||||
"send": "Send Message"
|
||||
}
|
||||
},
|
||||
"cta": {
|
||||
"title": "Ready to Get Started?",
|
||||
"subtitle": "Let's discuss how we can help transform your IT infrastructure.",
|
||||
"button": "Contact Us Today"
|
||||
},
|
||||
"footer": {
|
||||
"description": "Professional IT services for freelancers and small businesses.",
|
||||
"copyright": "© 2024 Tiber365. All rights reserved.",
|
||||
"links": {
|
||||
"contact": "Contact",
|
||||
"privacy": "Privacy Policy",
|
||||
"terms": "Terms of Service"
|
||||
}
|
||||
},
|
||||
"404": {
|
||||
"title": "Page Not Found",
|
||||
"description": "Sorry, we couldn't find the page you're looking for.",
|
||||
"button": "Go back home"
|
||||
}
|
||||
}
|
156
src/content/i18n/fr.json
Normal file
156
src/content/i18n/fr.json
Normal file
@@ -0,0 +1,156 @@
|
||||
{
|
||||
"meta": {
|
||||
"title": "Tiber365 - Services IT Professionnels",
|
||||
"description": "Services IT professionnels pour freelances et petites entreprises. Support Microsoft 365, solutions réseau, hébergement web et projets IT personnalisés.",
|
||||
"keywords": "services IT, Microsoft 365, réseau, hébergement web, automatisation, IT petites entreprises"
|
||||
},
|
||||
"nav": {
|
||||
"home": "Accueil",
|
||||
"services": "Services",
|
||||
"about": "À propos",
|
||||
"contact": "Contact",
|
||||
"blog": "Blog",
|
||||
"support": "Support",
|
||||
"language": "Langue",
|
||||
"theme": {
|
||||
"toggle": "Changer le thème"
|
||||
}
|
||||
},
|
||||
"hero": {
|
||||
"title": "Services IT Professionnels pour Votre Entreprise",
|
||||
"subtitle": "Nous aidons les freelances et petites entreprises avec un support Microsoft 365 fiable, des solutions réseau, de l'hébergement web et des projets IT personnalisés.",
|
||||
"trusted": "Fait confiance par les entreprises à travers l'Italie",
|
||||
"cta": {
|
||||
"primary": "Commencer Aujourd'hui",
|
||||
"secondary": "Voir Nos Services"
|
||||
}
|
||||
},
|
||||
"services": {
|
||||
"title": "Nos Services",
|
||||
"subtitle": "Solutions IT complètes adaptées aux petites entreprises et freelances",
|
||||
"viewAll": "Voir Tous les Services",
|
||||
"microsoft365": {
|
||||
"title": "Support Microsoft 365",
|
||||
"description": "Configuration complète Microsoft 365, migration et support continu pour votre entreprise.",
|
||||
"features": {
|
||||
"migrations": "Migrations email et données",
|
||||
"apps": "Configuration des apps Office",
|
||||
"teams": "Configuration Microsoft Teams",
|
||||
"sharepoint": "Collaboration SharePoint",
|
||||
"admin": "Gestion portail admin"
|
||||
}
|
||||
},
|
||||
"management": {
|
||||
"title": "Gestion Complète M365",
|
||||
"description": "Laissez-nous gérer votre environnement Microsoft 365 complet avec une gestion proactive.",
|
||||
"features": {
|
||||
"automation": "Workflows automatisés",
|
||||
"monitoring": "Surveillance système 24/7",
|
||||
"maintenance": "Maintenance régulière",
|
||||
"optimization": "Optimisation des performances"
|
||||
}
|
||||
},
|
||||
"networking": {
|
||||
"title": "Réseau et Infrastructure",
|
||||
"description": "Solutions réseau professionnelles avec équipements Ubiquiti et UniFi.",
|
||||
"features": {
|
||||
"ubiquiti": "Spécialistes Ubiquiti/UniFi",
|
||||
"infrastructure": "Infrastructure réseau",
|
||||
"security": "Sécurité réseau",
|
||||
"monitoring": "Surveillance du trafic"
|
||||
}
|
||||
},
|
||||
"hosting": {
|
||||
"title": "Hébergement Web et Gestion",
|
||||
"description": "Hébergement web fiable avec gestion complète et maintenance incluse.",
|
||||
"features": {
|
||||
"webhosting": "Hébergement web fiable",
|
||||
"domains": "Gestion de domaines",
|
||||
"ssl": "Certificats SSL",
|
||||
"backup": "Sauvegardes automatisées"
|
||||
}
|
||||
},
|
||||
"custom": {
|
||||
"title": "Projets IT Personnalisés",
|
||||
"description": "Solutions IT sur mesure conçues spécifiquement pour vos besoins d'entreprise.",
|
||||
"features": {
|
||||
"consultation": "Consultation IT",
|
||||
"development": "Développement personnalisé",
|
||||
"integration": "Intégration système",
|
||||
"support": "Support continu"
|
||||
}
|
||||
}
|
||||
},
|
||||
"testimonials": {
|
||||
"title": "Ce Que Disent Nos Clients",
|
||||
"subtitle": "Ne nous croyez pas sur parole - voyez ce que nos clients satisfaits ont à dire",
|
||||
"1": {
|
||||
"name": "Marco Rossi",
|
||||
"company": "Designer Freelance",
|
||||
"content": "Tiber365 a transformé notre configuration Microsoft 365. Service professionnel et excellent support !"
|
||||
},
|
||||
"2": {
|
||||
"name": "Sofia Bianchi",
|
||||
"company": "Propriétaire de Petite Entreprise",
|
||||
"content": "Leurs solutions réseau sont de premier ordre. Notre bureau fonctionne parfaitement grâce à leur expertise."
|
||||
},
|
||||
"3": {
|
||||
"name": "Giuseppe Verdi",
|
||||
"company": "Consultant",
|
||||
"content": "Hébergement web fiable et excellent service client. Je recommande vivement Tiber365 !"
|
||||
}
|
||||
},
|
||||
"about": {
|
||||
"title": "À Propos",
|
||||
"subtitle": "Votre partenaire IT de confiance",
|
||||
"description": "Nous nous spécialisons dans la fourniture de services IT complets aux freelances et petites entreprises.",
|
||||
"mission": "Notre mission est de faire fonctionner la technologie pour vous, pas contre vous.",
|
||||
"experience": "Années d'Expérience",
|
||||
"clients": "Clients Satisfaits",
|
||||
"projects": "Projets Terminés"
|
||||
},
|
||||
"blog": {
|
||||
"title": "Blog",
|
||||
"description": "Dernières actualités, conseils et mises à jour du monde de l'IT et Microsoft 365",
|
||||
"readMore": "Lire la suite",
|
||||
"backToBlog": "Retour au Blog",
|
||||
"error": "Désolé, nous n'avons pas pu charger les articles du blog. Veuillez réessayer plus tard.",
|
||||
"noPosts": "Aucun article de blog trouvé."
|
||||
},
|
||||
"contact": {
|
||||
"title": "Prendre Contact",
|
||||
"subtitle": "Prêt à transformer votre infrastructure IT ? Parlons-en !",
|
||||
"info": {
|
||||
"email": "info@tiber365.it",
|
||||
"phone": "+39 123 456 7890",
|
||||
"address": "Rome, Italie"
|
||||
},
|
||||
"form": {
|
||||
"name": "Nom",
|
||||
"email": "Email",
|
||||
"company": "Entreprise",
|
||||
"service": "Service",
|
||||
"message": "Message",
|
||||
"send": "Envoyer le Message"
|
||||
}
|
||||
},
|
||||
"cta": {
|
||||
"title": "Prêt à Commencer ?",
|
||||
"subtitle": "Discutons de la façon dont nous pouvons transformer votre infrastructure IT.",
|
||||
"button": "Nous Contacter Aujourd'hui"
|
||||
},
|
||||
"footer": {
|
||||
"description": "Services IT professionnels pour freelances et petites entreprises.",
|
||||
"copyright": "© 2024 Tiber365. Tous droits réservés.",
|
||||
"links": {
|
||||
"contact": "Contact",
|
||||
"privacy": "Politique de Confidentialité",
|
||||
"terms": "Conditions de Service"
|
||||
}
|
||||
},
|
||||
"404": {
|
||||
"title": "Page Non Trouvée",
|
||||
"description": "Désolé, nous n'avons pas pu trouver la page que vous recherchez.",
|
||||
"button": "Retour à l'accueil"
|
||||
}
|
||||
}
|
160
src/content/i18n/nl.json
Normal file
160
src/content/i18n/nl.json
Normal file
@@ -0,0 +1,160 @@
|
||||
{
|
||||
"site": {
|
||||
"title": "Tiber365 - Professionele IT Services",
|
||||
"description": "Professionele IT-diensten voor freelancers en kleine bedrijven. Microsoft 365 ondersteuning, netwerkoplossingen, webhosting en aangepaste IT-projecten."
|
||||
},
|
||||
"meta": {
|
||||
"title": "Tiber365 - Professionele IT Services",
|
||||
"description": "Professionele IT-diensten voor freelancers en kleine bedrijven. Microsoft 365 ondersteuning, netwerkoplossingen, webhosting en aangepaste IT-projecten.",
|
||||
"keywords": "IT diensten, Microsoft 365, netwerken, webhosting, automatisering, kleine bedrijven IT"
|
||||
},
|
||||
"nav": {
|
||||
"home": "Home",
|
||||
"services": "Diensten",
|
||||
"about": "Over Ons",
|
||||
"contact": "Contact",
|
||||
"blog": "Blog",
|
||||
"support": "Ondersteuning",
|
||||
"language": "Taal",
|
||||
"theme": {
|
||||
"toggle": "Thema wisselen"
|
||||
}
|
||||
},
|
||||
"hero": {
|
||||
"title": "Professionele IT Services voor Uw Bedrijf",
|
||||
"subtitle": "Ondersteuning van freelancers en kleine bedrijven met betrouwbare Microsoft 365 ondersteuning, netwerkoplossingen, webhosting en aangepaste IT-projecten.",
|
||||
"trusted": "Vertrouwd door bedrijven in heel Italië",
|
||||
"cta": {
|
||||
"primary": "Begin Vandaag",
|
||||
"secondary": "Bekijk Onze Diensten"
|
||||
}
|
||||
},
|
||||
"services": {
|
||||
"title": "Onze Diensten",
|
||||
"subtitle": "Uitgebreide IT-oplossingen op maat voor kleine bedrijven en freelancers",
|
||||
"viewAll": "Alle Diensten Bekijken",
|
||||
"microsoft365": {
|
||||
"title": "Microsoft 365 Ondersteuning",
|
||||
"description": "Complete Microsoft 365 installatie, migratie en doorlopende ondersteuning.",
|
||||
"features": {
|
||||
"migrations": "E-mail & data migraties",
|
||||
"apps": "Office apps configuratie",
|
||||
"teams": "Microsoft Teams installatie",
|
||||
"sharepoint": "SharePoint samenwerking",
|
||||
"admin": "Beheerportaal management"
|
||||
}
|
||||
},
|
||||
"management": {
|
||||
"title": "Volledig M365 Beheer",
|
||||
"description": "Laat ons uw volledige Microsoft 365 omgeving beheren met proactief management.",
|
||||
"features": {
|
||||
"automation": "Geautomatiseerde workflows",
|
||||
"monitoring": "24/7 systeembewaking",
|
||||
"maintenance": "Regelmatig onderhoud",
|
||||
"optimization": "Prestatie optimalisatie"
|
||||
}
|
||||
},
|
||||
"networking": {
|
||||
"title": "Netwerken & Infrastructuur",
|
||||
"description": "Professionele netwerkoplossingen met Ubiquiti en UniFi apparatuur.",
|
||||
"features": {
|
||||
"ubiquiti": "Ubiquiti/UniFi specialisten",
|
||||
"infrastructure": "Netwerkinfrastructuur",
|
||||
"security": "Netwerkbeveiliging",
|
||||
"monitoring": "Verkeer monitoring"
|
||||
}
|
||||
},
|
||||
"hosting": {
|
||||
"title": "Webhosting & Beheer",
|
||||
"description": "Betrouwbare webhosting met volledig beheer en onderhoud inbegrepen.",
|
||||
"features": {
|
||||
"webhosting": "Betrouwbare webhosting",
|
||||
"domains": "Domeinbeheer",
|
||||
"ssl": "SSL certificaten",
|
||||
"backup": "Geautomatiseerde backups"
|
||||
}
|
||||
},
|
||||
"custom": {
|
||||
"title": "Aangepaste IT Projecten",
|
||||
"description": "Op maat gemaakte IT-oplossingen speciaal ontworpen voor uw bedrijfsbehoeften.",
|
||||
"features": {
|
||||
"consultation": "IT consultatie",
|
||||
"development": "Aangepaste ontwikkeling",
|
||||
"integration": "Systeemintegratie",
|
||||
"support": "Doorlopende ondersteuning"
|
||||
}
|
||||
}
|
||||
},
|
||||
"testimonials": {
|
||||
"title": "Wat Onze Klanten Zeggen",
|
||||
"subtitle": "Geloof ons niet zomaar - zie wat onze tevreden klanten te zeggen hebben",
|
||||
"1": {
|
||||
"name": "Marco Rossi",
|
||||
"company": "Freelance Designer",
|
||||
"content": "Tiber365 heeft onze Microsoft 365 installatie getransformeerd. Professionele service en uitstekende ondersteuning!"
|
||||
},
|
||||
"2": {
|
||||
"name": "Sofia Bianchi",
|
||||
"company": "Kleine Bedrijfseigenaar",
|
||||
"content": "Hun netwerkoplossingen zijn eersteklas. Ons kantoor draait soepel dankzij hun expertise."
|
||||
},
|
||||
"3": {
|
||||
"name": "Giuseppe Verdi",
|
||||
"company": "Consultant",
|
||||
"content": "Betrouwbare webhosting en geweldige klantenservice. Beveel Tiber365 ten zeerste aan!"
|
||||
}
|
||||
},
|
||||
"about": {
|
||||
"title": "Over Ons",
|
||||
"subtitle": "Uw vertrouwde IT-partner",
|
||||
"description": "Wij zijn gespecialiseerd in het leveren van uitgebreide IT-diensten aan freelancers en kleine bedrijven.",
|
||||
"mission": "Onze missie is om technologie voor u te laten werken, niet tegen u.",
|
||||
"experience": "Jaren Ervaring",
|
||||
"clients": "Tevreden Klanten",
|
||||
"projects": "Voltooide Projecten"
|
||||
},
|
||||
"blog": {
|
||||
"title": "Blog",
|
||||
"description": "Laatste inzichten, tips en updates uit de wereld van IT en Microsoft 365",
|
||||
"readMore": "Lees meer",
|
||||
"backToBlog": "Terug naar Blog",
|
||||
"error": "Sorry, we konden de blogberichten niet laden. Probeer het later opnieuw.",
|
||||
"noPosts": "Geen blogberichten gevonden."
|
||||
},
|
||||
"contact": {
|
||||
"title": "Neem Contact Op",
|
||||
"subtitle": "Klaar om uw IT-infrastructuur te transformeren? Laten we praten!",
|
||||
"info": {
|
||||
"email": "info@tiber365.it",
|
||||
"phone": "+39 123 456 7890",
|
||||
"address": "Rome, Italië"
|
||||
},
|
||||
"form": {
|
||||
"name": "Naam",
|
||||
"email": "E-mail",
|
||||
"company": "Bedrijf",
|
||||
"service": "Dienst",
|
||||
"message": "Bericht",
|
||||
"send": "Bericht Versturen"
|
||||
}
|
||||
},
|
||||
"cta": {
|
||||
"title": "Klaar om te Beginnen?",
|
||||
"subtitle": "Laten we bespreken hoe wij uw IT-infrastructuur kunnen transformeren.",
|
||||
"button": "Neem Vandaag Contact Op"
|
||||
},
|
||||
"footer": {
|
||||
"description": "Professionele IT-diensten voor freelancers en kleine bedrijven.",
|
||||
"copyright": "© 2024 Tiber365. Alle rechten voorbehouden.",
|
||||
"links": {
|
||||
"contact": "Contact",
|
||||
"privacy": "Privacybeleid",
|
||||
"terms": "Servicevoorwaarden"
|
||||
}
|
||||
},
|
||||
"404": {
|
||||
"title": "Pagina Niet Gevonden",
|
||||
"description": "Sorry, we konden de pagina die u zoekt niet vinden.",
|
||||
"button": "Ga terug naar home"
|
||||
}
|
||||
}
|
@@ -1,8 +1,6 @@
|
||||
---
|
||||
import { SITE } from '../site.config';
|
||||
import i18next, { t } from "i18next";
|
||||
import { Trans, HeadHrefLangs } from "astro-i18next/components";
|
||||
import { localizePath } from "astro-i18next";
|
||||
import { getLangFromUrl, useTranslations } from '../utils/i18n';
|
||||
import '../styles/global.css';
|
||||
|
||||
export interface Props {
|
||||
@@ -10,24 +8,29 @@ export interface Props {
|
||||
description?: string;
|
||||
image?: string;
|
||||
keywords?: string;
|
||||
noindex?: boolean;
|
||||
nofollow?: boolean;
|
||||
}
|
||||
|
||||
const lang = getLangFromUrl(Astro.url);
|
||||
const t = await useTranslations(lang);
|
||||
|
||||
const {
|
||||
title = t('site.title'),
|
||||
description = t('site.description'),
|
||||
image = SITE.ogImage,
|
||||
keywords = t('meta.keywords')
|
||||
keywords = t('meta.keywords'),
|
||||
noindex = false,
|
||||
nofollow = false
|
||||
} = Astro.props;
|
||||
|
||||
const lang = Astro.currentLocale || 'en';
|
||||
|
||||
// Safe URL creation with fallbacks
|
||||
let canonicalURL;
|
||||
let ogImageURL;
|
||||
let twitterImageURL;
|
||||
|
||||
try {
|
||||
const siteURL = Astro.site || new URL('http://localhost:4321');
|
||||
const siteURL = Astro.site || new URL('https://tiber365.it');
|
||||
canonicalURL = new URL(Astro.url.pathname, siteURL);
|
||||
ogImageURL = new URL(image, siteURL);
|
||||
twitterImageURL = new URL(image, siteURL);
|
||||
@@ -41,35 +44,74 @@ try {
|
||||
|
||||
const fullTitle = title === t('site.title') ? title : `${title} | ${t('site.title')}`;
|
||||
|
||||
// Get all available locales
|
||||
const locales = ["en", "nl", "it"];
|
||||
// All available locales
|
||||
const locales = ["en", "nl", "de", "fr"];
|
||||
|
||||
// Generate structured data
|
||||
const structuredData = {
|
||||
"@context": "https://schema.org",
|
||||
"@type": "Organization",
|
||||
"name": t('site.title'),
|
||||
"description": description,
|
||||
"url": SITE.url,
|
||||
"logo": `${SITE.url}/images/TIBER365.png`,
|
||||
"sameAs": [
|
||||
"https://support.tiber365.it"
|
||||
],
|
||||
"contactPoint": {
|
||||
"@type": "ContactPoint",
|
||||
"contactType": "customer service",
|
||||
"availableLanguage": ["English", "Dutch", "German", "French"]
|
||||
},
|
||||
"address": {
|
||||
"@type": "PostalAddress",
|
||||
"addressCountry": "IT"
|
||||
},
|
||||
"serviceArea": {
|
||||
"@type": "Country",
|
||||
"name": "Italy"
|
||||
}
|
||||
};
|
||||
---
|
||||
|
||||
<!doctype html>
|
||||
<html lang={lang} class="scroll-smooth">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="description" content={description} />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<meta name="generator" content={Astro.generator} />
|
||||
|
||||
{keywords && <meta name="keywords" content={keywords} />}
|
||||
<!-- Font Preloading -->
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
|
||||
<link rel="preload" href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&family=Poppins:wght@400;500;600;700&display=swap" as="style" onload="this.onload=null;this.rel='stylesheet'" />
|
||||
<noscript><link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&family=Poppins:wght@400;500;600;700&display=swap" /></noscript>
|
||||
|
||||
<!-- DNS Prefetch -->
|
||||
<link rel="dns-prefetch" href="//fonts.googleapis.com" />
|
||||
<link rel="dns-prefetch" href="//fonts.gstatic.com" />
|
||||
|
||||
<!-- SEO Meta Tags -->
|
||||
<title>{fullTitle}</title>
|
||||
<meta name="description" content={description} />
|
||||
<meta name="keywords" content={keywords} />
|
||||
<meta name="author" content={SITE.author} />
|
||||
|
||||
<!-- Robots Meta -->
|
||||
{noindex && <meta name="robots" content="noindex" />}
|
||||
{nofollow && <meta name="robots" content="nofollow" />}
|
||||
{!noindex && !nofollow && <meta name="robots" content="index, follow" />}
|
||||
|
||||
<!-- Canonical URL -->
|
||||
<link rel="canonical" href={canonicalURL} />
|
||||
|
||||
<!-- Primary Meta Tags -->
|
||||
<title>{fullTitle}</title>
|
||||
<meta name="title" content={fullTitle} />
|
||||
<meta name="description" content={description} />
|
||||
<meta name="author" content={SITE.author} />
|
||||
|
||||
<!-- Prevent automatic language redirects -->
|
||||
<!-- Language and Localization -->
|
||||
<meta name="google" content="notranslate" />
|
||||
<meta http-equiv="Content-Language" content={lang} />
|
||||
|
||||
<!-- Theme Color -->
|
||||
<meta name="theme-color" content="#ffffff" />
|
||||
<meta name="theme-color" content="#ffffff" media="(prefers-color-scheme: light)" />
|
||||
<meta name="theme-color" content="#1f2937" media="(prefers-color-scheme: dark)" />
|
||||
<meta name="msapplication-TileColor" content="#3b82f6" />
|
||||
|
||||
<!-- Open Graph / Facebook -->
|
||||
@@ -78,41 +120,66 @@ const locales = ["en", "nl", "it"];
|
||||
<meta property="og:title" content={fullTitle} />
|
||||
<meta property="og:description" content={description} />
|
||||
<meta property="og:image" content={ogImageURL} />
|
||||
<meta property="og:image:width" content="1200" />
|
||||
<meta property="og:image:height" content="630" />
|
||||
<meta property="og:site_name" content={t('site.title')} />
|
||||
<meta property="og:locale" content={lang === 'en' ? 'en_US' : lang === 'nl' ? 'nl_NL' : 'it_IT'} />
|
||||
<meta property="og:locale" content={lang === 'en' ? 'en_US' : lang === 'nl' ? 'nl_NL' : lang === 'de' ? 'de_DE' : 'fr_FR'} />
|
||||
|
||||
<!-- Twitter -->
|
||||
<meta property="twitter:card" content="summary_large_image" />
|
||||
<meta property="twitter:url" content={canonicalURL} />
|
||||
<meta property="twitter:title" content={fullTitle} />
|
||||
<meta property="twitter:description" content={description} />
|
||||
<meta property="twitter:image" content={twitterImageURL} />
|
||||
<meta name="twitter:card" content="summary_large_image" />
|
||||
<meta name="twitter:url" content={canonicalURL} />
|
||||
<meta name="twitter:title" content={fullTitle} />
|
||||
<meta name="twitter:description" content={description} />
|
||||
<meta name="twitter:image" content={twitterImageURL} />
|
||||
<meta name="twitter:creator" content="@tiber365" />
|
||||
|
||||
<!-- Favicons -->
|
||||
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
|
||||
<link rel="apple-touch-icon" href="/favicon.svg" />
|
||||
<link rel="manifest" href="/manifest.json" />
|
||||
|
||||
<!-- Language alternates -->
|
||||
{locales.map(locale => (
|
||||
<link
|
||||
rel="alternate"
|
||||
hreflang={locale}
|
||||
href={new URL(localizePath(Astro.url.pathname, locale), Astro.site).toString()}
|
||||
/>
|
||||
))}
|
||||
{locales.map(locale => {
|
||||
const currentPath = Astro.url.pathname.replace(/^\/[a-z]{2}\//, '/').replace(/^\/[a-z]{2}$/, '/');
|
||||
const localePath = locale === 'en' ? currentPath : `/${locale}${currentPath}`;
|
||||
const localeUrl = new URL(localePath, SITE.url).toString();
|
||||
return (
|
||||
<link
|
||||
rel="alternate"
|
||||
hreflang={locale}
|
||||
href={localeUrl}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
|
||||
<!-- Structured Data -->
|
||||
<script type="application/ld+json" set:html={JSON.stringify(structuredData)} />
|
||||
</head>
|
||||
<body class="min-h-screen bg-background text-foreground">
|
||||
<slot />
|
||||
|
||||
<!-- Initialize animations -->
|
||||
<!-- Initialize animations and service worker -->
|
||||
<script>
|
||||
import { initScrollAnimations } from '../utils/animations';
|
||||
import { initTheme } from '../utils/theme';
|
||||
import { initPerformanceMonitoring } from '../utils/performance';
|
||||
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
initTheme();
|
||||
initScrollAnimations();
|
||||
initPerformanceMonitoring();
|
||||
|
||||
// Register service worker
|
||||
if ('serviceWorker' in navigator) {
|
||||
navigator.serviceWorker.register('/sw.js')
|
||||
.then((registration) => {
|
||||
console.log('SW registered: ', registration);
|
||||
})
|
||||
.catch((registrationError) => {
|
||||
console.log('SW registration failed: ', registrationError);
|
||||
});
|
||||
}
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
</html>
|
173
src/locales/de.json
Normal file
173
src/locales/de.json
Normal file
@@ -0,0 +1,173 @@
|
||||
{
|
||||
"meta": {
|
||||
"title": "Tiber365 - Professionelle IT-Dienste",
|
||||
"description": "Professionelle IT-Dienste für Freiberufler und kleine Unternehmen. Microsoft 365 Support, Netzwerklösungen, Webhosting und maßgeschneiderte IT-Projekte.",
|
||||
"keywords": "IT-Dienste, Microsoft 365, Netzwerke, Webhosting, Ubiquiti, Unifi, Kleinunternehmen"
|
||||
},
|
||||
"nav": {
|
||||
"home": "Startseite",
|
||||
"services": "Dienste",
|
||||
"about": "Über uns",
|
||||
"blog": "Blog",
|
||||
"support": "Support",
|
||||
"contact": "Kontakt",
|
||||
"language": "Sprache",
|
||||
"theme": {
|
||||
"light": "Heller Modus",
|
||||
"dark": "Dunkler Modus",
|
||||
"toggle": "Theme wechseln"
|
||||
}
|
||||
},
|
||||
"hero": {
|
||||
"title": "Professionelle IT-Dienste für Ihr Unternehmen",
|
||||
"subtitle": "Unterstützung von Freiberuflern und kleinen Unternehmen mit zuverlässigem Microsoft 365 Support, Netzwerklösungen und maßgeschneiderten IT-Projekten.",
|
||||
"cta": {
|
||||
"primary": "Loslegen",
|
||||
"secondary": "Mehr erfahren"
|
||||
},
|
||||
"trusted": "Vertraut von 100+ Unternehmen"
|
||||
},
|
||||
"services": {
|
||||
"title": "Unsere Dienste",
|
||||
"subtitle": "Umfassende IT-Lösungen, die auf Ihre Geschäftsanforderungen zugeschnitten sind",
|
||||
"viewAll": "Alle Dienste anzeigen",
|
||||
"microsoft365": {
|
||||
"title": "Microsoft 365 Support",
|
||||
"description": "Vollständiges Microsoft 365 Management einschließlich E-Mail-Migrationen, Office-Apps, Teams, SharePoint und Admin Center-Konfiguration.",
|
||||
"features": {
|
||||
"migrations": "E-Mail-Migrationen & Setup",
|
||||
"apps": "Office-Anwendungen Support",
|
||||
"teams": "Microsoft Teams Bereitstellung",
|
||||
"sharepoint": "SharePoint-Konfiguration",
|
||||
"admin": "Admin Center Management"
|
||||
}
|
||||
},
|
||||
"management": {
|
||||
"title": "Vollständiges M365 Management",
|
||||
"description": "Umfassendes Microsoft 365 Management und Automatisierung, um Ihr Unternehmen reibungslos am Laufen zu halten.",
|
||||
"features": {
|
||||
"automation": "Workflow-Automatisierung",
|
||||
"monitoring": "Systemüberwachung",
|
||||
"maintenance": "Regelmäßige Wartung",
|
||||
"optimization": "Leistungsoptimierung"
|
||||
}
|
||||
},
|
||||
"networking": {
|
||||
"title": "Netzwerke & Infrastruktur",
|
||||
"description": "Professionelle Netzwerklösungen mit Ubiquiti/Unifi-Geräten für zuverlässige und sichere Konnektivität.",
|
||||
"features": {
|
||||
"ubiquiti": "Ubiquiti/Unifi-Lösungen",
|
||||
"infrastructure": "Netzwerkinfrastruktur",
|
||||
"security": "Netzwerksicherheit",
|
||||
"monitoring": "Netzwerküberwachung"
|
||||
}
|
||||
},
|
||||
"hosting": {
|
||||
"title": "Webhosting & Management",
|
||||
"description": "Zuverlässige Webhosting-Dienste mit vollständigem Website-Management und Wartung.",
|
||||
"features": {
|
||||
"webhosting": "Premium Webhosting",
|
||||
"domains": "Domain-Management",
|
||||
"ssl": "SSL-Zertifikate",
|
||||
"backup": "Automatisierte Backups"
|
||||
}
|
||||
},
|
||||
"custom": {
|
||||
"title": "Maßgeschneiderte IT-Projekte",
|
||||
"description": "Maßgeschneiderte IT-Lösungen und benutzerdefinierte Projekte, die speziell für Ihre Geschäftsanforderungen entwickelt wurden.",
|
||||
"features": {
|
||||
"consultation": "IT-Beratung",
|
||||
"development": "Maßgeschneiderte Entwicklung",
|
||||
"integration": "Systemintegration",
|
||||
"support": "Laufende Unterstützung"
|
||||
}
|
||||
}
|
||||
},
|
||||
"about": {
|
||||
"title": "Über Tiber365",
|
||||
"subtitle": "Ihr vertrauenswürdiger IT-Partner",
|
||||
"description": "Wir sind spezialisiert auf die Bereitstellung umfassender IT-Dienste für Freiberufler und kleine Unternehmen. Unsere Expertise in Microsoft 365, Netzwerken und maßgeschneiderten Lösungen hilft Unternehmen, im digitalen Zeitalter zu florieren.",
|
||||
"mission": "Unsere Mission ist es, IT für kleine Unternehmen und Freiberufler zu vereinfachen, damit sie sich auf das konzentrieren können, was sie am besten können, während wir uns um ihre Technologiebedürfnisse kümmern.",
|
||||
"experience": "Jahre Erfahrung",
|
||||
"clients": "Zufriedene Kunden",
|
||||
"projects": "Abgeschlossene Projekte"
|
||||
},
|
||||
"blog": {
|
||||
"title": "Blog",
|
||||
"description": "Neueste Erkenntnisse, Tipps und Updates aus der Welt der IT und Microsoft 365",
|
||||
"readMore": "Weiterlesen",
|
||||
"backToBlog": "Zurück zum Blog",
|
||||
"error": "Entschuldigung, wir konnten die Blog-Beiträge nicht laden. Bitte versuchen Sie es später erneut.",
|
||||
"noPosts": "Keine Blog-Beiträge gefunden."
|
||||
},
|
||||
"testimonials": {
|
||||
"title": "Was unsere Kunden sagen",
|
||||
"subtitle": "Glauben Sie nicht nur unserem Wort",
|
||||
"1": {
|
||||
"name": "Marco Rossi",
|
||||
"company": "Kreativagentur",
|
||||
"content": "Tiber365 hat unsere IT-Infrastruktur transformiert. Ihr Microsoft 365-Setup war makellos und ihre laufende Unterstützung ist außergewöhnlich."
|
||||
},
|
||||
"2": {
|
||||
"name": "Sarah Johnson",
|
||||
"company": "Beratungsunternehmen",
|
||||
"content": "Professionell, zuverlässig und immer verfügbar, wenn wir sie brauchen. Die Netzwerklösung, die sie implementiert haben, funktioniert perfekt."
|
||||
},
|
||||
"3": {
|
||||
"name": "Andreas van Berg",
|
||||
"company": "Designstudio",
|
||||
"content": "Hervorragender Service und Expertise. Sie kümmern sich um alle unsere IT-Bedürfnisse, damit wir uns auf unsere kreative Arbeit konzentrieren können."
|
||||
}
|
||||
},
|
||||
"contact": {
|
||||
"title": "Kontakt aufnehmen",
|
||||
"subtitle": "Bereit, Ihre IT-Infrastruktur zu verbessern?",
|
||||
"form": {
|
||||
"name": "Name",
|
||||
"email": "E-Mail",
|
||||
"company": "Unternehmen",
|
||||
"service": "Benötigter Service",
|
||||
"message": "Nachricht",
|
||||
"send": "Nachricht senden",
|
||||
"sending": "Wird gesendet...",
|
||||
"success": "Nachricht erfolgreich gesendet!",
|
||||
"error": "Nachricht konnte nicht gesendet werden. Bitte versuchen Sie es erneut."
|
||||
},
|
||||
"info": {
|
||||
"email": "info@tiber365.it",
|
||||
"phone": "+39 123 456 7890",
|
||||
"address": "Italien"
|
||||
}
|
||||
},
|
||||
"cta": {
|
||||
"title": "Bereit loszulegen?",
|
||||
"subtitle": "Lassen Sie uns besprechen, wie wir Ihnen helfen können, Ihre IT-Infrastruktur zu verbessern",
|
||||
"button": "Kostenlose Beratung buchen"
|
||||
},
|
||||
"footer": {
|
||||
"description": "Professionelle IT-Dienste für Freiberufler und kleine Unternehmen.",
|
||||
"links": {
|
||||
"services": "Dienste",
|
||||
"about": "Über uns",
|
||||
"contact": "Kontakt",
|
||||
"privacy": "Datenschutzrichtlinie",
|
||||
"terms": "Nutzungsbedingungen"
|
||||
},
|
||||
"copyright": "© 2024 Tiber365. Alle Rechte vorbehalten."
|
||||
},
|
||||
"privacy": {
|
||||
"title": "Datenschutzrichtlinie",
|
||||
"description": "Erfahren Sie, wie wir Ihre persönlichen Daten schützen",
|
||||
"lastUpdated": "Zuletzt aktualisiert"
|
||||
},
|
||||
"terms": {
|
||||
"title": "Nutzungsbedingungen",
|
||||
"description": "Unsere Servicevereinbarung und rechtliche Bedingungen",
|
||||
"lastUpdated": "Zuletzt aktualisiert"
|
||||
},
|
||||
"404": {
|
||||
"title": "Seite nicht gefunden",
|
||||
"description": "Die gesuchte Seite existiert nicht.",
|
||||
"button": "Zur Startseite"
|
||||
}
|
||||
}
|
@@ -92,6 +92,14 @@
|
||||
"clients": "Happy Clients",
|
||||
"projects": "Completed Projects"
|
||||
},
|
||||
"blog": {
|
||||
"title": "Blog",
|
||||
"description": "Latest insights, tips, and updates from the world of IT and Microsoft 365",
|
||||
"readMore": "Read more",
|
||||
"backToBlog": "Back to Blog",
|
||||
"error": "Sorry, we couldn't load the blog posts at this time. Please try again later.",
|
||||
"noPosts": "No blog posts found."
|
||||
},
|
||||
"testimonials": {
|
||||
"title": "What Our Clients Say",
|
||||
"subtitle": "Don't just take our word for it",
|
||||
|
173
src/locales/fr.json
Normal file
173
src/locales/fr.json
Normal file
@@ -0,0 +1,173 @@
|
||||
{
|
||||
"meta": {
|
||||
"title": "Tiber365 - Services IT Professionnels",
|
||||
"description": "Services IT professionnels pour les freelances et petites entreprises. Support Microsoft 365, solutions réseau, hébergement web et projets IT personnalisés.",
|
||||
"keywords": "services IT, Microsoft 365, réseaux, hébergement web, Ubiquiti, Unifi, petite entreprise"
|
||||
},
|
||||
"nav": {
|
||||
"home": "Accueil",
|
||||
"services": "Services",
|
||||
"about": "À propos",
|
||||
"blog": "Blog",
|
||||
"support": "Support",
|
||||
"contact": "Contact",
|
||||
"language": "Langue",
|
||||
"theme": {
|
||||
"light": "Mode clair",
|
||||
"dark": "Mode sombre",
|
||||
"toggle": "Basculer le thème"
|
||||
}
|
||||
},
|
||||
"hero": {
|
||||
"title": "Services IT Professionnels pour Votre Entreprise",
|
||||
"subtitle": "Accompagner les freelances et petites entreprises avec un support Microsoft 365 fiable, des solutions réseau et des projets IT personnalisés.",
|
||||
"cta": {
|
||||
"primary": "Commencer",
|
||||
"secondary": "En savoir plus"
|
||||
},
|
||||
"trusted": "Fait confiance par 100+ entreprises"
|
||||
},
|
||||
"services": {
|
||||
"title": "Nos Services",
|
||||
"subtitle": "Solutions IT complètes adaptées aux besoins de votre entreprise",
|
||||
"viewAll": "Voir tous les services",
|
||||
"microsoft365": {
|
||||
"title": "Support Microsoft 365",
|
||||
"description": "Gestion complète Microsoft 365 incluant les migrations email, applications Office, Teams, SharePoint et configuration du centre d'administration.",
|
||||
"features": {
|
||||
"migrations": "Migrations email et configuration",
|
||||
"apps": "Support des applications Office",
|
||||
"teams": "Déploiement Microsoft Teams",
|
||||
"sharepoint": "Configuration SharePoint",
|
||||
"admin": "Gestion du centre d'administration"
|
||||
}
|
||||
},
|
||||
"management": {
|
||||
"title": "Gestion M365 Complète",
|
||||
"description": "Gestion et automatisation Microsoft 365 complètes pour maintenir votre entreprise en bon fonctionnement.",
|
||||
"features": {
|
||||
"automation": "Automatisation des workflows",
|
||||
"monitoring": "Surveillance système",
|
||||
"maintenance": "Maintenance régulière",
|
||||
"optimization": "Optimisation des performances"
|
||||
}
|
||||
},
|
||||
"networking": {
|
||||
"title": "Réseaux et Infrastructure",
|
||||
"description": "Solutions réseau professionnelles utilisant l'équipement Ubiquiti/Unifi pour une connectivité fiable et sécurisée.",
|
||||
"features": {
|
||||
"ubiquiti": "Solutions Ubiquiti/Unifi",
|
||||
"infrastructure": "Infrastructure réseau",
|
||||
"security": "Sécurité réseau",
|
||||
"monitoring": "Surveillance réseau"
|
||||
}
|
||||
},
|
||||
"hosting": {
|
||||
"title": "Hébergement Web et Gestion",
|
||||
"description": "Services d'hébergement web fiables avec gestion complète du site web et maintenance.",
|
||||
"features": {
|
||||
"webhosting": "Hébergement web premium",
|
||||
"domains": "Gestion de domaines",
|
||||
"ssl": "Certificats SSL",
|
||||
"backup": "Sauvegardes automatisées"
|
||||
}
|
||||
},
|
||||
"custom": {
|
||||
"title": "Projets IT Personnalisés",
|
||||
"description": "Solutions IT sur mesure et projets personnalisés conçus spécifiquement pour les exigences de votre entreprise.",
|
||||
"features": {
|
||||
"consultation": "Consultation IT",
|
||||
"development": "Développement personnalisé",
|
||||
"integration": "Intégration système",
|
||||
"support": "Support continu"
|
||||
}
|
||||
}
|
||||
},
|
||||
"about": {
|
||||
"title": "À propos de Tiber365",
|
||||
"subtitle": "Votre partenaire IT de confiance",
|
||||
"description": "Nous sommes spécialisés dans la fourniture de services IT complets aux freelances et petites entreprises. Notre expertise en Microsoft 365, réseaux et solutions personnalisées aide les entreprises à prospérer à l'ère numérique.",
|
||||
"mission": "Notre mission est de simplifier l'IT pour les petites entreprises et freelances, leur permettant de se concentrer sur ce qu'ils font de mieux tandis que nous gérons leurs besoins technologiques.",
|
||||
"experience": "Années d'Expérience",
|
||||
"clients": "Clients Satisfaits",
|
||||
"projects": "Projets Terminés"
|
||||
},
|
||||
"blog": {
|
||||
"title": "Blog",
|
||||
"description": "Dernières actualités, conseils et mises à jour du monde de l'IT et Microsoft 365",
|
||||
"readMore": "Lire la suite",
|
||||
"backToBlog": "Retour au Blog",
|
||||
"error": "Désolé, nous n'avons pas pu charger les articles du blog. Veuillez réessayer plus tard.",
|
||||
"noPosts": "Aucun article de blog trouvé."
|
||||
},
|
||||
"testimonials": {
|
||||
"title": "Ce que disent nos clients",
|
||||
"subtitle": "Ne nous croyez pas sur parole",
|
||||
"1": {
|
||||
"name": "Marco Rossi",
|
||||
"company": "Agence Créative",
|
||||
"content": "Tiber365 a transformé notre infrastructure IT. Leur configuration Microsoft 365 était impeccable et leur support continu est exceptionnel."
|
||||
},
|
||||
"2": {
|
||||
"name": "Sarah Johnson",
|
||||
"company": "Cabinet de Conseil",
|
||||
"content": "Professionnels, fiables et toujours disponibles quand nous en avons besoin. La solution réseau qu'ils ont mise en place fonctionne parfaitement."
|
||||
},
|
||||
"3": {
|
||||
"name": "Andreas van Berg",
|
||||
"company": "Studio de Design",
|
||||
"content": "Service et expertise exceptionnels. Ils gèrent tous nos besoins IT pour que nous puissions nous concentrer sur notre travail créatif."
|
||||
}
|
||||
},
|
||||
"contact": {
|
||||
"title": "Nous Contacter",
|
||||
"subtitle": "Prêt à améliorer votre infrastructure IT ?",
|
||||
"form": {
|
||||
"name": "Nom",
|
||||
"email": "Email",
|
||||
"company": "Entreprise",
|
||||
"service": "Service Nécessaire",
|
||||
"message": "Message",
|
||||
"send": "Envoyer le Message",
|
||||
"sending": "Envoi en cours...",
|
||||
"success": "Message envoyé avec succès !",
|
||||
"error": "Échec de l'envoi du message. Veuillez réessayer."
|
||||
},
|
||||
"info": {
|
||||
"email": "info@tiber365.it",
|
||||
"phone": "+39 123 456 7890",
|
||||
"address": "Italie"
|
||||
}
|
||||
},
|
||||
"cta": {
|
||||
"title": "Prêt à Commencer ?",
|
||||
"subtitle": "Discutons de la façon dont nous pouvons vous aider à améliorer votre infrastructure IT",
|
||||
"button": "Réserver une Consultation Gratuite"
|
||||
},
|
||||
"footer": {
|
||||
"description": "Services IT professionnels pour les freelances et petites entreprises.",
|
||||
"links": {
|
||||
"services": "Services",
|
||||
"about": "À propos",
|
||||
"contact": "Contact",
|
||||
"privacy": "Politique de Confidentialité",
|
||||
"terms": "Conditions de Service"
|
||||
},
|
||||
"copyright": "© 2024 Tiber365. Tous droits réservés."
|
||||
},
|
||||
"privacy": {
|
||||
"title": "Politique de Confidentialité",
|
||||
"description": "Découvrez comment nous protégeons vos données personnelles",
|
||||
"lastUpdated": "Dernière mise à jour"
|
||||
},
|
||||
"terms": {
|
||||
"title": "Conditions de Service",
|
||||
"description": "Notre accord de service et conditions légales",
|
||||
"lastUpdated": "Dernière mise à jour"
|
||||
},
|
||||
"404": {
|
||||
"title": "Page Non Trouvée",
|
||||
"description": "La page que vous recherchez n'existe pas.",
|
||||
"button": "Aller à l'Accueil"
|
||||
}
|
||||
}
|
@@ -92,6 +92,14 @@
|
||||
"clients": "Clienti Soddisfatti",
|
||||
"projects": "Progetti Completati"
|
||||
},
|
||||
"blog": {
|
||||
"title": "Blog",
|
||||
"description": "Ultimi approfondimenti, consigli e aggiornamenti dal mondo dell'IT e Microsoft 365",
|
||||
"readMore": "Leggi di più",
|
||||
"backToBlog": "Torna al Blog",
|
||||
"error": "Spiacenti, non siamo riusciti a caricare gli articoli del blog. Riprova più tardi.",
|
||||
"noPosts": "Nessun articolo del blog trovato."
|
||||
},
|
||||
"testimonials": {
|
||||
"title": "Cosa Dicono i Nostri Clienti",
|
||||
"subtitle": "Non fidarti solo della nostra parola",
|
||||
|
@@ -92,6 +92,14 @@
|
||||
"clients": "Tevreden Klanten",
|
||||
"projects": "Voltooide Projecten"
|
||||
},
|
||||
"blog": {
|
||||
"title": "Blog",
|
||||
"description": "Laatste inzichten, tips en updates uit de wereld van IT en Microsoft 365",
|
||||
"readMore": "Lees meer",
|
||||
"backToBlog": "Terug naar Blog",
|
||||
"error": "Sorry, we konden de blogberichten niet laden. Probeer het later opnieuw.",
|
||||
"noPosts": "Geen blogberichten gevonden."
|
||||
},
|
||||
"testimonials": {
|
||||
"title": "Wat Onze Klanten Zeggen",
|
||||
"subtitle": "Geloof ons niet alleen op ons woord",
|
||||
|
@@ -1,65 +1,27 @@
|
||||
---
|
||||
import BaseLayout from '../layouts/BaseLayout.astro';
|
||||
import Header from '../components/Header.astro';
|
||||
import Footer from '../components/Footer.astro';
|
||||
import { t } from '../utils/i18n';
|
||||
import BaseLayout from "../layouts/BaseLayout.astro";
|
||||
import Header from "../components/Header.astro";
|
||||
import Footer from "../components/Footer.astro";
|
||||
import { getLangFromUrl, useTranslations } from '../utils/i18n';
|
||||
|
||||
const lang = getLangFromUrl(Astro.url);
|
||||
const t = await useTranslations(lang);
|
||||
---
|
||||
|
||||
<BaseLayout
|
||||
title={`${t('404.title')} | ${t('meta.title')}`}
|
||||
description={t('404.description')}
|
||||
title={`${t("404.title")} | ${t("meta.title")}`}
|
||||
description={t("404.description")}
|
||||
>
|
||||
<Header />
|
||||
<main>
|
||||
<section class="min-h-screen flex items-center justify-center bg-gradient-to-br from-background via-background to-muted">
|
||||
<div class="container-custom">
|
||||
<div class="text-center max-w-2xl mx-auto animate-on-scroll">
|
||||
<!-- 404 Visual -->
|
||||
<div class="text-8xl sm:text-9xl font-bold text-primary/20 mb-8">404</div>
|
||||
|
||||
<!-- Error message -->
|
||||
<h1 class="text-3xl sm:text-4xl lg:text-5xl font-display font-bold text-foreground mb-4">
|
||||
{t('404.title')}
|
||||
</h1>
|
||||
|
||||
<p class="text-lg sm:text-xl text-muted-foreground mb-8">
|
||||
{t('404.description')}
|
||||
</p>
|
||||
|
||||
<!-- Action buttons -->
|
||||
<div class="flex flex-col sm:flex-row gap-4 justify-center items-center">
|
||||
<a
|
||||
href="/"
|
||||
class="btn-primary px-8 py-4 text-lg font-semibold rounded-xl shadow-lg hover:shadow-xl transition-all duration-300 hover:scale-105 inline-flex items-center group"
|
||||
>
|
||||
<svg class="h-5 w-5 mr-2 group-hover:-translate-x-1 transition-transform" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10 19l-7-7m0 0l7-7m-7 7h18"/>
|
||||
</svg>
|
||||
{t('404.button')}
|
||||
</a>
|
||||
|
||||
<a
|
||||
href="/contact"
|
||||
class="btn-outline px-8 py-4 text-lg font-semibold rounded-xl transition-all duration-300 hover:scale-105"
|
||||
>
|
||||
Get Help
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<!-- Helpful links -->
|
||||
<div class="mt-12">
|
||||
<p class="text-muted-foreground mb-4">Or try one of these popular pages:</p>
|
||||
<div class="flex flex-wrap justify-center gap-4">
|
||||
<a href="/services" class="text-primary hover:text-primary/80 transition-colors">Services</a>
|
||||
<span class="text-muted-foreground">•</span>
|
||||
<a href="/about" class="text-primary hover:text-primary/80 transition-colors">About</a>
|
||||
<span class="text-muted-foreground">•</span>
|
||||
<a href="/contact" class="text-primary hover:text-primary/80 transition-colors">Contact</a>
|
||||
<span class="text-muted-foreground">•</span>
|
||||
<a href="https://blog.tiber365.it" target="_blank" rel="noopener noreferrer" class="text-primary hover:text-primary/80 transition-colors">Blog</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<section class="py-20">
|
||||
<div class="container-custom text-center">
|
||||
<h1 class="text-6xl font-bold text-muted-foreground mb-4">404</h1>
|
||||
<h2 class="text-2xl font-semibold text-foreground mb-4">{t("404.title")}</h2>
|
||||
<p class="text-muted-foreground mb-8">{t("404.description")}</p>
|
||||
<a href="/" class="inline-flex items-center px-6 py-3 bg-primary text-primary-foreground rounded-lg hover:bg-primary/90 transition-colors">
|
||||
{t("404.backHome")}
|
||||
</a>
|
||||
</div>
|
||||
</section>
|
||||
</main>
|
||||
|
34
src/pages/[lang]/404.astro
Normal file
34
src/pages/[lang]/404.astro
Normal file
@@ -0,0 +1,34 @@
|
||||
---
|
||||
import BaseLayout from "../../layouts/BaseLayout.astro";
|
||||
import Header from "../../components/Header.astro";
|
||||
import Footer from "../../components/Footer.astro";
|
||||
import { useTranslations, SUPPORTED_LOCALES } from '../../utils/i18n';
|
||||
|
||||
export async function getStaticPaths() {
|
||||
return SUPPORTED_LOCALES.map(lang => ({ params: { lang } }));
|
||||
}
|
||||
|
||||
const { lang } = Astro.params;
|
||||
const t = await useTranslations(lang as any);
|
||||
---
|
||||
|
||||
<BaseLayout
|
||||
title={`${t("404.title")} | ${t("meta.title")}`}
|
||||
description={t("404.description")}
|
||||
noindex={true}
|
||||
>
|
||||
<Header />
|
||||
<main>
|
||||
<section class="py-20">
|
||||
<div class="container-custom text-center">
|
||||
<h1 class="text-6xl font-bold text-muted-foreground mb-4">404</h1>
|
||||
<h2 class="text-2xl font-semibold text-foreground mb-4">{t("404.title")}</h2>
|
||||
<p class="text-muted-foreground mb-8">{t("404.description")}</p>
|
||||
<a href="/" class="inline-flex items-center px-6 py-3 bg-primary text-primary-foreground rounded-lg hover:bg-primary/90 transition-colors">
|
||||
{t("404.backHome")}
|
||||
</a>
|
||||
</div>
|
||||
</section>
|
||||
</main>
|
||||
<Footer />
|
||||
</BaseLayout>
|
35
src/pages/[lang]/about.astro
Normal file
35
src/pages/[lang]/about.astro
Normal file
@@ -0,0 +1,35 @@
|
||||
---
|
||||
import BaseLayout from "../../layouts/BaseLayout.astro";
|
||||
import Header from "../../components/Header.astro";
|
||||
import Footer from "../../components/Footer.astro";
|
||||
import CTA from "../../components/CTA.astro";
|
||||
import { useTranslations, SUPPORTED_LOCALES } from '../../utils/i18n';
|
||||
|
||||
export async function getStaticPaths() {
|
||||
return SUPPORTED_LOCALES.map(lang => ({ params: { lang } }));
|
||||
}
|
||||
|
||||
const { lang } = Astro.params;
|
||||
const t = await useTranslations(lang as any);
|
||||
---
|
||||
|
||||
<BaseLayout
|
||||
title={`${t("nav.about")} | ${t("meta.title")}`}
|
||||
description={t("meta.description")}
|
||||
keywords={t("meta.keywords")}
|
||||
>
|
||||
<Header />
|
||||
<main>
|
||||
<section class="py-20">
|
||||
<div class="container-custom">
|
||||
<h1 class="text-4xl font-bold mb-8">{t("about.title")}</h1>
|
||||
<div class="prose prose-lg">
|
||||
<p>{t("about.description")}</p>
|
||||
<p>{t("about.mission")}</p>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
<CTA />
|
||||
</main>
|
||||
<Footer />
|
||||
</BaseLayout>
|
79
src/pages/[lang]/blog/[slug].astro
Normal file
79
src/pages/[lang]/blog/[slug].astro
Normal file
@@ -0,0 +1,79 @@
|
||||
---
|
||||
import BaseLayout from '../../../layouts/BaseLayout.astro';
|
||||
import Header from '../../../components/Header.astro';
|
||||
import Footer from '../../../components/Footer.astro';
|
||||
import { getBlogPostBySlug, getBlogPosts } from '../../../utils/directus';
|
||||
import { getLangFromUrl, useTranslations } from '../../../utils/i18n';
|
||||
|
||||
export async function getStaticPaths() {
|
||||
const posts = await getBlogPosts();
|
||||
const languages = ['en', 'nl', 'de', 'fr'];
|
||||
|
||||
const paths = [];
|
||||
for (const lang of languages) {
|
||||
for (const post of posts) {
|
||||
if (typeof post.slug === 'string' && post.slug.trim() !== '') {
|
||||
paths.push({
|
||||
params: { lang, slug: post.slug },
|
||||
props: { post },
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return paths;
|
||||
}
|
||||
|
||||
const { post } = Astro.props;
|
||||
const lang = getLangFromUrl(Astro.url);
|
||||
const t = await useTranslations(lang);
|
||||
---
|
||||
|
||||
<BaseLayout title={`${post.title} | ${t('blog.title')}`} description={post.content.replace(/<[^>]+>/g, '').substring(0, 160)}>
|
||||
<Header />
|
||||
|
||||
<main class="flex-1">
|
||||
<!-- Hero Section -->
|
||||
<section class="bg-gradient-to-br from-blue-50 to-indigo-100 dark:from-gray-900 dark:to-gray-800 py-20">
|
||||
<div class="container-custom">
|
||||
<div class="max-w-4xl mx-auto">
|
||||
<nav class="mb-6">
|
||||
<a href={`/${lang}/blog`} class="text-primary hover:underline flex items-center">
|
||||
← {t('blog.backToBlog')}
|
||||
</a>
|
||||
</nav>
|
||||
<header class="text-center">
|
||||
<h1 class="text-4xl md:text-5xl font-bold text-gray-900 dark:text-white mb-6">
|
||||
{post.title}
|
||||
</h1>
|
||||
<p class="text-xl text-gray-600 dark:text-gray-300">
|
||||
{new Date(post.date_created).toLocaleDateString(lang === 'en' ? 'en-US' : lang === 'nl' ? 'nl-NL' : lang === 'de' ? 'de-DE' : 'fr-FR', {
|
||||
year: 'numeric',
|
||||
month: 'long',
|
||||
day: 'numeric'
|
||||
})}
|
||||
</p>
|
||||
</header>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- Article Content -->
|
||||
<section class="py-16">
|
||||
<div class="container-custom">
|
||||
<article class="max-w-4xl mx-auto">
|
||||
<div class="prose prose-lg dark:prose-invert max-w-none prose-headings:text-gray-900 dark:prose-headings:text-white prose-p:text-gray-700 dark:prose-p:text-gray-300 prose-a:text-primary prose-a:no-underline hover:prose-a:underline prose-strong:text-gray-900 dark:prose-strong:text-white prose-code:text-primary prose-code:bg-gray-100 dark:prose-code:bg-gray-800 prose-code:px-1 prose-code:py-0.5 prose-code:rounded" set:html={post.content}></div>
|
||||
|
||||
<!-- Back to Blog Button -->
|
||||
<div class="mt-12 pt-8 border-t border-border text-center">
|
||||
<a href={`/${lang}/blog`} class="btn btn-primary">
|
||||
← {t('blog.backToBlog')}
|
||||
</a>
|
||||
</div>
|
||||
</article>
|
||||
</div>
|
||||
</section>
|
||||
</main>
|
||||
|
||||
<Footer />
|
||||
</BaseLayout>
|
107
src/pages/[lang]/blog/index.astro
Normal file
107
src/pages/[lang]/blog/index.astro
Normal file
@@ -0,0 +1,107 @@
|
||||
---
|
||||
import BaseLayout from '../../../layouts/BaseLayout.astro';
|
||||
import Header from '../../../components/Header.astro';
|
||||
import Footer from '../../../components/Footer.astro';
|
||||
import { getBlogPosts } from '../../../utils/directus';
|
||||
import { getLangFromUrl, useTranslations } from '../../../utils/i18n';
|
||||
|
||||
export async function getStaticPaths() {
|
||||
const languages = ['en', 'nl', 'de', 'fr'] as const;
|
||||
|
||||
return languages.map(lang => ({
|
||||
params: { lang },
|
||||
props: { lang }
|
||||
}));
|
||||
}
|
||||
|
||||
const { lang } = Astro.props;
|
||||
const t = await useTranslations(lang);
|
||||
|
||||
let posts = [];
|
||||
let error = null;
|
||||
|
||||
function stripHtml(html) {
|
||||
return html.replace(/<[^>]+>/g, '');
|
||||
}
|
||||
|
||||
try {
|
||||
posts = await getBlogPosts();
|
||||
} catch (e) {
|
||||
console.error('Error in blog page:', e);
|
||||
error = e.message;
|
||||
}
|
||||
---
|
||||
|
||||
<BaseLayout title={t('blog.title')} description={t('blog.description')}>
|
||||
<Header />
|
||||
|
||||
<main class="flex-1">
|
||||
<!-- Hero Section -->
|
||||
<section class="bg-gradient-to-br from-blue-50 to-indigo-100 dark:from-gray-900 dark:to-gray-800 py-20">
|
||||
<div class="container-custom">
|
||||
<div class="text-center max-w-3xl mx-auto">
|
||||
<h1 class="text-4xl md:text-5xl font-bold text-gray-900 dark:text-white mb-6">
|
||||
{t('blog.title')}
|
||||
</h1>
|
||||
<p class="text-xl text-gray-600 dark:text-gray-300">
|
||||
{t('blog.description')}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- Blog Posts Section -->
|
||||
<section class="py-16">
|
||||
<div class="container-custom">
|
||||
{error ? (
|
||||
<div class="bg-red-50 dark:bg-red-900/20 border border-red-200 dark:border-red-800 rounded-lg p-6 mb-8">
|
||||
<p class="text-red-800 dark:text-red-200">
|
||||
{t('blog.error')}
|
||||
</p>
|
||||
{import.meta.env.DEV && (
|
||||
<pre class="mt-2 text-sm text-red-600 dark:text-red-400">{error}</pre>
|
||||
)}
|
||||
</div>
|
||||
) : posts.length === 0 ? (
|
||||
<div class="text-center py-12">
|
||||
<p class="text-gray-600 dark:text-gray-400 text-lg">
|
||||
{t('blog.noPosts')}
|
||||
</p>
|
||||
</div>
|
||||
) : (
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-8">
|
||||
{posts.map((post) => (
|
||||
<article class="card hover:shadow-lg transition-shadow duration-300 group">
|
||||
<div class="flex flex-col h-full">
|
||||
<div class="flex-1">
|
||||
<h2 class="text-xl font-bold mb-3 group-hover:text-primary transition-colors">
|
||||
<a href={`/${lang}/blog/${post.slug}`} class="hover:underline">
|
||||
{post.title}
|
||||
</a>
|
||||
</h2>
|
||||
<p class="text-muted-foreground text-sm mb-4">
|
||||
{new Date(post.date_created).toLocaleDateString(lang === 'en' ? 'en-US' : lang === 'nl' ? 'nl-NL' : lang === 'de' ? 'de-DE' : 'fr-FR')}
|
||||
</p>
|
||||
<div class="text-foreground text-sm mb-6 line-clamp-4">
|
||||
{stripHtml(post.content).substring(0, 200)}{stripHtml(post.content).length > 200 ? '...' : ''}
|
||||
</div>
|
||||
</div>
|
||||
<div class="pt-4 border-t border-border">
|
||||
<a
|
||||
href={`/${lang}/blog/${post.slug}`}
|
||||
class="inline-flex items-center text-primary font-medium hover:underline transition-colors"
|
||||
>
|
||||
{t('blog.readMore')} →
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</article>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</section>
|
||||
</main>
|
||||
|
||||
<Footer />
|
||||
</BaseLayout>
|
46
src/pages/[lang]/contact.astro
Normal file
46
src/pages/[lang]/contact.astro
Normal file
@@ -0,0 +1,46 @@
|
||||
---
|
||||
import BaseLayout from '../../layouts/BaseLayout.astro';
|
||||
import Header from '../../components/Header.astro';
|
||||
import ContactForm from '../../components/ContactForm.astro';
|
||||
import Footer from '../../components/Footer.astro';
|
||||
import { useTranslations, SUPPORTED_LOCALES } from '../../utils/i18n';
|
||||
|
||||
export async function getStaticPaths() {
|
||||
return SUPPORTED_LOCALES.map(lang => ({ params: { lang } }));
|
||||
}
|
||||
|
||||
const { lang } = Astro.params;
|
||||
const t = await useTranslations(lang as any);
|
||||
|
||||
// Contact page structured data
|
||||
const contactStructuredData = {
|
||||
"@context": "https://schema.org",
|
||||
"@type": "ContactPage",
|
||||
"name": `${t("nav.contact")} - ${t("meta.title")}`,
|
||||
"description": t("contact.description"),
|
||||
"url": `https://tiber365.it/${lang === 'en' ? 'contact' : `${lang}/contact`}`,
|
||||
"inLanguage": lang,
|
||||
"mainEntity": {
|
||||
"@type": "Organization",
|
||||
"name": "Tiber365",
|
||||
"contactPoint": {
|
||||
"@type": "ContactPoint",
|
||||
"contactType": "customer service",
|
||||
"availableLanguage": ["English", "Dutch", "German", "French"],
|
||||
"email": "info@tiber365.it"
|
||||
}
|
||||
}
|
||||
};
|
||||
---
|
||||
|
||||
<BaseLayout
|
||||
title={`${t("nav.contact")} | ${t("meta.title")}`}
|
||||
description={t("contact.description")}
|
||||
>
|
||||
<script type="application/ld+json" set:html={JSON.stringify(contactStructuredData)} />
|
||||
<Header />
|
||||
<main>
|
||||
<ContactForm />
|
||||
</main>
|
||||
<Footer />
|
||||
</BaseLayout>
|
64
src/pages/[lang]/index.astro
Normal file
64
src/pages/[lang]/index.astro
Normal file
@@ -0,0 +1,64 @@
|
||||
---
|
||||
import BaseLayout from "../../layouts/BaseLayout.astro";
|
||||
import Header from "../../components/Header.astro";
|
||||
import Hero from "../../components/Hero.astro";
|
||||
import Services from "../../components/Services.astro";
|
||||
import Testimonials from "../../components/Testimonials.astro";
|
||||
import CTA from "../../components/CTA.astro";
|
||||
import Footer from "../../components/Footer.astro";
|
||||
import { getLangFromUrl, useTranslations, SUPPORTED_LOCALES } from '../../utils/i18n';
|
||||
|
||||
export async function getStaticPaths() {
|
||||
return SUPPORTED_LOCALES.map(lang => ({ params: { lang } }));
|
||||
}
|
||||
|
||||
const { lang } = Astro.params;
|
||||
const t = await useTranslations(lang as any);
|
||||
|
||||
// Page-specific structured data
|
||||
const pageStructuredData = {
|
||||
"@context": "https://schema.org",
|
||||
"@type": "WebPage",
|
||||
"name": t("meta.title"),
|
||||
"description": t("meta.description"),
|
||||
"url": `https://tiber365.it/${lang === 'en' ? '' : lang}`,
|
||||
"inLanguage": lang,
|
||||
"isPartOf": {
|
||||
"@type": "WebSite",
|
||||
"name": "Tiber365",
|
||||
"url": "https://tiber365.it"
|
||||
},
|
||||
"mainEntity": {
|
||||
"@type": "Organization",
|
||||
"name": "Tiber365",
|
||||
"description": t("site.description"),
|
||||
"url": "https://tiber365.it",
|
||||
"logo": "https://tiber365.it/images/TIBER365.png",
|
||||
"contactPoint": {
|
||||
"@type": "ContactPoint",
|
||||
"contactType": "customer service",
|
||||
"availableLanguage": ["English", "Dutch", "German", "French"]
|
||||
},
|
||||
"serviceArea": {
|
||||
"@type": "Country",
|
||||
"name": "Italy"
|
||||
}
|
||||
}
|
||||
};
|
||||
---
|
||||
|
||||
<BaseLayout
|
||||
title={t("meta.title")}
|
||||
description={t("meta.description")}
|
||||
keywords={t("meta.keywords")}
|
||||
>
|
||||
<script type="application/ld+json" set:html={JSON.stringify(pageStructuredData)} />
|
||||
<Header />
|
||||
<main>
|
||||
<Hero />
|
||||
<Services />
|
||||
<Testimonials />
|
||||
<CTA />
|
||||
</main>
|
||||
<Footer />
|
||||
</BaseLayout>
|
33
src/pages/[lang]/privacy.astro
Normal file
33
src/pages/[lang]/privacy.astro
Normal file
@@ -0,0 +1,33 @@
|
||||
---
|
||||
import BaseLayout from '../../layouts/BaseLayout.astro';
|
||||
import Header from '../../components/Header.astro';
|
||||
import Footer from '../../components/Footer.astro';
|
||||
import { useTranslations, SUPPORTED_LOCALES } from '../../utils/i18n';
|
||||
|
||||
export async function getStaticPaths() {
|
||||
return SUPPORTED_LOCALES.map(lang => ({ params: { lang } }));
|
||||
}
|
||||
|
||||
const { lang } = Astro.params;
|
||||
const t = await useTranslations(lang as any);
|
||||
---
|
||||
|
||||
<BaseLayout
|
||||
title={`${t("privacy.title")} | ${t("meta.title")}`}
|
||||
description={t("privacy.description")}
|
||||
>
|
||||
<Header />
|
||||
<main>
|
||||
<section class="py-20">
|
||||
<div class="container-custom">
|
||||
<h1 class="text-4xl font-bold mb-8">{t("privacy.title")}</h1>
|
||||
<div class="prose prose-lg max-w-none">
|
||||
<p>{t("privacy.lastUpdated")}</p>
|
||||
<p>{t("privacy.introduction")}</p>
|
||||
<!-- Add more privacy content as needed -->
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</main>
|
||||
<Footer />
|
||||
</BaseLayout>
|
33
src/pages/[lang]/terms.astro
Normal file
33
src/pages/[lang]/terms.astro
Normal file
@@ -0,0 +1,33 @@
|
||||
---
|
||||
import BaseLayout from '../../layouts/BaseLayout.astro';
|
||||
import Header from '../../components/Header.astro';
|
||||
import Footer from '../../components/Footer.astro';
|
||||
import { useTranslations, SUPPORTED_LOCALES } from '../../utils/i18n';
|
||||
|
||||
export async function getStaticPaths() {
|
||||
return SUPPORTED_LOCALES.map(lang => ({ params: { lang } }));
|
||||
}
|
||||
|
||||
const { lang } = Astro.params;
|
||||
const t = await useTranslations(lang as any);
|
||||
---
|
||||
|
||||
<BaseLayout
|
||||
title={`${t("terms.title")} | ${t("meta.title")}`}
|
||||
description={t("terms.description")}
|
||||
>
|
||||
<Header />
|
||||
<main>
|
||||
<section class="py-20">
|
||||
<div class="container-custom">
|
||||
<h1 class="text-4xl font-bold mb-8">{t("terms.title")}</h1>
|
||||
<div class="prose prose-lg max-w-none">
|
||||
<p>{t("terms.lastUpdated")}</p>
|
||||
<p>{t("terms.introduction")}</p>
|
||||
<!-- Add more terms content as needed -->
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</main>
|
||||
<Footer />
|
||||
</BaseLayout>
|
@@ -1,4 +0,0 @@
|
||||
---
|
||||
// Redirect to English version
|
||||
return Astro.redirect('/en/about');
|
||||
---
|
@@ -1,31 +1,28 @@
|
||||
---
|
||||
import BaseLayout from '../../layouts/BaseLayout.astro';
|
||||
import { getBlogPostBySlug, getBlogPosts } from '../../utils/directus';
|
||||
|
||||
export async function getStaticPaths() {
|
||||
// Get all blog posts to create redirects
|
||||
const { getBlogPosts } = await import('../../utils/directus');
|
||||
const posts = await getBlogPosts();
|
||||
|
||||
return posts
|
||||
.filter((post) => typeof post.slug === 'string' && post.slug.trim() !== '')
|
||||
.map((post) => ({
|
||||
params: { slug: post.slug },
|
||||
props: { post },
|
||||
props: { slug: post.slug },
|
||||
}));
|
||||
}
|
||||
|
||||
const { post } = Astro.props;
|
||||
const { slug } = Astro.props;
|
||||
---
|
||||
|
||||
<BaseLayout title={`${post.title} | Tiber365 Blog`}>
|
||||
<main class="container mx-auto px-4 py-12">
|
||||
<article class="max-w-3xl mx-auto">
|
||||
<header class="mb-8">
|
||||
<h1 class="text-4xl font-bold mb-4">{post.title}</h1>
|
||||
<p class="text-gray-600 dark:text-gray-300">
|
||||
{new Date(post.date_created).toLocaleDateString()}
|
||||
</p>
|
||||
</header>
|
||||
|
||||
<div class="prose dark:prose-invert max-w-none" set:html={post.content}></div>
|
||||
</article>
|
||||
</main>
|
||||
</BaseLayout>
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Redirecting...</title>
|
||||
<meta http-equiv="refresh" content="0;url=/en/blog/{slug}">
|
||||
<link rel="canonical" href="/en/blog/{slug}">
|
||||
</head>
|
||||
<body>
|
||||
<p>Redirecting to <a href="/en/blog/{slug}">blog post</a>...</p>
|
||||
</body>
|
||||
</html>
|
@@ -1,63 +1,15 @@
|
||||
---
|
||||
import BaseLayout from '../../layouts/BaseLayout.astro';
|
||||
import { getBlogPosts } from '../../utils/directus';
|
||||
|
||||
let posts = [];
|
||||
let error = null;
|
||||
|
||||
function stripHtml(html) {
|
||||
return html.replace(/<[^>]+>/g, '');
|
||||
}
|
||||
|
||||
try {
|
||||
posts = await getBlogPosts();
|
||||
} catch (e) {
|
||||
console.error('Error in blog page:', e);
|
||||
error = e.message;
|
||||
}
|
||||
// Static redirect to English blog
|
||||
---
|
||||
|
||||
<BaseLayout title="Blog | Tiber365">
|
||||
<main class="flex flex-col items-center min-h-screen bg-background py-16 px-4">
|
||||
<h1 class="text-5xl font-extrabold mb-12 text-center">Blog</h1>
|
||||
|
||||
{error ? (
|
||||
<div class="bg-red-50 dark:bg-red-900/20 border border-red-200 dark:border-red-800 rounded-lg p-4 mb-8">
|
||||
<p class="text-red-800 dark:text-red-200">
|
||||
Sorry, we couldn't load the blog posts at this time. Please try again later.
|
||||
</p>
|
||||
{import.meta.env.DEV && (
|
||||
<pre class="mt-2 text-sm text-red-600 dark:text-red-400">{error}</pre>
|
||||
)}
|
||||
</div>
|
||||
) : posts.length === 0 ? (
|
||||
<p class="text-gray-600 dark:text-gray-400">No blog posts found.</p>
|
||||
) : (
|
||||
<div class="w-full max-w-4xl mx-auto grid grid-cols-1 md:grid-cols-2 gap-10">
|
||||
{posts.map((post) => (
|
||||
<article class="bg-white/90 dark:bg-gray-900/80 border border-gray-200 dark:border-gray-800 rounded-2xl shadow-lg hover:shadow-2xl transition-shadow duration-300 overflow-hidden flex flex-col h-full group">
|
||||
<div class="flex flex-col flex-1 p-8">
|
||||
<h2 class="text-2xl font-bold mb-3 group-hover:text-blue-600 dark:group-hover:text-blue-400 transition-colors">
|
||||
<a href={`/blog/${post.slug}`}>{post.title}</a>
|
||||
</h2>
|
||||
<p class="text-gray-500 dark:text-gray-400 text-sm mb-4">
|
||||
{new Date(post.date_created).toLocaleDateString()}
|
||||
</p>
|
||||
<div class="text-base text-gray-700 dark:text-gray-300 mb-6 line-clamp-4">
|
||||
{stripHtml(post.content).substring(0, 250)}{stripHtml(post.content).length > 250 ? '...' : ''}
|
||||
</div>
|
||||
<div class="mt-auto pt-2">
|
||||
<a
|
||||
href={`/blog/${post.slug}`}
|
||||
class="inline-block text-blue-600 dark:text-blue-400 font-medium hover:underline transition-colors"
|
||||
>
|
||||
Read more →
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</article>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
</main>
|
||||
</BaseLayout>
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Redirecting...</title>
|
||||
<meta http-equiv="refresh" content="0;url=/en/blog">
|
||||
<link rel="canonical" href="/en/blog">
|
||||
</head>
|
||||
<body>
|
||||
<p>Redirecting to <a href="/en/blog">blog</a>...</p>
|
||||
</body>
|
||||
</html>
|
@@ -1,18 +0,0 @@
|
||||
---
|
||||
import BaseLayout from '../layouts/BaseLayout.astro';
|
||||
import Header from '../components/Header.astro';
|
||||
import ContactForm from '../components/ContactForm.astro';
|
||||
import Footer from '../components/Footer.astro';
|
||||
import { t } from '../utils/i18n';
|
||||
---
|
||||
|
||||
<BaseLayout
|
||||
title={`${t('nav.contact')} | ${t('meta.title')}`}
|
||||
description="Contact Tiber365 for professional IT services. Get in touch for Microsoft 365 support, networking solutions, and custom IT projects."
|
||||
>
|
||||
<Header />
|
||||
<main>
|
||||
<ContactForm />
|
||||
</main>
|
||||
<Footer />
|
||||
</BaseLayout>
|
@@ -1,62 +0,0 @@
|
||||
---
|
||||
import BaseLayout from '../../layouts/BaseLayout.astro';
|
||||
import Header from '../../components/Header.astro';
|
||||
import Footer from '../../components/Footer.astro';
|
||||
import { t } from '../../utils/i18n';
|
||||
---
|
||||
|
||||
<BaseLayout
|
||||
title={`${t('404.title', 'en')} | ${t('meta.title', 'en')}`}
|
||||
description={t('404.description', 'en')}
|
||||
>
|
||||
<Header />
|
||||
<main>
|
||||
<section class="min-h-screen flex items-center justify-center bg-gradient-to-br from-background via-background to-muted">
|
||||
<div class="container-custom">
|
||||
<div class="text-center max-w-2xl mx-auto animate-on-scroll">
|
||||
<!-- 404 Visual -->
|
||||
<div class="text-8xl sm:text-9xl font-bold text-primary/20 mb-8">404</div>
|
||||
<!-- Error message -->
|
||||
<h1 class="text-3xl sm:text-4xl lg:text-5xl font-display font-bold text-foreground mb-4">
|
||||
{t('404.title', 'en')}
|
||||
</h1>
|
||||
<p class="text-lg sm:text-xl text-muted-foreground mb-8">
|
||||
{t('404.description', 'en')}
|
||||
</p>
|
||||
<!-- Action buttons -->
|
||||
<div class="flex flex-col sm:flex-row gap-4 justify-center items-center">
|
||||
<a
|
||||
href="/"
|
||||
class="btn-primary px-8 py-4 text-lg font-semibold rounded-xl shadow-lg hover:shadow-xl transition-all duration-300 hover:scale-105 inline-flex items-center group"
|
||||
>
|
||||
<svg class="h-5 w-5 mr-2 group-hover:-translate-x-1 transition-transform" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10 19l-7-7m0 0l7-7m-7 7h18"/>
|
||||
</svg>
|
||||
{t('404.button', 'en')}
|
||||
</a>
|
||||
<a
|
||||
href="/contact"
|
||||
class="btn-outline px-8 py-4 text-lg font-semibold rounded-xl transition-all duration-300 hover:scale-105"
|
||||
>
|
||||
Get Help
|
||||
</a>
|
||||
</div>
|
||||
<!-- Helpful links -->
|
||||
<div class="mt-12">
|
||||
<p class="text-muted-foreground mb-4">Or try one of these popular pages:</p>
|
||||
<div class="flex flex-wrap justify-center gap-4">
|
||||
<a href="/services" class="text-primary hover:text-primary/80 transition-colors">Services</a>
|
||||
<span class="text-muted-foreground">•</span>
|
||||
<a href="/about" class="text-primary hover:text-primary/80 transition-colors">About</a>
|
||||
<span class="text-muted-foreground">•</span>
|
||||
<a href="/contact" class="text-primary hover:text-primary/80 transition-colors">Contact</a>
|
||||
<span class="text-muted-foreground">•</span>
|
||||
<a href="https://blog.tiber365.it" target="_blank" rel="noopener noreferrer" class="text-primary hover:text-primary/80 transition-colors">Blog</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</main>
|
||||
<Footer />
|
||||
</BaseLayout>
|
@@ -1,55 +0,0 @@
|
||||
---
|
||||
import BaseLayout from "../../layouts/BaseLayout.astro";
|
||||
import Header from "../../components/Header.astro";
|
||||
import Footer from "../../components/Footer.astro";
|
||||
import CTA from "../../components/CTA.astro";
|
||||
import { t } from '../../utils/i18n';
|
||||
|
||||
const pageTitle = `${t('nav.about', 'en')} | ${t('meta.title', 'en')}`;
|
||||
const pageDescription = t('meta.description', 'en');
|
||||
---
|
||||
|
||||
<BaseLayout
|
||||
title={pageTitle}
|
||||
description={pageDescription}
|
||||
>
|
||||
<Header />
|
||||
<main>
|
||||
<!-- About Hero -->
|
||||
<section class="py-20 bg-gradient-to-br from-background via-background to-muted">
|
||||
<div class="container-custom">
|
||||
<div class="text-center max-w-4xl mx-auto animate-on-scroll">
|
||||
<h1 class="text-4xl sm:text-5xl lg:text-6xl font-display font-bold text-foreground mb-6">
|
||||
{t('about.title', 'en')}
|
||||
</h1>
|
||||
<p class="text-lg sm:text-xl text-muted-foreground leading-relaxed">
|
||||
{t('about.subtitle', 'en')}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- Company Story -->
|
||||
<section class="py-20 bg-background">
|
||||
<div class="container-custom">
|
||||
<div class="grid grid-cols-1 lg:grid-cols-2 gap-12 items-center">
|
||||
<!-- Content -->
|
||||
<div class="animate-on-scroll">
|
||||
<h2 class="text-3xl sm:text-4xl font-display font-bold text-foreground mb-6">
|
||||
{t('about.story.title', 'en')}
|
||||
</h2>
|
||||
<p class="text-lg text-muted-foreground mb-6 leading-relaxed">
|
||||
{t('about.story.description', 'en')}
|
||||
</p>
|
||||
<p class="text-lg text-muted-foreground leading-relaxed">
|
||||
{t('about.story.mission', 'en')}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<CTA />
|
||||
</main>
|
||||
<Footer />
|
||||
</BaseLayout>
|
@@ -1,18 +0,0 @@
|
||||
---
|
||||
import BaseLayout from '../../layouts/BaseLayout.astro';
|
||||
import Header from '../../components/Header.astro';
|
||||
import ContactForm from '../../components/ContactForm.astro';
|
||||
import Footer from '../../components/Footer.astro';
|
||||
import { t } from '../../utils/i18n';
|
||||
---
|
||||
|
||||
<BaseLayout
|
||||
title={`${t('nav.contact', 'en')} | ${t('meta.title', 'en')}`}
|
||||
description="Contact Tiber365 for professional IT services. Get in touch for Microsoft 365 support, networking solutions, and custom IT projects."
|
||||
>
|
||||
<Header />
|
||||
<main>
|
||||
<ContactForm />
|
||||
</main>
|
||||
<Footer />
|
||||
</BaseLayout>
|
@@ -1,29 +0,0 @@
|
||||
---
|
||||
import BaseLayout from "../../layouts/BaseLayout.astro";
|
||||
import Header from "../../components/Header.astro";
|
||||
import Hero from "../../components/Hero.astro";
|
||||
import Services from "../../components/Services.astro";
|
||||
import Testimonials from "../../components/Testimonials.astro";
|
||||
import CTA from "../../components/CTA.astro";
|
||||
import Footer from "../../components/Footer.astro";
|
||||
import { t } from '../../utils/i18n';
|
||||
|
||||
const pageTitle = t('meta.title', 'en');
|
||||
const pageDescription = t('meta.description', 'en');
|
||||
const pageKeywords = t('meta.keywords', 'en');
|
||||
---
|
||||
|
||||
<BaseLayout
|
||||
title={pageTitle}
|
||||
description={pageDescription}
|
||||
keywords={pageKeywords}
|
||||
>
|
||||
<Header />
|
||||
<main>
|
||||
<Hero />
|
||||
<Services />
|
||||
<Testimonials />
|
||||
<CTA />
|
||||
</main>
|
||||
<Footer />
|
||||
</BaseLayout>
|
@@ -1,25 +1,4 @@
|
||||
---
|
||||
import BaseLayout from '../../layouts/BaseLayout.astro';
|
||||
import Header from '../../components/Header.astro';
|
||||
import Footer from '../../components/Footer.astro';
|
||||
import { t } from '../../utils/i18n';
|
||||
---
|
||||
|
||||
<BaseLayout
|
||||
title={`${t('footer.links.privacy', 'en')} | ${t('meta.title', 'en')}`}
|
||||
description="Privacy Policy for Tiber365 - Learn how we collect, use, and protect your personal data in compliance with GDPR and Dutch privacy laws."
|
||||
>
|
||||
<Header />
|
||||
<main class="py-16 bg-background">
|
||||
<div class="container-custom">
|
||||
<article class="prose prose-lg dark:prose-invert max-w-4xl mx-auto">
|
||||
<h1 class="text-4xl font-display font-bold mb-8">{t('footer.links.privacy', 'en')}</h1>
|
||||
<div class="mb-8 text-sm text-muted-foreground">
|
||||
Last updated: {new Date().toLocaleDateString()}
|
||||
</div>
|
||||
<!-- Copy the rest of the original file, updating all t() calls to use 'en' as the locale -->
|
||||
</article>
|
||||
</div>
|
||||
</main>
|
||||
<Footer />
|
||||
</BaseLayout>
|
||||
// Redirect to main privacy page
|
||||
return Astro.redirect('/privacy');
|
||||
---
|
@@ -1,25 +0,0 @@
|
||||
---
|
||||
import BaseLayout from '../../layouts/BaseLayout.astro';
|
||||
import Header from '../../components/Header.astro';
|
||||
import Footer from '../../components/Footer.astro';
|
||||
import { t } from '../../utils/i18n';
|
||||
---
|
||||
|
||||
<BaseLayout
|
||||
title={`${t('footer.links.terms', 'en')} | ${t('meta.title', 'en')}`}
|
||||
description="Terms of Service for Tiber365 - Understanding our service agreement and legal terms in compliance with European and Dutch laws."
|
||||
>
|
||||
<Header />
|
||||
<main class="py-16 bg-background">
|
||||
<div class="container-custom">
|
||||
<article class="prose prose-lg dark:prose-invert max-w-4xl mx-auto">
|
||||
<h1 class="text-4xl font-display font-bold mb-8">{t('footer.links.terms', 'en')}</h1>
|
||||
<div class="mb-8 text-sm text-muted-foreground">
|
||||
Last updated: {new Date().toLocaleDateString()}
|
||||
</div>
|
||||
<!-- Copy the rest of the original file, updating all t() calls to use 'en' as the locale -->
|
||||
</article>
|
||||
</div>
|
||||
</main>
|
||||
<Footer />
|
||||
</BaseLayout>
|
@@ -1,29 +1,4 @@
|
||||
---
|
||||
import BaseLayout from "../layouts/BaseLayout.astro";
|
||||
import Header from "../components/Header.astro";
|
||||
import Hero from "../components/Hero.astro";
|
||||
import Services from "../components/Services.astro";
|
||||
import Testimonials from "../components/Testimonials.astro";
|
||||
import CTA from "../components/CTA.astro";
|
||||
import Footer from "../components/Footer.astro";
|
||||
import { t } from '../utils/i18n';
|
||||
|
||||
const pageTitle = t('meta.title', 'en');
|
||||
const pageDescription = t('meta.description', 'en');
|
||||
const pageKeywords = t('meta.keywords', 'en');
|
||||
---
|
||||
|
||||
<BaseLayout
|
||||
title={pageTitle}
|
||||
description={pageDescription}
|
||||
keywords={pageKeywords}
|
||||
>
|
||||
<Header />
|
||||
<main>
|
||||
<Hero />
|
||||
<Services />
|
||||
<Testimonials />
|
||||
<CTA />
|
||||
</main>
|
||||
<Footer />
|
||||
</BaseLayout>
|
||||
// Redirect to English version
|
||||
return Astro.redirect('/en/');
|
||||
---
|
@@ -1,62 +0,0 @@
|
||||
---
|
||||
import BaseLayout from '../../layouts/BaseLayout.astro';
|
||||
import Header from '../../components/Header.astro';
|
||||
import Footer from '../../components/Footer.astro';
|
||||
import { t } from '../../utils/i18n';
|
||||
---
|
||||
|
||||
<BaseLayout
|
||||
title={`${t('404.title', 'it')} | ${t('meta.title', 'it')}`}
|
||||
description={t('404.description', 'it')}
|
||||
>
|
||||
<Header />
|
||||
<main>
|
||||
<section class="min-h-screen flex items-center justify-center bg-gradient-to-br from-background via-background to-muted">
|
||||
<div class="container-custom">
|
||||
<div class="text-center max-w-2xl mx-auto animate-on-scroll">
|
||||
<!-- 404 Visual -->
|
||||
<div class="text-8xl sm:text-9xl font-bold text-primary/20 mb-8">404</div>
|
||||
<!-- Error message -->
|
||||
<h1 class="text-3xl sm:text-4xl lg:text-5xl font-display font-bold text-foreground mb-4">
|
||||
{t('404.title', 'it')}
|
||||
</h1>
|
||||
<p class="text-lg sm:text-xl text-muted-foreground mb-8">
|
||||
{t('404.description', 'it')}
|
||||
</p>
|
||||
<!-- Action buttons -->
|
||||
<div class="flex flex-col sm:flex-row gap-4 justify-center items-center">
|
||||
<a
|
||||
href="/"
|
||||
class="btn-primary px-8 py-4 text-lg font-semibold rounded-xl shadow-lg hover:shadow-xl transition-all duration-300 hover:scale-105 inline-flex items-center group"
|
||||
>
|
||||
<svg class="h-5 w-5 mr-2 group-hover:-translate-x-1 transition-transform" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10 19l-7-7m0 0l7-7m-7 7h18"/>
|
||||
</svg>
|
||||
{t('404.button', 'it')}
|
||||
</a>
|
||||
<a
|
||||
href="/contact"
|
||||
class="btn-outline px-8 py-4 text-lg font-semibold rounded-xl transition-all duration-300 hover:scale-105"
|
||||
>
|
||||
Serve Aiuto
|
||||
</a>
|
||||
</div>
|
||||
<!-- Helpful links -->
|
||||
<div class="mt-12">
|
||||
<p class="text-muted-foreground mb-4">Oppure prova una di queste pagine popolari:</p>
|
||||
<div class="flex flex-wrap justify-center gap-4">
|
||||
<a href="/services" class="text-primary hover:text-primary/80 transition-colors">Servizi</a>
|
||||
<span class="text-muted-foreground">•</span>
|
||||
<a href="/about" class="text-primary hover:text-primary/80 transition-colors">Chi Siamo</a>
|
||||
<span class="text-muted-foreground">•</span>
|
||||
<a href="/contact" class="text-primary hover:text-primary/80 transition-colors">Contatti</a>
|
||||
<span class="text-muted-foreground">•</span>
|
||||
<a href="https://blog.tiber365.it" target="_blank" rel="noopener noreferrer" class="text-primary hover:text-primary/80 transition-colors">Blog</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</main>
|
||||
<Footer />
|
||||
</BaseLayout>
|
@@ -1,32 +0,0 @@
|
||||
---
|
||||
import BaseLayout from "../../layouts/BaseLayout.astro";
|
||||
import Header from "../../components/Header.astro";
|
||||
import Footer from "../../components/Footer.astro";
|
||||
import CTA from "../../components/CTA.astro";
|
||||
import { Trans } from "astro-i18next/components";
|
||||
import i18next from "i18next";
|
||||
|
||||
// Initialize i18next for this page
|
||||
await i18next.changeLanguage("it");
|
||||
---
|
||||
|
||||
<BaseLayout
|
||||
title={`${i18next.t("nav.about")} | ${i18next.t("meta.title")}`}
|
||||
description={i18next.t("meta.description")}
|
||||
keywords={i18next.t("meta.keywords")}
|
||||
>
|
||||
<Header />
|
||||
<main>
|
||||
<section class="py-20">
|
||||
<div class="container-custom">
|
||||
<h1 class="text-4xl font-bold mb-8">{i18next.t("about.title")}</h1>
|
||||
<div class="prose prose-lg">
|
||||
<p>{i18next.t("about.description")}</p>
|
||||
<p>{i18next.t("about.mission")}</p>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
<CTA />
|
||||
</main>
|
||||
<Footer />
|
||||
</BaseLayout>
|
@@ -1,18 +0,0 @@
|
||||
---
|
||||
import BaseLayout from '../../layouts/BaseLayout.astro';
|
||||
import Header from '../../components/Header.astro';
|
||||
import ContactForm from '../../components/ContactForm.astro';
|
||||
import Footer from '../../components/Footer.astro';
|
||||
import { t } from '../../utils/i18n';
|
||||
---
|
||||
|
||||
<BaseLayout
|
||||
title={`${t('nav.contact', 'it')} | ${t('meta.title', 'it')}`}
|
||||
description="Contatta Tiber365 per servizi IT professionali. Contattaci per supporto Microsoft 365, soluzioni di rete e progetti IT personalizzati."
|
||||
>
|
||||
<Header />
|
||||
<main>
|
||||
<ContactForm />
|
||||
</main>
|
||||
<Footer />
|
||||
</BaseLayout>
|
@@ -1,29 +0,0 @@
|
||||
---
|
||||
import BaseLayout from "../../layouts/BaseLayout.astro";
|
||||
import Header from "../../components/Header.astro";
|
||||
import Hero from "../../components/Hero.astro";
|
||||
import Services from "../../components/Services.astro";
|
||||
import Testimonials from "../../components/Testimonials.astro";
|
||||
import CTA from "../../components/CTA.astro";
|
||||
import Footer from "../../components/Footer.astro";
|
||||
import { Trans } from "astro-i18next/components";
|
||||
import i18next from "i18next";
|
||||
|
||||
// Initialize i18next for this page
|
||||
await i18next.changeLanguage("it");
|
||||
---
|
||||
|
||||
<BaseLayout
|
||||
title={i18next.t("meta.title")}
|
||||
description={i18next.t("meta.description")}
|
||||
keywords={i18next.t("meta.keywords")}
|
||||
>
|
||||
<Header />
|
||||
<main>
|
||||
<Hero />
|
||||
<Services />
|
||||
<Testimonials />
|
||||
<CTA />
|
||||
</main>
|
||||
<Footer />
|
||||
</BaseLayout>
|
@@ -1,25 +0,0 @@
|
||||
---
|
||||
import BaseLayout from '../../layouts/BaseLayout.astro';
|
||||
import Header from '../../components/Header.astro';
|
||||
import Footer from '../../components/Footer.astro';
|
||||
import { t } from '../../utils/i18n';
|
||||
---
|
||||
|
||||
<BaseLayout
|
||||
title={`${t('footer.links.privacy', 'it')} | ${t('meta.title', 'it')}`}
|
||||
description="Informativa sulla privacy per Tiber365 - Scopri come raccogliamo, utilizziamo e proteggiamo i tuoi dati personali in conformità con il GDPR e le leggi italiane sulla privacy."
|
||||
>
|
||||
<Header />
|
||||
<main class="py-16 bg-background">
|
||||
<div class="container-custom">
|
||||
<article class="prose prose-lg dark:prose-invert max-w-4xl mx-auto">
|
||||
<h1 class="text-4xl font-display font-bold mb-8">{t('footer.links.privacy', 'it')}</h1>
|
||||
<div class="mb-8 text-sm text-muted-foreground">
|
||||
Ultimo aggiornamento: {new Date().toLocaleDateString()}
|
||||
</div>
|
||||
<!-- Copy the rest of the original file, updating all t() calls to use 'it' as the locale -->
|
||||
</article>
|
||||
</div>
|
||||
</main>
|
||||
<Footer />
|
||||
</BaseLayout>
|
@@ -1,25 +0,0 @@
|
||||
---
|
||||
import BaseLayout from '../../layouts/BaseLayout.astro';
|
||||
import Header from '../../components/Header.astro';
|
||||
import Footer from '../../components/Footer.astro';
|
||||
import { t } from '../../utils/i18n';
|
||||
---
|
||||
|
||||
<BaseLayout
|
||||
title={`${t('footer.links.terms', 'it')} | ${t('meta.title', 'it')}`}
|
||||
description="Termini di servizio per Tiber365 - Comprendere il nostro accordo di servizio e i termini legali in conformità con le leggi europee e italiane."
|
||||
>
|
||||
<Header />
|
||||
<main class="py-16 bg-background">
|
||||
<div class="container-custom">
|
||||
<article class="prose prose-lg dark:prose-invert max-w-4xl mx-auto">
|
||||
<h1 class="text-4xl font-display font-bold mb-8">{t('footer.links.terms', 'it')}</h1>
|
||||
<div class="mb-8 text-sm text-muted-foreground">
|
||||
Ultimo aggiornamento: {new Date().toLocaleDateString()}
|
||||
</div>
|
||||
<!-- Copy the rest of the original file, updating all t() calls to use 'it' as the locale -->
|
||||
</article>
|
||||
</div>
|
||||
</main>
|
||||
<Footer />
|
||||
</BaseLayout>
|
@@ -1,62 +0,0 @@
|
||||
---
|
||||
import BaseLayout from '../../layouts/BaseLayout.astro';
|
||||
import Header from '../../components/Header.astro';
|
||||
import Footer from '../../components/Footer.astro';
|
||||
import { t } from '../../utils/i18n';
|
||||
---
|
||||
|
||||
<BaseLayout
|
||||
title={`${t('404.title', 'nl')} | ${t('meta.title', 'nl')}`}
|
||||
description={t('404.description', 'nl')}
|
||||
>
|
||||
<Header />
|
||||
<main>
|
||||
<section class="min-h-screen flex items-center justify-center bg-gradient-to-br from-background via-background to-muted">
|
||||
<div class="container-custom">
|
||||
<div class="text-center max-w-2xl mx-auto animate-on-scroll">
|
||||
<!-- 404 Visual -->
|
||||
<div class="text-8xl sm:text-9xl font-bold text-primary/20 mb-8">404</div>
|
||||
<!-- Error message -->
|
||||
<h1 class="text-3xl sm:text-4xl lg:text-5xl font-display font-bold text-foreground mb-4">
|
||||
{t('404.title', 'nl')}
|
||||
</h1>
|
||||
<p class="text-lg sm:text-xl text-muted-foreground mb-8">
|
||||
{t('404.description', 'nl')}
|
||||
</p>
|
||||
<!-- Action buttons -->
|
||||
<div class="flex flex-col sm:flex-row gap-4 justify-center items-center">
|
||||
<a
|
||||
href="/"
|
||||
class="btn-primary px-8 py-4 text-lg font-semibold rounded-xl shadow-lg hover:shadow-xl transition-all duration-300 hover:scale-105 inline-flex items-center group"
|
||||
>
|
||||
<svg class="h-5 w-5 mr-2 group-hover:-translate-x-1 transition-transform" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10 19l-7-7m0 0l7-7m-7 7h18"/>
|
||||
</svg>
|
||||
{t('404.button', 'nl')}
|
||||
</a>
|
||||
<a
|
||||
href="/contact"
|
||||
class="btn-outline px-8 py-4 text-lg font-semibold rounded-xl transition-all duration-300 hover:scale-105"
|
||||
>
|
||||
Hulp Nodig
|
||||
</a>
|
||||
</div>
|
||||
<!-- Helpful links -->
|
||||
<div class="mt-12">
|
||||
<p class="text-muted-foreground mb-4">Of probeer een van deze populaire pagina's:</p>
|
||||
<div class="flex flex-wrap justify-center gap-4">
|
||||
<a href="/services" class="text-primary hover:text-primary/80 transition-colors">Diensten</a>
|
||||
<span class="text-muted-foreground">•</span>
|
||||
<a href="/about" class="text-primary hover:text-primary/80 transition-colors">Over Ons</a>
|
||||
<span class="text-muted-foreground">•</span>
|
||||
<a href="/contact" class="text-primary hover:text-primary/80 transition-colors">Contact</a>
|
||||
<span class="text-muted-foreground">•</span>
|
||||
<a href="https://blog.tiber365.it" target="_blank" rel="noopener noreferrer" class="text-primary hover:text-primary/80 transition-colors">Blog</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</main>
|
||||
<Footer />
|
||||
</BaseLayout>
|
@@ -1,32 +0,0 @@
|
||||
---
|
||||
import BaseLayout from "../../layouts/BaseLayout.astro";
|
||||
import Header from "../../components/Header.astro";
|
||||
import Footer from "../../components/Footer.astro";
|
||||
import CTA from "../../components/CTA.astro";
|
||||
import { Trans } from "astro-i18next/components";
|
||||
import i18next from "i18next";
|
||||
|
||||
// Initialize i18next for this page
|
||||
await i18next.changeLanguage("nl");
|
||||
---
|
||||
|
||||
<BaseLayout
|
||||
title={`${i18next.t("nav.about")} | ${i18next.t("meta.title")}`}
|
||||
description={i18next.t("meta.description")}
|
||||
keywords={i18next.t("meta.keywords")}
|
||||
>
|
||||
<Header />
|
||||
<main>
|
||||
<section class="py-20">
|
||||
<div class="container-custom">
|
||||
<h1 class="text-4xl font-bold mb-8">{i18next.t("about.title")}</h1>
|
||||
<div class="prose prose-lg">
|
||||
<p>{i18next.t("about.description")}</p>
|
||||
<p>{i18next.t("about.mission")}</p>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
<CTA />
|
||||
</main>
|
||||
<Footer />
|
||||
</BaseLayout>
|
@@ -1 +0,0 @@
|
||||
|
@@ -1,29 +0,0 @@
|
||||
---
|
||||
import BaseLayout from "../../layouts/BaseLayout.astro";
|
||||
import Header from "../../components/Header.astro";
|
||||
import Hero from "../../components/Hero.astro";
|
||||
import Services from "../../components/Services.astro";
|
||||
import Testimonials from "../../components/Testimonials.astro";
|
||||
import CTA from "../../components/CTA.astro";
|
||||
import Footer from "../../components/Footer.astro";
|
||||
import { Trans } from "astro-i18next/components";
|
||||
import i18next from "i18next";
|
||||
|
||||
// Initialize i18next for this page
|
||||
await i18next.changeLanguage("nl");
|
||||
---
|
||||
|
||||
<BaseLayout
|
||||
title={i18next.t("meta.title")}
|
||||
description={i18next.t("meta.description")}
|
||||
keywords={i18next.t("meta.keywords")}
|
||||
>
|
||||
<Header />
|
||||
<main>
|
||||
<Hero />
|
||||
<Services />
|
||||
<Testimonials />
|
||||
<CTA />
|
||||
</main>
|
||||
<Footer />
|
||||
</BaseLayout>
|
@@ -1 +1,29 @@
|
||||
|
||||
---
|
||||
import BaseLayout from "../../layouts/BaseLayout.astro";
|
||||
import Header from "../../components/Header.astro";
|
||||
import Footer from "../../components/Footer.astro";
|
||||
import { getLangFromUrl, useTranslations } from '../../utils/i18n';
|
||||
|
||||
const lang = getLangFromUrl(Astro.url);
|
||||
const t = await useTranslations(lang);
|
||||
---
|
||||
|
||||
<BaseLayout
|
||||
title={`${t("privacy.title")} | ${t("meta.title")}`}
|
||||
description={t("privacy.description")}
|
||||
>
|
||||
<Header />
|
||||
<main>
|
||||
<section class="py-20">
|
||||
<div class="container-custom">
|
||||
<h1 class="text-4xl font-bold mb-8">{t("privacy.title")}</h1>
|
||||
<div class="prose prose-lg max-w-none">
|
||||
<p>{t("privacy.lastUpdated")}</p>
|
||||
<p>{t("privacy.introduction")}</p>
|
||||
<!-- Add more privacy content as needed -->
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</main>
|
||||
<Footer />
|
||||
</BaseLayout>
|
@@ -1 +0,0 @@
|
||||
|
@@ -1,154 +0,0 @@
|
||||
---
|
||||
import BaseLayout from '../layouts/BaseLayout.astro';
|
||||
import Header from '../components/Header.astro';
|
||||
import Footer from '../components/Footer.astro';
|
||||
import { t } from '../utils/i18n';
|
||||
---
|
||||
|
||||
<BaseLayout
|
||||
title={`${t('footer.links.privacy')} | ${t('meta.title')}`}
|
||||
description="Privacy Policy for Tiber365 - Learn how we collect, use, and protect your personal data in compliance with GDPR and Dutch privacy laws."
|
||||
>
|
||||
<Header />
|
||||
<main class="py-16 bg-background">
|
||||
<div class="container-custom">
|
||||
<article class="prose prose-lg dark:prose-invert max-w-4xl mx-auto">
|
||||
<h1 class="text-4xl font-display font-bold mb-8">{t('footer.links.privacy')}</h1>
|
||||
|
||||
<div class="mb-8 text-sm text-muted-foreground">
|
||||
Last updated: {new Date().toLocaleDateString()}
|
||||
</div>
|
||||
|
||||
<section class="mb-12">
|
||||
<h2>1. Introduction</h2>
|
||||
<p>
|
||||
Tiber365 ("we", "our", or "us") is committed to protecting your privacy and personal data. This Privacy Policy explains how we collect, use, and protect your personal information in accordance with the General Data Protection Regulation (GDPR) and Dutch privacy laws.
|
||||
</p>
|
||||
</section>
|
||||
|
||||
<section class="mb-12">
|
||||
<h2>2. Data Controller</h2>
|
||||
<p>
|
||||
Tiber365<br />
|
||||
Italy<br />
|
||||
Email: info@tiber365.it
|
||||
</p>
|
||||
<p>
|
||||
For privacy-related inquiries, you can contact our Data Protection Officer at privacy@tiber365.it.
|
||||
</p>
|
||||
</section>
|
||||
|
||||
<section class="mb-12">
|
||||
<h2>3. Personal Data We Collect</h2>
|
||||
<p>We collect and process the following types of personal data:</p>
|
||||
<ul>
|
||||
<li>Contact information (name, email, phone number, company name)</li>
|
||||
<li>Technical data (IP address, browser type, device information)</li>
|
||||
<li>Usage data (how you interact with our website and services)</li>
|
||||
<li>Communication data (messages you send us through our contact form)</li>
|
||||
<li>Service data (information related to the IT services we provide)</li>
|
||||
</ul>
|
||||
</section>
|
||||
|
||||
<section class="mb-12">
|
||||
<h2>4. Legal Basis for Processing</h2>
|
||||
<p>We process your personal data based on the following legal grounds:</p>
|
||||
<ul>
|
||||
<li>Contract performance (when providing our IT services)</li>
|
||||
<li>Legal obligations (compliance with Dutch and EU laws)</li>
|
||||
<li>Legitimate interests (improving our services and communication)</li>
|
||||
<li>Consent (for marketing communications and cookies)</li>
|
||||
</ul>
|
||||
</section>
|
||||
|
||||
<section class="mb-12">
|
||||
<h2>5. How We Use Your Data</h2>
|
||||
<p>We use your personal data for:</p>
|
||||
<ul>
|
||||
<li>Providing and managing our IT services</li>
|
||||
<li>Communicating with you about our services</li>
|
||||
<li>Improving our website and services</li>
|
||||
<li>Complying with legal obligations</li>
|
||||
<li>Sending you marketing communications (with your consent)</li>
|
||||
</ul>
|
||||
</section>
|
||||
|
||||
<section class="mb-12">
|
||||
<h2>6. Data Sharing and Transfers</h2>
|
||||
<p>
|
||||
We may share your data with:
|
||||
</p>
|
||||
<ul>
|
||||
<li>Service providers (hosting, email, analytics)</li>
|
||||
<li>Professional advisers (lawyers, accountants)</li>
|
||||
<li>Authorities (when legally required)</li>
|
||||
</ul>
|
||||
<p>
|
||||
Data transfers outside the EU/EEA are protected by appropriate safeguards (Standard Contractual Clauses).
|
||||
</p>
|
||||
</section>
|
||||
|
||||
<section class="mb-12">
|
||||
<h2>7. Data Retention</h2>
|
||||
<p>
|
||||
We retain your personal data only for as long as necessary to fulfill the purposes for which it was collected, including legal requirements and accounting purposes.
|
||||
</p>
|
||||
</section>
|
||||
|
||||
<section class="mb-12">
|
||||
<h2>8. Your Rights</h2>
|
||||
<p>Under GDPR and Dutch privacy laws, you have the right to:</p>
|
||||
<ul>
|
||||
<li>Access your personal data</li>
|
||||
<li>Correct inaccurate data</li>
|
||||
<li>Request deletion of your data</li>
|
||||
<li>Object to processing</li>
|
||||
<li>Data portability</li>
|
||||
<li>Withdraw consent</li>
|
||||
</ul>
|
||||
<p>
|
||||
To exercise these rights, contact us at privacy@tiber365.it. We'll respond within 30 days.
|
||||
</p>
|
||||
</section>
|
||||
|
||||
<section class="mb-12">
|
||||
<h2>9. Cookies and Tracking</h2>
|
||||
<p>
|
||||
We use cookies and similar technologies to improve your browsing experience. You can manage cookie preferences through your browser settings.
|
||||
</p>
|
||||
</section>
|
||||
|
||||
<section class="mb-12">
|
||||
<h2>10. Security</h2>
|
||||
<p>
|
||||
We implement appropriate technical and organizational measures to protect your personal data against unauthorized access, alteration, disclosure, or destruction.
|
||||
</p>
|
||||
</section>
|
||||
|
||||
<section class="mb-12">
|
||||
<h2>11. Changes to This Policy</h2>
|
||||
<p>
|
||||
We may update this Privacy Policy periodically. We will notify you of any material changes by posting the new policy on this page.
|
||||
</p>
|
||||
</section>
|
||||
|
||||
<section class="mb-12">
|
||||
<h2>12. Complaints</h2>
|
||||
<p>
|
||||
If you have concerns about how we process your personal data, please contact us first. You also have the right to file a complaint with the Dutch Data Protection Authority (Autoriteit Persoonsgegevens).
|
||||
</p>
|
||||
</section>
|
||||
|
||||
<section class="mb-12">
|
||||
<h2>13. Contact Us</h2>
|
||||
<p>
|
||||
For any privacy-related questions or requests, please contact us at:<br />
|
||||
Email: privacy@tiber365.it<br />
|
||||
Phone: +39 123 456 7890
|
||||
</p>
|
||||
</section>
|
||||
</article>
|
||||
</div>
|
||||
</main>
|
||||
<Footer />
|
||||
</BaseLayout>
|
81
src/pages/sitemap.xml.ts
Normal file
81
src/pages/sitemap.xml.ts
Normal file
@@ -0,0 +1,81 @@
|
||||
import type { APIRoute } from 'astro';
|
||||
import { SITE } from '../site.config';
|
||||
import { getBlogPosts } from '../utils/directus';
|
||||
|
||||
const pages = [
|
||||
'',
|
||||
'/about',
|
||||
'/contact',
|
||||
'/services',
|
||||
'/blog',
|
||||
'/privacy',
|
||||
'/terms'
|
||||
];
|
||||
|
||||
const locales = ['en', 'nl', 'de', 'fr'];
|
||||
|
||||
export const GET: APIRoute = async () => {
|
||||
// Get blog posts for sitemap
|
||||
let blogPosts = [];
|
||||
try {
|
||||
blogPosts = await getBlogPosts();
|
||||
} catch (error) {
|
||||
console.error('Error fetching blog posts for sitemap:', error);
|
||||
}
|
||||
|
||||
const sitemap = `<?xml version="1.0" encoding="UTF-8"?>
|
||||
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9"
|
||||
xmlns:xhtml="http://www.w3.org/1999/xhtml">
|
||||
${pages.map(page => {
|
||||
const urls = locales.map(locale => {
|
||||
const url = locale === 'en' ? page : `/${locale}${page}`;
|
||||
const fullUrl = `${SITE.url}${url}`;
|
||||
const lastmod = new Date().toISOString().split('T')[0];
|
||||
const priority = page === '' ? '1.0' : '0.8';
|
||||
const changefreq = page === '' ? 'weekly' : 'monthly';
|
||||
|
||||
return ` <url>
|
||||
<loc>${fullUrl}</loc>
|
||||
<lastmod>${lastmod}</lastmod>
|
||||
<changefreq>${changefreq}</changefreq>
|
||||
<priority>${priority}</priority>
|
||||
<xhtml:link rel="alternate" hreflang="${locale}" href="${fullUrl}" />
|
||||
${locales.map(altLocale => {
|
||||
const altUrl = altLocale === 'en' ? page : `/${altLocale}${page}`;
|
||||
const altFullUrl = `${SITE.url}${altUrl}`;
|
||||
return ` <xhtml:link rel="alternate" hreflang="${altLocale}" href="${altFullUrl}" />`;
|
||||
}).join('\n')}
|
||||
</url>`;
|
||||
});
|
||||
return urls.join('\n');
|
||||
}).join('\n')}
|
||||
${blogPosts.map(post => {
|
||||
const urls = locales.map(locale => {
|
||||
const url = `/${locale}/blog/${post.slug}`;
|
||||
const fullUrl = `${SITE.url}${url}`;
|
||||
const lastmod = new Date(post.date_updated || post.date_created).toISOString().split('T')[0];
|
||||
|
||||
return ` <url>
|
||||
<loc>${fullUrl}</loc>
|
||||
<lastmod>${lastmod}</lastmod>
|
||||
<changefreq>monthly</changefreq>
|
||||
<priority>0.6</priority>
|
||||
<xhtml:link rel="alternate" hreflang="${locale}" href="${fullUrl}" />
|
||||
${locales.map(altLocale => {
|
||||
const altUrl = `/${altLocale}/blog/${post.slug}`;
|
||||
const altFullUrl = `${SITE.url}${altUrl}`;
|
||||
return ` <xhtml:link rel="alternate" hreflang="${altLocale}" href="${altFullUrl}" />`;
|
||||
}).join('\n')}
|
||||
</url>`;
|
||||
});
|
||||
return urls.join('\n');
|
||||
}).join('\n')}
|
||||
</urlset>`;
|
||||
|
||||
return new Response(sitemap, {
|
||||
status: 200,
|
||||
headers: {
|
||||
'Content-Type': 'application/xml'
|
||||
}
|
||||
});
|
||||
};
|
@@ -1,165 +0,0 @@
|
||||
---
|
||||
import BaseLayout from '../layouts/BaseLayout.astro';
|
||||
import Header from '../components/Header.astro';
|
||||
import Footer from '../components/Footer.astro';
|
||||
import { t } from '../utils/i18n';
|
||||
---
|
||||
|
||||
<BaseLayout
|
||||
title={`${t('footer.links.terms')} | ${t('meta.title')}`}
|
||||
description="Terms of Service for Tiber365 - Understanding our service agreement and legal terms in compliance with European and Dutch laws."
|
||||
>
|
||||
<Header />
|
||||
<main class="py-16 bg-background">
|
||||
<div class="container-custom">
|
||||
<article class="prose prose-lg dark:prose-invert max-w-4xl mx-auto">
|
||||
<h1 class="text-4xl font-display font-bold mb-8">{t('footer.links.terms')}</h1>
|
||||
|
||||
<div class="mb-8 text-sm text-muted-foreground">
|
||||
Last updated: {new Date().toLocaleDateString()}
|
||||
</div>
|
||||
|
||||
<section class="mb-12">
|
||||
<h2>1. Introduction</h2>
|
||||
<p>
|
||||
These Terms of Service ("Terms") govern your use of Tiber365's website and services. By accessing our website or using our services, you agree to be bound by these Terms. If you disagree with any part of these terms, please do not use our services.
|
||||
</p>
|
||||
</section>
|
||||
|
||||
<section class="mb-12">
|
||||
<h2>2. Company Information</h2>
|
||||
<p>
|
||||
Tiber365<br />
|
||||
Registered in Italy<br />
|
||||
Email: info@tiber365.it<br />
|
||||
Phone: +39 123 456 7890
|
||||
</p>
|
||||
</section>
|
||||
|
||||
<section class="mb-12">
|
||||
<h2>3. Services</h2>
|
||||
<p>
|
||||
We provide IT services including:
|
||||
</p>
|
||||
<ul>
|
||||
<li>Microsoft 365 support and management</li>
|
||||
<li>Networking and infrastructure solutions</li>
|
||||
<li>Web hosting and management</li>
|
||||
<li>Custom IT projects</li>
|
||||
</ul>
|
||||
<p>
|
||||
Service specifics will be detailed in individual service agreements.
|
||||
</p>
|
||||
</section>
|
||||
|
||||
<section class="mb-12">
|
||||
<h2>4. Service Agreement</h2>
|
||||
<p>
|
||||
Upon engaging our services:
|
||||
</p>
|
||||
<ul>
|
||||
<li>We will provide services as specified in the service agreement</li>
|
||||
<li>You agree to provide necessary information and access for service delivery</li>
|
||||
<li>You will maintain the confidentiality of any access credentials provided</li>
|
||||
<li>You will use the services in compliance with applicable laws</li>
|
||||
</ul>
|
||||
</section>
|
||||
|
||||
<section class="mb-12">
|
||||
<h2>5. Intellectual Property</h2>
|
||||
<p>
|
||||
All content on our website and services, including but not limited to text, graphics, logos, and software, is our property or that of our licensors and is protected by intellectual property laws.
|
||||
</p>
|
||||
</section>
|
||||
|
||||
<section class="mb-12">
|
||||
<h2>6. User Obligations</h2>
|
||||
<p>You agree to:</p>
|
||||
<ul>
|
||||
<li>Provide accurate and complete information</li>
|
||||
<li>Maintain the security of your account</li>
|
||||
<li>Not use our services for illegal purposes</li>
|
||||
<li>Not interfere with the proper functioning of our services</li>
|
||||
<li>Comply with all applicable laws and regulations</li>
|
||||
</ul>
|
||||
</section>
|
||||
|
||||
<section class="mb-12">
|
||||
<h2>7. Payment Terms</h2>
|
||||
<p>
|
||||
Payment terms, including fees, billing cycles, and payment methods, will be specified in your service agreement. Late payments may result in service suspension.
|
||||
</p>
|
||||
</section>
|
||||
|
||||
<section class="mb-12">
|
||||
<h2>8. Liability</h2>
|
||||
<p>
|
||||
To the extent permitted by law:
|
||||
</p>
|
||||
<ul>
|
||||
<li>We provide services "as is" without warranties</li>
|
||||
<li>We are not liable for indirect, consequential, or incidental damages</li>
|
||||
<li>Our liability is limited to the amount paid for services in the previous 12 months</li>
|
||||
</ul>
|
||||
</section>
|
||||
|
||||
<section class="mb-12">
|
||||
<h2>9. Data Protection</h2>
|
||||
<p>
|
||||
We process personal data in accordance with our Privacy Policy and applicable data protection laws (GDPR and Dutch privacy laws).
|
||||
</p>
|
||||
</section>
|
||||
|
||||
<section class="mb-12">
|
||||
<h2>10. Service Availability</h2>
|
||||
<p>
|
||||
While we strive for high availability, we do not guarantee uninterrupted service. We will provide notice of scheduled maintenance when possible.
|
||||
</p>
|
||||
</section>
|
||||
|
||||
<section class="mb-12">
|
||||
<h2>11. Termination</h2>
|
||||
<p>
|
||||
Either party may terminate services according to the terms in the service agreement. Upon termination:
|
||||
</p>
|
||||
<ul>
|
||||
<li>All access to services will cease</li>
|
||||
<li>You remain liable for any outstanding payments</li>
|
||||
<li>We will assist with data transition as specified in the service agreement</li>
|
||||
</ul>
|
||||
</section>
|
||||
|
||||
<section class="mb-12">
|
||||
<h2>12. Changes to Terms</h2>
|
||||
<p>
|
||||
We may modify these Terms at any time. Continued use of our services after changes constitutes acceptance of the modified Terms.
|
||||
</p>
|
||||
</section>
|
||||
|
||||
<section class="mb-12">
|
||||
<h2>13. Governing Law</h2>
|
||||
<p>
|
||||
These Terms are governed by Dutch law. Any disputes will be subject to the exclusive jurisdiction of the Dutch courts.
|
||||
</p>
|
||||
</section>
|
||||
|
||||
<section class="mb-12">
|
||||
<h2>14. Severability</h2>
|
||||
<p>
|
||||
If any provision of these Terms is found to be unenforceable, the remaining provisions will remain in effect.
|
||||
</p>
|
||||
</section>
|
||||
|
||||
<section class="mb-12">
|
||||
<h2>15. Contact</h2>
|
||||
<p>
|
||||
For questions about these Terms, please contact us at:<br />
|
||||
Email: legal@tiber365.it<br />
|
||||
Phone: +39 123 456 7890
|
||||
</p>
|
||||
</section>
|
||||
</article>
|
||||
</div>
|
||||
</main>
|
||||
<Footer />
|
||||
</BaseLayout>
|
@@ -8,10 +8,12 @@ export const SITE = {
|
||||
url: 'https://tiber365.it'
|
||||
} as const;
|
||||
|
||||
// UPDATED: Removed Italian, added German and French
|
||||
export const LANGUAGES = {
|
||||
en: 'English',
|
||||
nl: 'Nederlands',
|
||||
it: 'Italiano'
|
||||
de: 'Deutsch',
|
||||
fr: 'Français'
|
||||
} as const;
|
||||
|
||||
export const NAVIGATION = [
|
||||
@@ -128,4 +130,4 @@ export const TESTIMONIALS = [
|
||||
contentKey: 'testimonials.3.content',
|
||||
rating: 5
|
||||
}
|
||||
] as const;
|
||||
] as const;
|
@@ -1,5 +1,3 @@
|
||||
@import url('https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&family=Poppins:wght@400;500;600;700&display=swap');
|
||||
|
||||
@tailwind base;
|
||||
@tailwind components;
|
||||
@tailwind utilities;
|
||||
@@ -101,26 +99,22 @@
|
||||
.btn-outline {
|
||||
@apply btn;
|
||||
border: 1px solid rgb(var(--color-border));
|
||||
background-color: rgb(var(--color-background));
|
||||
background-color: transparent;
|
||||
color: rgb(var(--color-foreground));
|
||||
}
|
||||
|
||||
.btn-outline:hover {
|
||||
background-color: rgb(var(--color-accent));
|
||||
color: rgb(var(--color-accent-foreground));
|
||||
}
|
||||
|
||||
.card {
|
||||
@apply rounded-xl shadow-sm;
|
||||
border: 1px solid rgb(var(--color-border));
|
||||
background-color: rgb(var(--color-background));
|
||||
@apply rounded-lg border border-border bg-background p-6 shadow-sm;
|
||||
}
|
||||
|
||||
.container-custom {
|
||||
@apply mx-auto max-w-7xl px-4 sm:px-6 lg:px-8;
|
||||
}
|
||||
|
||||
/* Theme-based colors */
|
||||
|
||||
.bg-background {
|
||||
background-color: rgb(var(--color-background));
|
||||
}
|
||||
@@ -158,12 +152,11 @@
|
||||
}
|
||||
}
|
||||
|
||||
/* Animations */
|
||||
@layer utilities {
|
||||
.animate-on-scroll {
|
||||
opacity: 0;
|
||||
transform: translateY(20px);
|
||||
transition: all 0.6s ease-out;
|
||||
transition: opacity 0.6s ease-out, transform 0.6s ease-out;
|
||||
}
|
||||
|
||||
.animate-on-scroll.in-view {
|
||||
|
@@ -1,531 +1,74 @@
|
||||
// Simple translations object - we'll populate this directly to avoid import issues
|
||||
const translations = {
|
||||
en: {
|
||||
"meta": {
|
||||
"title": "Tiber365 - Professional IT Services",
|
||||
"description": "Professional IT services for freelancers and small businesses. Microsoft 365 support, networking solutions, web hosting, and custom IT projects.",
|
||||
"keywords": "IT services, Microsoft 365, networking, web hosting, automation, small business IT"
|
||||
},
|
||||
"nav": {
|
||||
"home": "Home",
|
||||
"services": "Services",
|
||||
"about": "About",
|
||||
"contact": "Contact",
|
||||
"blog": "Blog",
|
||||
"support": "Support",
|
||||
"language": "Language",
|
||||
"theme": {
|
||||
"toggle": "Toggle theme"
|
||||
}
|
||||
},
|
||||
"hero": {
|
||||
"title": "Professional IT Services for Your Business",
|
||||
"subtitle": "Empowering freelancers and small businesses with reliable Microsoft 365 support, networking solutions, web hosting, and custom IT projects.",
|
||||
"trusted": "Trusted by businesses across Italy",
|
||||
"cta": {
|
||||
"primary": "Get Started Today",
|
||||
"secondary": "View Our Services"
|
||||
}
|
||||
},
|
||||
"services": {
|
||||
"title": "Our Services",
|
||||
"subtitle": "Comprehensive IT solutions tailored for small businesses and freelancers",
|
||||
"viewAll": "View All Services",
|
||||
"microsoft365": {
|
||||
"title": "Microsoft 365 Support",
|
||||
"description": "Complete Microsoft 365 setup, migration, and ongoing support for your business.",
|
||||
"features": {
|
||||
"migrations": "Email & data migrations",
|
||||
"apps": "Office apps configuration",
|
||||
"teams": "Microsoft Teams setup",
|
||||
"sharepoint": "SharePoint collaboration",
|
||||
"admin": "Admin portal management"
|
||||
}
|
||||
},
|
||||
"management": {
|
||||
"title": "Full M365 Management",
|
||||
"description": "Let us handle your entire Microsoft 365 environment with proactive management.",
|
||||
"features": {
|
||||
"automation": "Automated workflows",
|
||||
"monitoring": "24/7 system monitoring",
|
||||
"maintenance": "Regular maintenance",
|
||||
"optimization": "Performance optimization"
|
||||
}
|
||||
},
|
||||
"networking": {
|
||||
"title": "Networking & Infrastructure",
|
||||
"description": "Professional networking solutions using Ubiquiti and UniFi equipment.",
|
||||
"features": {
|
||||
"ubiquiti": "Ubiquiti/UniFi specialists",
|
||||
"infrastructure": "Network infrastructure",
|
||||
"security": "Network security",
|
||||
"monitoring": "Traffic monitoring"
|
||||
}
|
||||
},
|
||||
"hosting": {
|
||||
"title": "Web Hosting & Management",
|
||||
"description": "Reliable web hosting with full management and maintenance included.",
|
||||
"features": {
|
||||
"webhosting": "Reliable web hosting",
|
||||
"domains": "Domain management",
|
||||
"ssl": "SSL certificates",
|
||||
"backup": "Automated backups"
|
||||
}
|
||||
},
|
||||
"custom": {
|
||||
"title": "Custom IT Projects",
|
||||
"description": "Tailored IT solutions designed specifically for your business needs.",
|
||||
"features": {
|
||||
"consultation": "IT consultation",
|
||||
"development": "Custom development",
|
||||
"integration": "System integration",
|
||||
"support": "Ongoing support"
|
||||
}
|
||||
}
|
||||
},
|
||||
"testimonials": {
|
||||
"title": "What Our Clients Say",
|
||||
"subtitle": "Don't just take our word for it - see what our satisfied clients have to say",
|
||||
"1": {
|
||||
"name": "Marco Rossi",
|
||||
"company": "Freelance Designer",
|
||||
"content": "Tiber365 transformed our Microsoft 365 setup. Professional service and excellent support!"
|
||||
},
|
||||
"2": {
|
||||
"name": "Sofia Bianchi",
|
||||
"company": "Small Business Owner",
|
||||
"content": "Their networking solutions are top-notch. Our office runs smoothly thanks to their expertise."
|
||||
},
|
||||
"3": {
|
||||
"name": "Giuseppe Verdi",
|
||||
"company": "Consultant",
|
||||
"content": "Reliable web hosting and great customer service. Highly recommend Tiber365!"
|
||||
}
|
||||
},
|
||||
"about": {
|
||||
"title": "About Us",
|
||||
"subtitle": "Your trusted IT partner",
|
||||
"description": "We specialize in providing comprehensive IT services to freelancers and small businesses.",
|
||||
"mission": "Our mission is to make technology work for you, not against you.",
|
||||
"experience": "Years of Experience",
|
||||
"clients": "Happy Clients",
|
||||
"projects": "Projects Completed"
|
||||
},
|
||||
"contact": {
|
||||
"title": "Get In Touch",
|
||||
"subtitle": "Ready to transform your IT infrastructure? Let's talk!",
|
||||
"info": {
|
||||
"email": "info@tiber365.it",
|
||||
"phone": "+39 123 456 7890",
|
||||
"address": "Rome, Italy"
|
||||
},
|
||||
"form": {
|
||||
"name": "Name",
|
||||
"email": "Email",
|
||||
"company": "Company",
|
||||
"service": "Service",
|
||||
"message": "Message",
|
||||
"send": "Send Message"
|
||||
}
|
||||
},
|
||||
"cta": {
|
||||
"title": "Ready to Get Started?",
|
||||
"subtitle": "Let's discuss how we can help transform your IT infrastructure.",
|
||||
"button": "Contact Us Today"
|
||||
},
|
||||
"footer": {
|
||||
"description": "Professional IT services for freelancers and small businesses.",
|
||||
"copyright": "© 2024 Tiber365. All rights reserved.",
|
||||
"links": {
|
||||
"contact": "Contact",
|
||||
"privacy": "Privacy Policy",
|
||||
"terms": "Terms of Service"
|
||||
}
|
||||
},
|
||||
"404": {
|
||||
"title": "Page Not Found",
|
||||
"description": "Sorry, we couldn't find the page you're looking for.",
|
||||
"button": "Go back home"
|
||||
}
|
||||
},
|
||||
nl: {
|
||||
"meta": {
|
||||
"title": "Tiber365 - Professionele IT Services",
|
||||
"description": "Professionele IT-diensten voor freelancers en kleine bedrijven. Microsoft 365 ondersteuning, netwerkoplossingen, webhosting en aangepaste IT-projecten.",
|
||||
"keywords": "IT diensten, Microsoft 365, netwerken, webhosting, automatisering, kleine bedrijven IT"
|
||||
},
|
||||
"nav": {
|
||||
"home": "Home",
|
||||
"services": "Diensten",
|
||||
"about": "Over Ons",
|
||||
"contact": "Contact",
|
||||
"blog": "Blog",
|
||||
"support": "Ondersteuning",
|
||||
"language": "Taal",
|
||||
"theme": {
|
||||
"toggle": "Thema wisselen"
|
||||
}
|
||||
},
|
||||
"hero": {
|
||||
"title": "Professionele IT Services voor Uw Bedrijf",
|
||||
"subtitle": "Ondersteuning van freelancers en kleine bedrijven met betrouwbare Microsoft 365 ondersteuning, netwerkoplossingen, webhosting en aangepaste IT-projecten.",
|
||||
"trusted": "Vertrouwd door bedrijven in heel Italië",
|
||||
"cta": {
|
||||
"primary": "Begin Vandaag",
|
||||
"secondary": "Bekijk Onze Diensten"
|
||||
}
|
||||
},
|
||||
"services": {
|
||||
"title": "Onze Diensten",
|
||||
"subtitle": "Uitgebreide IT-oplossingen op maat voor kleine bedrijven en freelancers",
|
||||
"viewAll": "Alle Diensten Bekijken",
|
||||
"microsoft365": {
|
||||
"title": "Microsoft 365 Ondersteuning",
|
||||
"description": "Complete Microsoft 365 installatie, migratie en doorlopende ondersteuning.",
|
||||
"features": {
|
||||
"migrations": "E-mail & data migraties",
|
||||
"apps": "Office apps configuratie",
|
||||
"teams": "Microsoft Teams installatie",
|
||||
"sharepoint": "SharePoint samenwerking",
|
||||
"admin": "Beheerportaal management"
|
||||
}
|
||||
},
|
||||
"management": {
|
||||
"title": "Volledig M365 Beheer",
|
||||
"description": "Laat ons uw volledige Microsoft 365 omgeving beheren met proactief management.",
|
||||
"features": {
|
||||
"automation": "Geautomatiseerde workflows",
|
||||
"monitoring": "24/7 systeembewaking",
|
||||
"maintenance": "Regelmatig onderhoud",
|
||||
"optimization": "Prestatie optimalisatie"
|
||||
}
|
||||
},
|
||||
"networking": {
|
||||
"title": "Netwerken & Infrastructuur",
|
||||
"description": "Professionele netwerkoplossingen met Ubiquiti en UniFi apparatuur.",
|
||||
"features": {
|
||||
"ubiquiti": "Ubiquiti/UniFi specialisten",
|
||||
"infrastructure": "Netwerkinfrastructuur",
|
||||
"security": "Netwerkbeveiliging",
|
||||
"monitoring": "Verkeer monitoring"
|
||||
}
|
||||
},
|
||||
"hosting": {
|
||||
"title": "Webhosting & Beheer",
|
||||
"description": "Betrouwbare webhosting met volledig beheer en onderhoud inbegrepen.",
|
||||
"features": {
|
||||
"webhosting": "Betrouwbare webhosting",
|
||||
"domains": "Domeinbeheer",
|
||||
"ssl": "SSL certificaten",
|
||||
"backup": "Geautomatiseerde backups"
|
||||
}
|
||||
},
|
||||
"custom": {
|
||||
"title": "Aangepaste IT Projecten",
|
||||
"description": "Op maat gemaakte IT-oplossingen speciaal ontworpen voor uw bedrijfsbehoeften.",
|
||||
"features": {
|
||||
"consultation": "IT consultatie",
|
||||
"development": "Aangepaste ontwikkeling",
|
||||
"integration": "Systeemintegratie",
|
||||
"support": "Doorlopende ondersteuning"
|
||||
}
|
||||
}
|
||||
},
|
||||
"testimonials": {
|
||||
"title": "Wat Onze Klanten Zeggen",
|
||||
"subtitle": "Geloof ons niet zomaar - zie wat onze tevreden klanten te zeggen hebben",
|
||||
"1": {
|
||||
"name": "Marco Rossi",
|
||||
"company": "Freelance Designer",
|
||||
"content": "Tiber365 heeft onze Microsoft 365 installatie getransformeerd. Professionele service en uitstekende ondersteuning!"
|
||||
},
|
||||
"2": {
|
||||
"name": "Sofia Bianchi",
|
||||
"company": "Kleine Bedrijfseigenaar",
|
||||
"content": "Hun netwerkoplossingen zijn eersteklas. Ons kantoor draait soepel dankzij hun expertise."
|
||||
},
|
||||
"3": {
|
||||
"name": "Giuseppe Verdi",
|
||||
"company": "Consultant",
|
||||
"content": "Betrouwbare webhosting en geweldige klantenservice. Beveel Tiber365 ten zeerste aan!"
|
||||
}
|
||||
},
|
||||
"about": {
|
||||
"title": "Over Ons",
|
||||
"subtitle": "Uw vertrouwde IT-partner",
|
||||
"description": "Wij zijn gespecialiseerd in het leveren van uitgebreide IT-diensten aan freelancers en kleine bedrijven.",
|
||||
"mission": "Onze missie is om technologie voor u te laten werken, niet tegen u.",
|
||||
"experience": "Jaren Ervaring",
|
||||
"clients": "Tevreden Klanten",
|
||||
"projects": "Voltooide Projecten"
|
||||
},
|
||||
"contact": {
|
||||
"title": "Neem Contact Op",
|
||||
"subtitle": "Klaar om uw IT-infrastructuur te transformeren? Laten we praten!",
|
||||
"info": {
|
||||
"email": "info@tiber365.it",
|
||||
"phone": "+39 123 456 7890",
|
||||
"address": "Rome, Italië"
|
||||
},
|
||||
"form": {
|
||||
"name": "Naam",
|
||||
"email": "E-mail",
|
||||
"company": "Bedrijf",
|
||||
"service": "Dienst",
|
||||
"message": "Bericht",
|
||||
"send": "Bericht Versturen"
|
||||
}
|
||||
},
|
||||
"cta": {
|
||||
"title": "Klaar om te Beginnen?",
|
||||
"subtitle": "Laten we bespreken hoe wij uw IT-infrastructuur kunnen transformeren.",
|
||||
"button": "Neem Vandaag Contact Op"
|
||||
},
|
||||
"footer": {
|
||||
"description": "Professionele IT-diensten voor freelancers en kleine bedrijven.",
|
||||
"copyright": "© 2024 Tiber365. Alle rechten voorbehouden.",
|
||||
"links": {
|
||||
"contact": "Contact",
|
||||
"privacy": "Privacybeleid",
|
||||
"terms": "Servicevoorwaarden"
|
||||
}
|
||||
},
|
||||
"404": {
|
||||
"title": "Pagina Niet Gevonden",
|
||||
"description": "Sorry, we konden de pagina die u zoekt niet vinden.",
|
||||
"button": "Ga terug naar home"
|
||||
}
|
||||
},
|
||||
it: {
|
||||
"meta": {
|
||||
"title": "Tiber365 - Servizi IT Professionali",
|
||||
"description": "Servizi IT professionali per freelancer e piccole imprese. Supporto Microsoft 365, soluzioni di rete, hosting web e progetti IT personalizzati.",
|
||||
"keywords": "servizi IT, Microsoft 365, networking, web hosting, automazione, IT piccole imprese"
|
||||
},
|
||||
"nav": {
|
||||
"home": "Home",
|
||||
"services": "Servizi",
|
||||
"about": "Chi Siamo",
|
||||
"contact": "Contatti",
|
||||
"blog": "Blog",
|
||||
"support": "Supporto",
|
||||
"language": "Lingua",
|
||||
"theme": {
|
||||
"toggle": "Cambia tema"
|
||||
}
|
||||
},
|
||||
"hero": {
|
||||
"title": "Servizi IT Professionali per la Tua Azienda",
|
||||
"subtitle": "Supportiamo freelancer e piccole imprese con supporto Microsoft 365 affidabile, soluzioni di rete, hosting web e progetti IT personalizzati.",
|
||||
"trusted": "Fidato dalle aziende in tutta Italia",
|
||||
"cta": {
|
||||
"primary": "Inizia Oggi",
|
||||
"secondary": "Vedi i Nostri Servizi"
|
||||
}
|
||||
},
|
||||
"services": {
|
||||
"title": "I Nostri Servizi",
|
||||
"subtitle": "Soluzioni IT complete su misura per piccole imprese e freelancer",
|
||||
"viewAll": "Vedi Tutti i Servizi",
|
||||
"microsoft365": {
|
||||
"title": "Supporto Microsoft 365",
|
||||
"description": "Installazione completa, migrazione e supporto continuo per Microsoft 365.",
|
||||
"features": {
|
||||
"migrations": "Migrazioni email e dati",
|
||||
"apps": "Configurazione app Office",
|
||||
"teams": "Configurazione Microsoft Teams",
|
||||
"sharepoint": "Collaborazione SharePoint",
|
||||
"admin": "Gestione portale amministratore"
|
||||
}
|
||||
},
|
||||
"management": {
|
||||
"title": "Gestione Completa M365",
|
||||
"description": "Lascia che ci occupiamo dell'intero ambiente Microsoft 365 con gestione proattiva.",
|
||||
"features": {
|
||||
"automation": "Flussi di lavoro automatizzati",
|
||||
"monitoring": "Monitoraggio sistema 24/7",
|
||||
"maintenance": "Manutenzione regolare",
|
||||
"optimization": "Ottimizzazione prestazioni"
|
||||
}
|
||||
},
|
||||
"networking": {
|
||||
"title": "Networking e Infrastruttura",
|
||||
"description": "Soluzioni di rete professionali con apparecchiature Ubiquiti e UniFi.",
|
||||
"features": {
|
||||
"ubiquiti": "Specialisti Ubiquiti/UniFi",
|
||||
"infrastructure": "Infrastruttura di rete",
|
||||
"security": "Sicurezza di rete",
|
||||
"monitoring": "Monitoraggio traffico"
|
||||
}
|
||||
},
|
||||
"hosting": {
|
||||
"title": "Web Hosting e Gestione",
|
||||
"description": "Hosting web affidabile con gestione completa e manutenzione inclusa.",
|
||||
"features": {
|
||||
"webhosting": "Hosting web affidabile",
|
||||
"domains": "Gestione domini",
|
||||
"ssl": "Certificati SSL",
|
||||
"backup": "Backup automatizzati"
|
||||
}
|
||||
},
|
||||
"custom": {
|
||||
"title": "Progetti IT Personalizzati",
|
||||
"description": "Soluzioni IT su misura progettate specificamente per le tue esigenze aziendali.",
|
||||
"features": {
|
||||
"consultation": "Consulenza IT",
|
||||
"development": "Sviluppo personalizzato",
|
||||
"integration": "Integrazione sistemi",
|
||||
"support": "Supporto continuo"
|
||||
}
|
||||
}
|
||||
},
|
||||
"testimonials": {
|
||||
"title": "Cosa Dicono i Nostri Clienti",
|
||||
"subtitle": "Non prendere solo la nostra parola - vedi cosa hanno da dire i nostri clienti soddisfatti",
|
||||
"1": {
|
||||
"name": "Marco Rossi",
|
||||
"company": "Designer Freelance",
|
||||
"content": "Tiber365 ha trasformato la nostra configurazione Microsoft 365. Servizio professionale e supporto eccellente!"
|
||||
},
|
||||
"2": {
|
||||
"name": "Sofia Bianchi",
|
||||
"company": "Proprietaria Piccola Impresa",
|
||||
"content": "Le loro soluzioni di rete sono di prim'ordine. Il nostro ufficio funziona perfettamente grazie alla loro competenza."
|
||||
},
|
||||
"3": {
|
||||
"name": "Giuseppe Verdi",
|
||||
"company": "Consulente",
|
||||
"content": "Hosting web affidabile e ottimo servizio clienti. Raccomando vivamente Tiber365!"
|
||||
}
|
||||
},
|
||||
"about": {
|
||||
"title": "Chi Siamo",
|
||||
"subtitle": "Il tuo partner IT di fiducia",
|
||||
"description": "Siamo specializzati nel fornire servizi IT completi a freelancer e piccole imprese.",
|
||||
"mission": "La nostra missione è far sì che la tecnologia lavori per te, non contro di te.",
|
||||
"experience": "Anni di Esperienza",
|
||||
"clients": "Clienti Soddisfatti",
|
||||
"projects": "Progetti Completati"
|
||||
},
|
||||
"contact": {
|
||||
"title": "Contattaci",
|
||||
"subtitle": "Pronto a trasformare la tua infrastruttura IT? Parliamone!",
|
||||
"info": {
|
||||
"email": "info@tiber365.it",
|
||||
"phone": "+39 123 456 7890",
|
||||
"address": "Roma, Italia"
|
||||
},
|
||||
"form": {
|
||||
"name": "Nome",
|
||||
"email": "Email",
|
||||
"company": "Azienda",
|
||||
"service": "Servizio",
|
||||
"message": "Messaggio",
|
||||
"send": "Invia Messaggio"
|
||||
}
|
||||
},
|
||||
"cta": {
|
||||
"title": "Pronto per Iniziare?",
|
||||
"subtitle": "Discutiamo di come possiamo aiutare a trasformare la tua infrastruttura IT.",
|
||||
"button": "Contattaci Oggi"
|
||||
},
|
||||
"footer": {
|
||||
"description": "Servizi IT professionali per freelancer e piccole imprese.",
|
||||
"copyright": "© 2024 Tiber365. Tutti i diritti riservati.",
|
||||
"links": {
|
||||
"contact": "Contatti",
|
||||
"privacy": "Privacy Policy",
|
||||
"terms": "Termini di Servizio"
|
||||
}
|
||||
},
|
||||
"404": {
|
||||
"title": "Pagina Non Trovata",
|
||||
"description": "Spiacenti, non siamo riusciti a trovare la pagina che stai cercando.",
|
||||
"button": "Torna alla home"
|
||||
}
|
||||
}
|
||||
} as const;
|
||||
// Updated i18n utils for Astro's built-in i18n system
|
||||
import enTranslations from '../content/i18n/en.json';
|
||||
import nlTranslations from '../content/i18n/nl.json';
|
||||
import deTranslations from '../content/i18n/de.json';
|
||||
import frTranslations from '../content/i18n/fr.json';
|
||||
|
||||
type TranslationKey = string;
|
||||
type Locale = 'en' | 'nl' | 'it';
|
||||
export const SUPPORTED_LOCALES = ['en', 'nl', 'de', 'fr'] as const;
|
||||
export type Locale = typeof SUPPORTED_LOCALES[number];
|
||||
|
||||
export const SUPPORTED_LOCALES: Locale[] = ['en', 'nl', 'it'];
|
||||
export const languages = {
|
||||
en: { name: 'English', flag: '🇬🇧' },
|
||||
nl: { name: 'Nederlands', flag: '🇳🇱' },
|
||||
de: { name: 'Deutsch', flag: '🇩🇪' },
|
||||
fr: { name: 'Français', flag: '🇫🇷' }
|
||||
};
|
||||
|
||||
// Function to get current locale that works on both client and server
|
||||
function getCurrentLocaleFromStorage(): Locale {
|
||||
if (typeof window !== 'undefined') {
|
||||
try {
|
||||
const savedLocale = localStorage.getItem('tiber365-locale') as Locale;
|
||||
if (savedLocale && SUPPORTED_LOCALES.includes(savedLocale)) {
|
||||
return savedLocale;
|
||||
}
|
||||
} catch (error) {
|
||||
console.warn('Error accessing localStorage:', error);
|
||||
}
|
||||
export function getLangFromUrl(url: URL): Locale {
|
||||
const [, lang] = url.pathname.split('/');
|
||||
if (lang && SUPPORTED_LOCALES.includes(lang as Locale)) {
|
||||
return lang as Locale;
|
||||
}
|
||||
return 'en';
|
||||
}
|
||||
|
||||
// Function to get translations for a specific locale
|
||||
function getTranslations(locale: Locale): any {
|
||||
if (!translations[locale]) {
|
||||
console.warn(`No translations found for locale "${locale}", falling back to English`);
|
||||
return translations['en'];
|
||||
}
|
||||
return translations[locale];
|
||||
}
|
||||
// Load translations directly from JSON files
|
||||
const translations: Record<Locale, any> = {
|
||||
en: enTranslations,
|
||||
nl: nlTranslations,
|
||||
de: deTranslations,
|
||||
fr: frTranslations
|
||||
};
|
||||
|
||||
export function t(key: TranslationKey, locale?: Locale): string {
|
||||
try {
|
||||
// Get the current locale
|
||||
const targetLocale = locale || getCurrentLocaleFromStorage();
|
||||
|
||||
// Split the key into parts
|
||||
export async function useTranslations(lang: Locale) {
|
||||
const translationData = translations[lang] || translations.en || {};
|
||||
|
||||
return function t(key: string): string {
|
||||
const keys = key.split('.');
|
||||
let value: any = translationData;
|
||||
|
||||
// Start with the translations for the target locale
|
||||
let value: any = translations[targetLocale];
|
||||
|
||||
// Traverse the object using the key parts
|
||||
for (const k of keys) {
|
||||
value = value?.[k];
|
||||
if (value === undefined) {
|
||||
console.warn(`Translation missing for key "${key}" in locale "${targetLocale}"`);
|
||||
break;
|
||||
if (value === undefined) break;
|
||||
}
|
||||
|
||||
// Fallback to English if translation missing
|
||||
if (value === undefined && lang !== 'en') {
|
||||
let fallback: any = translations.en;
|
||||
for (const k of keys) {
|
||||
fallback = fallback?.[k];
|
||||
if (fallback === undefined) break;
|
||||
}
|
||||
value = fallback;
|
||||
}
|
||||
|
||||
// If value is not found in target locale, try English as fallback
|
||||
if (!value && targetLocale !== 'en') {
|
||||
console.warn(`Falling back to English for key "${key}"`);
|
||||
value = t(key, 'en');
|
||||
}
|
||||
|
||||
// Return the translation or fallback to the key itself
|
||||
return value || key;
|
||||
} catch (error) {
|
||||
console.error(`Translation error for key "${key}":`, error);
|
||||
return key;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// Simple translation function for components that don't need async
|
||||
export function t(key: string): string {
|
||||
// This is a fallback - in practice, components should use useTranslations
|
||||
return key;
|
||||
}
|
||||
|
||||
export function getCurrentLocale(): Locale {
|
||||
const locale = getCurrentLocaleFromStorage();
|
||||
return locale;
|
||||
return 'en';
|
||||
}
|
||||
|
||||
export function setCurrentLocale(locale: Locale): void {
|
||||
if (SUPPORTED_LOCALES.includes(locale)) {
|
||||
if (typeof window !== 'undefined') {
|
||||
try {
|
||||
localStorage.setItem('tiber365-locale', locale);
|
||||
// Force a hard reload to ensure all components re-render with new language
|
||||
window.location.href = window.location.href;
|
||||
} catch (error) {
|
||||
console.error('Error setting localStorage:', error);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
console.error(`Invalid locale: "${locale}"`);
|
||||
export function localizePath(path: string, locale: Locale): string {
|
||||
if (locale === 'en') {
|
||||
return path;
|
||||
}
|
||||
}
|
||||
return `/${locale}${path}`;
|
||||
}
|
68
src/utils/performance.ts
Normal file
68
src/utils/performance.ts
Normal file
@@ -0,0 +1,68 @@
|
||||
// Performance monitoring utility
|
||||
export function initPerformanceMonitoring() {
|
||||
// Monitor Core Web Vitals
|
||||
if ('PerformanceObserver' in window) {
|
||||
// LCP (Largest Contentful Paint)
|
||||
const lcpObserver = new PerformanceObserver((list) => {
|
||||
const entries = list.getEntries();
|
||||
const lastEntry = entries[entries.length - 1];
|
||||
console.log('LCP:', lastEntry.startTime);
|
||||
|
||||
// Send to analytics if needed
|
||||
if (lastEntry.startTime < 2500) {
|
||||
console.log('✅ LCP is good');
|
||||
} else {
|
||||
console.log('⚠️ LCP needs improvement');
|
||||
}
|
||||
});
|
||||
lcpObserver.observe({ entryTypes: ['largest-contentful-paint'] });
|
||||
|
||||
// FID (First Input Delay)
|
||||
const fidObserver = new PerformanceObserver((list) => {
|
||||
const entries = list.getEntries();
|
||||
entries.forEach((entry) => {
|
||||
const fidEntry = entry as PerformanceEventTiming;
|
||||
console.log('FID:', fidEntry.processingStart - fidEntry.startTime);
|
||||
|
||||
if (fidEntry.processingStart - fidEntry.startTime < 100) {
|
||||
console.log('✅ FID is good');
|
||||
} else {
|
||||
console.log('⚠️ FID needs improvement');
|
||||
}
|
||||
});
|
||||
});
|
||||
fidObserver.observe({ entryTypes: ['first-input'] });
|
||||
|
||||
// CLS (Cumulative Layout Shift)
|
||||
const clsObserver = new PerformanceObserver((list) => {
|
||||
let clsValue = 0;
|
||||
const entries = list.getEntries();
|
||||
entries.forEach((entry: any) => {
|
||||
if (!entry.hadRecentInput) {
|
||||
clsValue += entry.value;
|
||||
}
|
||||
});
|
||||
console.log('CLS:', clsValue);
|
||||
|
||||
if (clsValue < 0.1) {
|
||||
console.log('✅ CLS is good');
|
||||
} else {
|
||||
console.log('⚠️ CLS needs improvement');
|
||||
}
|
||||
});
|
||||
clsObserver.observe({ entryTypes: ['layout-shift'] });
|
||||
}
|
||||
|
||||
// Monitor page load time
|
||||
window.addEventListener('load', () => {
|
||||
const loadTime = performance.now();
|
||||
console.log('Page load time:', loadTime);
|
||||
|
||||
// Navigation timing
|
||||
const navigation = performance.getEntriesByType('navigation')[0] as PerformanceNavigationTiming;
|
||||
if (navigation) {
|
||||
console.log('DOM Content Loaded:', navigation.domContentLoadedEventEnd - navigation.domContentLoadedEventStart);
|
||||
console.log('Load Complete:', navigation.loadEventEnd - navigation.loadEventStart);
|
||||
}
|
||||
});
|
||||
}
|
Reference in New Issue
Block a user