From 956acb69cee39f3a5885d6dd1ba2b7ea242e1ec6 Mon Sep 17 00:00:00 2001 From: Linus Rath <139418639+rathlinus@users.noreply.github.com> Date: Mon, 25 May 2026 17:01:52 +0200 Subject: [PATCH] feat: add NEXT_PUBLIC_DEFAULT_LOCALE for fallback UI locale #243 --- .env.example | 16 ++++++++++++++++ Dockerfile | 5 +++++ i18n/routing.ts | 16 ++++++++++++++-- 3 files changed, 35 insertions(+), 2 deletions(-) diff --git a/.env.example b/.env.example index 99da0cb0..5f21140e 100644 --- a/.env.example +++ b/.env.example @@ -234,6 +234,22 @@ LOGIN_WEBSITE_URL=https://bulwarkmail.org # your own directory (e.g. http://localhost:3001 for local development). # EXTENSION_DIRECTORY_URL=https://extensions.bulwarkmail.org +# ============================================================================= +# Internationalization +# ============================================================================= +# These are build-time variables - to change them with the published Docker +# image, rebuild it with --build-arg (see README "Default UI locale"). +# +# Fallback UI locale used when the visitor's Accept-Language header does not +# match any supported locale. Defaults to "en". +# Supported: cs, da, de, en, es, fr, it, ja, ko, lv, nl, pl, pt, ru, tr, uk, zh +# NEXT_PUBLIC_DEFAULT_LOCALE=tr + +# Locale prefix mode for URLs. Recommended "always" when proxying under a +# subpath (NEXT_PUBLIC_BASE_PATH) to avoid next-intl rewrite loops. +# Values: never (default) | always | as-needed +# NEXT_PUBLIC_LOCALE_PREFIX=always + # ============================================================================= # Legacy Build-time Variables (still supported as fallback) # ============================================================================= diff --git a/Dockerfile b/Dockerfile index 8e3a3e68..2b7c21ae 100644 --- a/Dockerfile +++ b/Dockerfile @@ -8,6 +8,11 @@ ENV NEXT_TELEMETRY_DISABLED=1 # at build time, so it cannot be changed without rebuilding. ARG NEXT_PUBLIC_BASE_PATH= ENV NEXT_PUBLIC_BASE_PATH=$NEXT_PUBLIC_BASE_PATH +# Optional: fallback UI locale (e.g. tr, de, fr) used when the visitor's +# Accept-Language header does not match any supported locale. Baked in at +# build time because next-intl wires it into client-side routing too. +ARG NEXT_PUBLIC_DEFAULT_LOCALE= +ENV NEXT_PUBLIC_DEFAULT_LOCALE=$NEXT_PUBLIC_DEFAULT_LOCALE # Commit SHA shown in the About screen. .dockerignore excludes .git, so # `git rev-parse` inside the build can't find it - CI must pass it in. ARG GIT_COMMIT=unknown diff --git a/i18n/routing.ts b/i18n/routing.ts index 8bea497e..ad420514 100644 --- a/i18n/routing.ts +++ b/i18n/routing.ts @@ -12,9 +12,21 @@ const localePrefix = (process.env.NEXT_PUBLIC_LOCALE_PREFIX ?? 'never') as | 'always' | 'as-needed'; +const SUPPORTED_LOCALES = ['cs', 'da', 'de', 'en', 'es', 'fr', 'it', 'ja', 'ko', 'lv', 'nl', 'pl', 'pt', 'ru', 'tr', 'uk', 'zh'] as const; + +// Fallback locale used when the visitor's Accept-Language header does not +// match any supported locale (and no NEXT_LOCALE cookie is set yet). Admins +// set this via NEXT_PUBLIC_DEFAULT_LOCALE at build time to localise greenfield +// deployments without having every user change their preference manually. +const envDefaultLocale = process.env.NEXT_PUBLIC_DEFAULT_LOCALE?.trim(); +const resolvedDefaultLocale = + envDefaultLocale && (SUPPORTED_LOCALES as readonly string[]).includes(envDefaultLocale) + ? (envDefaultLocale as (typeof SUPPORTED_LOCALES)[number]) + : 'en'; + export const routing = defineRouting({ - locales: ['cs', 'da', 'de', 'en', 'es', 'fr', 'it', 'ja', 'ko', 'lv', 'nl', 'pl', 'pt', 'ru', 'tr', 'uk', 'zh'], - defaultLocale: 'en', + locales: SUPPORTED_LOCALES, + defaultLocale: resolvedDefaultLocale, localePrefix });