339 lines
10 KiB
TypeScript
339 lines
10 KiB
TypeScript
export type Locale = 'en' | 'de';
|
|
|
|
export const defaultLocale: Locale = 'en';
|
|
export const locales: Locale[] = ['en', 'de'];
|
|
|
|
// Simple translation dictionary
|
|
const translations = {
|
|
en: {
|
|
site: {
|
|
title: 'Kabel-Konfigurator',
|
|
description: 'Professional cable solutions - configure and order custom cables',
|
|
},
|
|
nav: {
|
|
home: 'Home',
|
|
blog: 'Blog',
|
|
products: 'Products',
|
|
contact: 'Contact',
|
|
privacy: 'Privacy Policy',
|
|
legal: 'Legal Notice',
|
|
terms: 'Terms & Conditions',
|
|
},
|
|
home: {
|
|
hero: 'Professional Cable Solutions',
|
|
heroSubtitle: 'Configure your custom cables online',
|
|
cta: 'Configure Now',
|
|
featuredPosts: 'Latest News',
|
|
featuredProducts: 'Featured Products',
|
|
},
|
|
blog: {
|
|
title: 'Blog',
|
|
description: 'Latest news and insights about cables and energy',
|
|
readMore: 'Read more',
|
|
noPosts: 'No posts available.',
|
|
backToBlog: '← Back to Blog',
|
|
categories: 'Categories',
|
|
featured: 'Featured Posts',
|
|
allPosts: 'All Posts',
|
|
noPostsDescription: 'Check back soon for new content.',
|
|
},
|
|
products: {
|
|
title: 'Products',
|
|
categories: 'Categories',
|
|
noProducts: 'No products available.',
|
|
noCategories: 'No categories available.',
|
|
inStock: 'In Stock',
|
|
outOfStock: 'Out of Stock',
|
|
price: 'Price',
|
|
sku: 'SKU',
|
|
viewAll: 'View All Products',
|
|
},
|
|
product: {
|
|
backToProducts: '← Back to Products',
|
|
description: 'Description',
|
|
specifications: 'Specifications',
|
|
price: 'Price',
|
|
sku: 'SKU',
|
|
stock: 'Stock Status',
|
|
inStock: 'In Stock',
|
|
outOfStock: 'Out of Stock',
|
|
},
|
|
productCategory: {
|
|
backToCategories: '← Back to Categories',
|
|
productsInCategory: 'Products in this category',
|
|
},
|
|
contact: {
|
|
title: 'Contact Us',
|
|
subtitle: 'Get in touch with our team',
|
|
name: 'Your Name',
|
|
email: 'Your Email',
|
|
message: 'Your Message',
|
|
submit: 'Send Message',
|
|
success: 'Message sent successfully!',
|
|
error: 'Failed to send message. Please try again.',
|
|
processing: 'Sending...',
|
|
phone: 'Phone (optional)',
|
|
subject: 'Subject',
|
|
company: 'Company (optional)',
|
|
requiredFields: 'Required fields are marked with *',
|
|
sending: 'Sending...',
|
|
errors: {
|
|
nameRequired: 'Please enter your name',
|
|
emailRequired: 'Please enter your email address',
|
|
emailInvalid: 'Please enter a valid email address',
|
|
messageRequired: 'Please enter your message',
|
|
},
|
|
},
|
|
consent: {
|
|
title: 'Cookie & Analytics Consent',
|
|
description: 'We use analytics cookies to improve our website. Please accept to continue.',
|
|
accept: 'Accept',
|
|
decline: 'Decline',
|
|
analytics: 'Analytics',
|
|
analyticsDesc: 'Help us understand how visitors use our site',
|
|
},
|
|
cookieConsent: {
|
|
message: 'We use cookies to enhance your browsing experience and analyze our traffic.',
|
|
privacyPolicy: 'Privacy Policy',
|
|
decline: 'Decline',
|
|
accept: 'Accept',
|
|
},
|
|
footer: {
|
|
rights: 'All rights reserved.',
|
|
madeWith: 'Made with Next.js',
|
|
},
|
|
common: {
|
|
readMore: 'Read more',
|
|
back: 'Back',
|
|
loading: 'Loading...',
|
|
noContent: 'No content available.',
|
|
date: 'Date',
|
|
updated: 'Updated',
|
|
},
|
|
form: {
|
|
success: 'Message sent successfully!',
|
|
error: {
|
|
submit: 'Failed to send message. Please try again.',
|
|
network: 'Network error. Please try again.',
|
|
},
|
|
sending: 'Sending...',
|
|
name: 'Your Name',
|
|
email: 'Your Email',
|
|
message: 'Your Message',
|
|
submit: 'Send Message',
|
|
},
|
|
},
|
|
de: {
|
|
site: {
|
|
title: 'Kabel-Konfigurator',
|
|
description: 'Professionelle Kabel-Lösungen - konfigurieren und bestellen Sie maßgeschneiderte Kabel',
|
|
},
|
|
nav: {
|
|
home: 'Startseite',
|
|
blog: 'Blog',
|
|
products: 'Produkte',
|
|
contact: 'Kontakt',
|
|
privacy: 'Datenschutz',
|
|
legal: 'Impressum',
|
|
terms: 'AGB',
|
|
},
|
|
home: {
|
|
hero: 'Professionelle Kabel-Lösungen',
|
|
heroSubtitle: 'Konfigurieren Sie Ihre maßgeschneiderten Kabel online',
|
|
cta: 'Jetzt konfigurieren',
|
|
featuredPosts: 'Aktuelle Neuigkeiten',
|
|
featuredProducts: 'Empfohlene Produkte',
|
|
},
|
|
blog: {
|
|
title: 'Blog',
|
|
description: 'Aktuelle Neuigkeiten und Einblicke über Kabel und Energie',
|
|
readMore: 'Weiterlesen',
|
|
noPosts: 'Keine Beiträge verfügbar.',
|
|
backToBlog: '← Zurück zum Blog',
|
|
categories: 'Kategorien',
|
|
featured: 'Beiträge',
|
|
allPosts: 'Alle Beiträge',
|
|
noPostsDescription: 'Schauen Sie bald wieder vorbei für neue Inhalte.',
|
|
},
|
|
products: {
|
|
title: 'Produkte',
|
|
categories: 'Kategorien',
|
|
noProducts: 'Keine Produkte verfügbar.',
|
|
noCategories: 'Keine Kategorien verfügbar.',
|
|
inStock: 'Auf Lager',
|
|
outOfStock: 'Nicht auf Lager',
|
|
price: 'Preis',
|
|
sku: 'Artikelnummer',
|
|
viewAll: 'Alle Produkte anzeigen',
|
|
},
|
|
product: {
|
|
backToProducts: '← Zurück zu Produkten',
|
|
description: 'Beschreibung',
|
|
specifications: 'Spezifikationen',
|
|
price: 'Preis',
|
|
sku: 'Artikelnummer',
|
|
stock: 'Lagerbestand',
|
|
inStock: 'Auf Lager',
|
|
outOfStock: 'Nicht auf Lager',
|
|
},
|
|
productCategory: {
|
|
backToCategories: '← Zurück zu Kategorien',
|
|
productsInCategory: 'Produkte in dieser Kategorie',
|
|
},
|
|
contact: {
|
|
title: 'Kontakt',
|
|
subtitle: 'Nehmen Sie Kontakt mit unserem Team auf',
|
|
name: 'Ihr Name',
|
|
email: 'Ihre E-Mail',
|
|
message: 'Ihre Nachricht',
|
|
submit: 'Nachricht senden',
|
|
success: 'Nachricht erfolgreich gesendet!',
|
|
error: 'Nachricht konnte nicht gesendet werden. Bitte versuchen Sie es erneut.',
|
|
processing: 'Wird gesendet...',
|
|
phone: 'Telefon (optional)',
|
|
subject: 'Betreff',
|
|
company: 'Firma (optional)',
|
|
requiredFields: 'Pflichtfelder sind mit * markiert',
|
|
sending: 'Wird gesendet...',
|
|
errors: {
|
|
nameRequired: 'Bitte geben Sie Ihren Namen ein',
|
|
emailRequired: 'Bitte geben Sie Ihre E-Mail-Adresse ein',
|
|
emailInvalid: 'Bitte geben Sie eine gültige E-Mail-Adresse ein',
|
|
messageRequired: 'Bitte geben Sie Ihre Nachricht ein',
|
|
},
|
|
},
|
|
consent: {
|
|
title: 'Cookie- & Analyse-Einwilligung',
|
|
description: 'Wir verwenden Analyse-Cookies, um unsere Website zu verbessern. Bitte akzeptieren Sie zur Fortsetzung.',
|
|
accept: 'Akzeptieren',
|
|
decline: 'Ablehnen',
|
|
analytics: 'Analyse',
|
|
analyticsDesc: 'Helfen Sie uns zu verstehen, wie Besucher unsere Seite nutzen',
|
|
},
|
|
cookieConsent: {
|
|
message: 'Wir verwenden Cookies, um Ihr Surferlebnis zu verbessern und unseren Traffic zu analysieren.',
|
|
privacyPolicy: 'Datenschutzrichtlinie',
|
|
decline: 'Ablehnen',
|
|
accept: 'Akzeptieren',
|
|
},
|
|
footer: {
|
|
rights: 'Alle Rechte vorbehalten.',
|
|
madeWith: 'Erstellt mit Next.js',
|
|
},
|
|
common: {
|
|
readMore: 'Weiterlesen',
|
|
back: 'Zurück',
|
|
loading: 'Wird geladen...',
|
|
noContent: 'Kein Inhalt verfügbar.',
|
|
date: 'Datum',
|
|
updated: 'Aktualisiert',
|
|
},
|
|
form: {
|
|
success: 'Nachricht erfolgreich gesendet!',
|
|
error: {
|
|
submit: 'Nachricht konnte nicht gesendet werden. Bitte versuchen Sie es erneut.',
|
|
network: 'Netzwerkfehler. Bitte versuchen Sie es erneut.',
|
|
},
|
|
sending: 'Wird gesendet...',
|
|
name: 'Ihr Name',
|
|
email: 'Ihre E-Mail',
|
|
message: 'Ihre Nachricht',
|
|
submit: 'Nachricht senden',
|
|
},
|
|
},
|
|
};
|
|
|
|
export function t(key: string, locale: Locale = 'en'): string {
|
|
const keys = key.split('.');
|
|
let value: any = translations[locale];
|
|
|
|
for (const k of keys) {
|
|
if (value && typeof value === 'object' && k in value) {
|
|
value = value[k];
|
|
} else {
|
|
// Fallback to English
|
|
value = translations.en;
|
|
for (const k2 of keys) {
|
|
if (value && typeof value === 'object' && k2 in value) {
|
|
value = value[k2];
|
|
} else {
|
|
return key; // Return the key itself if translation not found
|
|
}
|
|
}
|
|
return value;
|
|
}
|
|
}
|
|
|
|
// Ensure we always return a string
|
|
return typeof value === 'string' ? value : key;
|
|
}
|
|
|
|
export function getLocaleFromPath(path: string): Locale {
|
|
if (path.startsWith('/de/')) {
|
|
return 'de';
|
|
}
|
|
return 'en';
|
|
}
|
|
|
|
export function getLocalizedPath(path: string, locale: Locale): string {
|
|
if (locale === 'en') {
|
|
return path.replace('/de/', '/');
|
|
}
|
|
if (locale === 'de') {
|
|
if (path === '/') return '/de';
|
|
return path.startsWith('/de/') ? path : `/de${path}`;
|
|
}
|
|
return path;
|
|
}
|
|
|
|
export function getPathWithoutLocale(path: string): string {
|
|
if (path.startsWith('/de/')) {
|
|
return path.substring(3) || '/';
|
|
}
|
|
return path;
|
|
}
|
|
|
|
export const languageNames: Record<Locale, string> = {
|
|
en: 'English',
|
|
de: 'Deutsch',
|
|
};
|
|
|
|
export function getSiteInfo(locale?: Locale) {
|
|
const loc = locale || defaultLocale;
|
|
return {
|
|
title: t('site.title', loc),
|
|
description: t('site.description', loc),
|
|
locale: loc,
|
|
baseUrl: process.env.NEXT_PUBLIC_SITE_URL || 'https://example.com',
|
|
locales: ['en', 'de'],
|
|
};
|
|
}
|
|
|
|
// Hook for client components (simplified version)
|
|
export function useTranslation(namespace?: string) {
|
|
// This would be used in client components
|
|
// For now, return a simple t function
|
|
return {
|
|
t: (key: string) => t(namespace ? `${namespace}.${key}` : key, defaultLocale)
|
|
};
|
|
}
|
|
|
|
// Get alternate URLs for SEO
|
|
export function getAlternateUrls(path: string) {
|
|
return [
|
|
{ locale: 'en', url: path.replace('/de/', '/') },
|
|
{ locale: 'de', url: path.startsWith('/de') ? path : `/de${path}` },
|
|
];
|
|
}
|
|
|
|
// Hook for client components - returns current locale
|
|
export function useLocale(): Locale {
|
|
// This is a simplified version for build purposes
|
|
// In a real app, this would use next/navigation to get the current path
|
|
return defaultLocale;
|
|
}
|
|
|
|
// Get dictionary for client components
|
|
export function getDictionary(locale: Locale) {
|
|
return translations[locale];
|
|
} |