diff --git a/src/app/globals.css b/src/app/globals.css
index f89f3acd..fd630c57 100644
--- a/src/app/globals.css
+++ b/src/app/globals.css
@@ -1011,6 +1011,21 @@ tbody tr:hover {
.content-card-body {
padding: 0.85rem;
}
+ .nav-item {
+ white-space: normal;
+ text-wrap: balance;
+ font-size: 12px;
+ padding: 0.5rem 0.75rem;
+ height: auto;
+ min-height: 44px;
+ }
+ .nav-item::after {
+ display: none;
+ }
+ .dropdown-item {
+ font-size: 13px;
+ padding: 0.6rem 0.85rem;
+ }
}
/* make tables scroll on small screens */
diff --git a/src/components/navigation.tsx b/src/components/navigation.tsx
index 2d22ddae..bca1be86 100644
--- a/src/components/navigation.tsx
+++ b/src/components/navigation.tsx
@@ -34,7 +34,8 @@ export async function Navigation() {
-
+
+
+
diff --git a/src/i18n/request.ts b/src/i18n/request.ts
index eefe19ee..c82e31fb 100644
--- a/src/i18n/request.ts
+++ b/src/i18n/request.ts
@@ -1,9 +1,8 @@
-import { cookies } from "next/headers";
+import { cookies, headers } from "next/headers";
import { getRequestConfig } from "next-intl/server";
-// i18n WITHOUT routing: the locale is chosen by a `NEXT_LOCALE` cookie (set by
-// the language switcher) rather than a URL segment, so every existing route and
-// the access-guard middleware keep working unchanged. English is the fallback.
+// i18n WITHOUT routing: the locale is chosen by a `NEXT_LOCALE` cookie, then
+// the Accept-Language header, and finally English as fallback.
export const SUPPORTED_LOCALES = ["en", "it", "nl", "de", "fr", "es", "pt", "pl", "sv", "tr", "ro", "hu", "cs", "sk", "da", "no", "el", "bg", "hr", "sr", "uk", "ru"] as const;
export type AppLocale = (typeof SUPPORTED_LOCALES)[number];
export const DEFAULT_LOCALE: AppLocale = "en";
@@ -12,10 +11,37 @@ export function isSupportedLocale(value: string | undefined): value is AppLocale
return !!value && (SUPPORTED_LOCALES as readonly string[]).includes(value);
}
+function detectLocaleFromAcceptLanguage(acceptLanguage: string | null): AppLocale | null {
+ if (!acceptLanguage) return null;
+ const locales = acceptLanguage
+ .split(",")
+ .map((entry) => {
+ const [tag, qPart] = entry.split(";");
+ const quality = qPart ? parseFloat(qPart.replace("q=", "")) : 1;
+ const lang = tag?.trim().split("-")[0] ?? "";
+ return { lang, quality };
+ })
+ .filter((l) => l.lang)
+ .sort((a, b) => b.quality - a.quality);
+
+ for (const { lang } of locales) {
+ if (isSupportedLocale(lang)) return lang;
+ }
+ return null;
+}
+
export default getRequestConfig(async () => {
const store = await cookies();
const cookieLocale = store.get("NEXT_LOCALE")?.value;
- const locale: AppLocale = isSupportedLocale(cookieLocale) ? cookieLocale : DEFAULT_LOCALE;
+
+ let locale: AppLocale;
+ if (isSupportedLocale(cookieLocale)) {
+ locale = cookieLocale;
+ } else {
+ const headersList = await headers();
+ const detected = detectLocaleFromAcceptLanguage(headersList.get("Accept-Language"));
+ locale = detected ?? DEFAULT_LOCALE;
+ }
// Safe: `locale` is validated against SUPPORTED_LOCALES above (only en/it/nl/de/fr/es).
const messages = (await import(`../messages/${locale}.json`)).default;