Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 13 additions & 1 deletion i18n/routing.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,21 @@
import { defineRouting } from 'next-intl/routing';

// Locale prefix mode can be configured via NEXT_PUBLIC_LOCALE_PREFIX.
// - "never" (default): /settings — locale from cookie/Accept-Language
// - "always": /en/settings — locale always in the URL
// - "as-needed": /settings for default locale, /fr/settings otherwise
// When proxying Bulwark under a sub-path (NEXT_PUBLIC_BASE_PATH), "always" is
// recommended to avoid next-intl rewrite loops caused by locale detection
// conflicting with the proxy's path rewriting.
const localePrefix = (process.env.NEXT_PUBLIC_LOCALE_PREFIX ?? 'never') as
| 'never'
| 'always'
| 'as-needed';

export const routing = defineRouting({
locales: ['en', 'fr', 'de', 'es', 'it', 'ja', 'ko', 'lv', 'nl', 'pl', 'pt', 'ru', 'zh'],
defaultLocale: 'en',
localePrefix: 'never'
localePrefix
});

export const locales = routing.locales;
Expand Down
10 changes: 9 additions & 1 deletion proxy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,16 @@ export function proxy(request: NextRequest) {
const pathname = request.nextUrl.pathname;
const isAdminRoute = pathname === '/admin' || pathname.startsWith('/admin/');

// When localePrefix is 'always', paths that already have a locale prefix
// (e.g. /en/settings) should not be re-processed by the intl middleware —
// doing so can trigger rewrite loops when combined with a proxy basePath.
const locales = routing.locales as readonly string[];
const hasLocalePrefix = locales.some(
(l) => pathname === `/${l}` || pathname.startsWith(`/${l}/`)
);

let intlResponse: ReturnType<typeof intlMiddleware> | null = null;
if (!isAdminRoute) {
if (!isAdminRoute && !hasLocalePrefix) {
try {
intlResponse = intlMiddleware(request);
} catch (error) {
Expand Down