Update legal documents and localization for compliance and clarity
- Updated .env.example with legal operator details for compliance. - Refactored Impressum, Privacy, and Terms pages to utilize a new LegalDocument component for improved structure and maintainability. - Enhanced localization files to include legal content in both German and English, ensuring accurate representation of legal information. - Improved i18n handling to support locale detection from Accept-Language headers.
This commit is contained in:
@@ -1,18 +1,20 @@
|
||||
import { cookies } from 'next/headers';
|
||||
import { cookies, headers } from 'next/headers';
|
||||
import deMessages from '@/messages/de.json';
|
||||
import enMessages from '@/messages/en.json';
|
||||
import legalDe from '@/messages/legal-de.json';
|
||||
import legalEn from '@/messages/legal-en.json';
|
||||
import { env } from './env';
|
||||
|
||||
export type Locale = 'de' | 'en';
|
||||
|
||||
export const LOCALE_COOKIE_NAME = 'nexumi_locale';
|
||||
|
||||
export type Messages = typeof enMessages;
|
||||
export const MESSAGES = {
|
||||
de: { ...deMessages, legal: legalDe },
|
||||
en: { ...enMessages, legal: legalEn }
|
||||
} as const;
|
||||
|
||||
export const MESSAGES: Record<Locale, Messages> = {
|
||||
de: deMessages,
|
||||
en: enMessages
|
||||
};
|
||||
export type Messages = (typeof MESSAGES)['en'];
|
||||
|
||||
function resolve(messages: Messages, key: string): string | undefined {
|
||||
const value = key.split('.').reduce<unknown>((acc, part) => {
|
||||
@@ -43,12 +45,45 @@ function isLocale(value: string | undefined): value is Locale {
|
||||
return value === 'de' || value === 'en';
|
||||
}
|
||||
|
||||
function localeFromAcceptLanguage(header: string | null): Locale | undefined {
|
||||
if (!header) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const preferred = header
|
||||
.split(',')
|
||||
.map((part) => {
|
||||
const [tag, qValue] = part.trim().split(';q=');
|
||||
return { lang: tag.trim().toLowerCase().slice(0, 2), q: qValue ? Number(qValue) : 1 };
|
||||
})
|
||||
.filter((entry) => entry.lang.length === 2 && !Number.isNaN(entry.q))
|
||||
.sort((a, b) => b.q - a.q);
|
||||
|
||||
for (const entry of preferred) {
|
||||
if (isLocale(entry.lang)) {
|
||||
return entry.lang;
|
||||
}
|
||||
}
|
||||
|
||||
return undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolves the active locale for the current request from the
|
||||
* `nexumi_locale` cookie, falling back to the server's configured default.
|
||||
* `nexumi_locale` cookie, then Accept-Language, then the server default.
|
||||
*/
|
||||
export async function getLocale(): Promise<Locale> {
|
||||
const cookieStore = await cookies();
|
||||
const cookieLocale = cookieStore.get(LOCALE_COOKIE_NAME)?.value;
|
||||
return isLocale(cookieLocale) ? cookieLocale : env.DEFAULT_LOCALE;
|
||||
if (isLocale(cookieLocale)) {
|
||||
return cookieLocale;
|
||||
}
|
||||
|
||||
const headerList = await headers();
|
||||
const fromHeader = localeFromAcceptLanguage(headerList.get('accept-language'));
|
||||
if (fromHeader) {
|
||||
return fromHeader;
|
||||
}
|
||||
|
||||
return env.DEFAULT_LOCALE;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user