next-intlayer
Version:
Simplify internationalization i18n in Next.js with context providers, hooks, locale detection, and multilingual content integration.
1 lines • 21.1 kB
Source Map (JSON)
{"version":3,"file":"intlayerProxy.mjs","names":["search","localeDetector","basePath","searchWithLocale"],"sources":["../../../src/proxy/intlayerProxy.ts"],"sourcesContent":["import configuration from '@intlayer/config/built';\nimport { DefaultValues } from '@intlayer/config/client';\nimport { getLocaleFromStorage, setLocaleInStorage } from '@intlayer/core';\nimport type { Locale } from '@intlayer/types';\nimport {\n type NextFetchEvent,\n type NextRequest,\n NextResponse,\n} from 'next/server';\nimport { localeDetector } from './localeDetector';\n\n/**\n * Controls whether locale detection occurs during Next.js prefetch requests\n * - true: Detect and apply locale during prefetch\n * - false: Use default locale during prefetch (recommended)\n *\n * This setting affects how Next.js handles locale prefetching:\n *\n * Example scenario:\n * - User's browser language is 'fr'\n * - Current page is /fr/about\n * - Link prefetches /about\n *\n * With `detectLocaleOnPrefetchNoPrefix:true`\n * - Prefetch detects 'fr' locale from browser\n * - Redirects prefetch to /fr/about\n *\n * With `detectLocaleOnPrefetchNoPrefix:false` (default)\n * - Prefetch uses default locale\n * - Redirects prefetch to /en/about (assuming 'en' is default)\n *\n * When to use true:\n * - Your app uses non-localized internal links (e.g. <a href=\"/about\">)\n * - You want consistent locale detection behavior between regular and prefetch requests\n *\n * When to use false (default):\n * - Your app uses locale-prefixed links (e.g. <a href=\"/fr/about\">)\n * - You want to optimize prefetching performance\n * - You want to avoid potential redirect loops\n */\nconst DEFAULT_DETECT_LOCALE_ON_PREFETCH_NO_PREFIX = false;\n\nconst { internationalization, routing } = configuration ?? {};\nconst { locales, defaultLocale } = internationalization ?? {};\nconst { basePath, mode } = routing ?? {};\n// Note: cookie names are resolved inside LocaleStorage based on configuration\n\n// Derived flags from routing.mode\nconst effectiveMode = mode ?? DefaultValues.Routing.ROUTING_MODE;\nconst noPrefix =\n effectiveMode === 'no-prefix' || effectiveMode === 'search-params';\nconst prefixDefault = effectiveMode === 'prefix-all';\n\n/**\n * Detects if the request is a prefetch request from Next.js.\n *\n * Next.js prefetch requests can be identified by several headers:\n * - purpose: 'prefetch' (standard prefetch header)\n * - next-router-prefetch: '1' (Next.js router prefetch)\n * - next-url: present (Next.js internal navigation)\n *\n * During prefetch, we should ignore cookie-based locale detection\n * to prevent unwanted redirects when users are switching locales.\n *\n * @param request - The incoming Next.js request object.\n * @returns - True if the request is a prefetch request, false otherwise.\n */\nconst isPrefetchRequest = (request: NextRequest): boolean => {\n const purpose = request.headers.get('purpose');\n const nextRouterPrefetch = request.headers.get('next-router-prefetch');\n const nextUrl = request.headers.get('next-url');\n const xNextjsData = request.headers.get('x-nextjs-data');\n\n return (\n purpose === 'prefetch' ||\n nextRouterPrefetch === '1' ||\n !!nextUrl ||\n !!xNextjsData\n );\n};\n\n// Ensure locale is reflected in search params when routing mode is 'search-params'\nconst appendLocaleSearchIfNeeded = (\n search: string | undefined,\n locale: Locale\n): string | undefined => {\n if (effectiveMode !== 'search-params') return search;\n\n const params = new URLSearchParams(search ?? '');\n\n params.set('locale', locale);\n\n return `?${params.toString()}`;\n};\n\n/**\n * Proxy that handles the internationalization layer\n *\n * Usage:\n *\n * ```ts\n * // ./src/proxy.ts\n *\n * export { intlayerProxy as proxy } from '@intlayer/next/proxy';\n *\n * // applies this proxy only to files in the app directory\n * export const config = {\n * matcher: '/((?!api|static|.*\\\\..*|_next).*)',\n * };\n * ```\n *\n * Main proxy function for handling internationalization.\n *\n * @param request - The incoming Next.js request object.\n * @param event - The Next.js fetch event (optional).\n * @param response - The Next.js response object (optional).\n * @returns - The response to be returned to the client.\n */\nexport const intlayerProxy = (\n request: NextRequest,\n _event?: NextFetchEvent,\n _response?: NextResponse\n): NextResponse => {\n const pathname = request.nextUrl.pathname;\n\n const localLocale = getLocalLocale(request);\n\n if (\n noPrefix // If the application is configured not to use locale prefixes in URLs\n ) {\n return handleNoPrefix(request, localLocale, pathname);\n }\n\n const pathLocale = getPathLocale(pathname);\n\n return handlePrefix(request, localLocale, pathLocale, pathname);\n};\n\n/**\n * Retrieves the locale from the request cookies if available and valid.\n *\n * @param request - The incoming Next.js request object.\n * @returns - The locale found in the cookies, or undefined if not found or invalid.\n */\nconst getLocalLocale = (request: NextRequest): Locale | undefined =>\n getLocaleFromStorage({\n getCookie: (name: string) => request.cookies.get(name)?.value ?? null,\n getHeader: (name: string) => request.headers.get(name) ?? null,\n });\n\n/**\n * Handles the case where URLs do not have locale prefixes.\n *\n * @param request - The incoming Next.js request object.\n * @param localLocale - The locale from the cookie.\n * @param pathname - The pathname from the request URL.\n * @returns - The rewritten response with the locale applied.\n */\nconst handleNoPrefix = (\n request: NextRequest,\n localLocale: Locale | undefined,\n pathname: string\n): NextResponse => {\n // Check if pathname has a locale prefix (even though we're in no-prefix mode)\n const pathLocale = getPathLocale(pathname);\n\n // If a locale prefix is detected in the URL, redirect to remove it\n if (pathLocale) {\n // Strip the locale prefix from the pathname\n const pathWithoutLocale = pathname.slice(`/${pathLocale}`.length) || '/';\n\n // Build redirect URL without locale prefix but with search params if needed\n const search = appendLocaleSearchIfNeeded(\n request.nextUrl.search,\n pathLocale\n );\n const redirectPath = search\n ? `${pathWithoutLocale}${search}`\n : `${pathWithoutLocale}${request.nextUrl.search ?? ''}`;\n\n // Redirect to the path without locale prefix (URL changes in browser)\n return redirectUrl(request, redirectPath);\n }\n\n // If no locale prefix in URL, determine locale and rewrite internally\n const locale = localLocale ?? defaultLocale;\n\n // In search-params mode, we need to redirect to add the locale search param\n if (effectiveMode === 'search-params') {\n // Check if locale search param already exists and matches the detected locale\n const existingSearchParams = new URLSearchParams(request.nextUrl.search);\n const existingLocale = existingSearchParams.get('locale');\n\n // If the existing locale matches the detected locale, no redirect needed\n if (existingLocale === locale) {\n // For internal routing, we need to add the locale prefix so Next.js can match [locale] param\n const internalPath = `/${locale}${pathname}`;\n const rewritePath = `${internalPath}${request.nextUrl.search ?? ''}`;\n\n // Rewrite internally (URL stays the same in browser, but Next.js routes to /[locale]/path)\n return rewriteUrl(request, rewritePath, locale);\n }\n\n const search = appendLocaleSearchIfNeeded(request.nextUrl.search, locale);\n const redirectPath = search\n ? `${pathname}${search}`\n : `${pathname}${request.nextUrl.search ?? ''}`;\n\n // Redirect to add/update the locale search param (URL changes in browser)\n return redirectUrl(request, redirectPath);\n }\n\n // For internal routing, we need to add the locale prefix so Next.js can match [locale] param\n const internalPath = `/${locale}${pathname}`;\n\n // Add search params if needed\n const search = appendLocaleSearchIfNeeded(request.nextUrl.search, locale);\n const rewritePath = search\n ? `${internalPath}${search}`\n : `${internalPath}${request.nextUrl.search ?? ''}`;\n\n // Rewrite internally (URL stays the same in browser, but Next.js routes to /[locale]/path)\n return rewriteUrl(request, rewritePath, locale);\n};\n\n/**\n * Extracts the locale from the URL pathname if present.\n *\n * @param pathname - The pathname from the request URL.\n * @returns - The locale found in the pathname, or undefined if not found.\n */\nconst getPathLocale = (pathname: string): Locale | undefined =>\n locales.find(\n (locale) => pathname.startsWith(`/${locale}/`) || pathname === `/${locale}`\n );\n\n/**\n * Handles the case where URLs have locale prefixes.\n *\n * @param request - The incoming Next.js request object.\n * @param localLocale - The locale from the cookie.\n * @param pathLocale - The locale extracted from the pathname.\n * @param pathname - The pathname from the request URL.\n * @param basePathTrailingSlash - Indicates if the basePath ends with a slash.\n * @returns - The response to be returned to the client.\n */\nconst handlePrefix = (\n request: NextRequest,\n localLocale: Locale | undefined,\n pathLocale: Locale | undefined,\n pathname: string\n): NextResponse => {\n if (\n !pathLocale // If the URL does not contain a locale prefix\n ) {\n const isPrefetch = isPrefetchRequest(request);\n\n if (isPrefetch && !DEFAULT_DETECT_LOCALE_ON_PREFETCH_NO_PREFIX) {\n return handleMissingPathLocale(request, defaultLocale, pathname);\n }\n\n return handleMissingPathLocale(request, localLocale, pathname);\n }\n\n // If the URL contains a locale prefix\n return handleExistingPathLocale(request, localLocale, pathLocale, pathname);\n};\n\n/**\n * Handles requests where the locale is missing from the URL pathname.\n *\n * @param request - The incoming Next.js request object.\n * @param localLocale - The locale from the cookie.\n * @param pathname - The pathname from the request URL.\n * @param basePathTrailingSlash - Indicates if the basePath ends with a slash.\n * @returns - The response to be returned to the client.\n */\nconst handleMissingPathLocale = (\n request: NextRequest,\n localLocale: Locale | undefined,\n pathname: string\n): NextResponse => {\n let locale = (localLocale ??\n localeDetector?.(request) ??\n defaultLocale) as Locale;\n if (!locales.includes(locale)) {\n locale = defaultLocale;\n }\n\n const newPath = constructPath(\n locale,\n pathname,\n basePath,\n appendLocaleSearchIfNeeded(request.nextUrl.search, locale)\n );\n\n return prefixDefault || locale !== defaultLocale\n ? redirectUrl(request, newPath)\n : rewriteUrl(request, newPath, locale);\n};\n\n/**\n * Handles requests where the locale exists in the URL pathname.\n *\n * @param request - The incoming Next.js request object.\n * @param localLocale - The locale from the cookie.\n * @param pathLocale - The locale extracted from the pathname.\n * @param pathname - The pathname from the request URL.\n * @returns - The response to be returned to the client.\n */\nconst handleExistingPathLocale = (\n request: NextRequest,\n localLocale: Locale | undefined,\n pathLocale: Locale,\n pathname: string\n): NextResponse => {\n if (\n // If the cookie locale is set and differs from the locale in the URL\n localLocale &&\n localLocale !== pathLocale\n ) {\n const newPath = handleCookieLocaleMismatch(\n request,\n pathname,\n pathLocale,\n localLocale,\n basePath\n );\n return redirectUrl(request, newPath);\n }\n\n // If the cookie locale matches the path locale, or cookie locale is not set, or serverSetCookie is 'always'\n return handleDefaultLocaleRedirect(request, pathLocale, pathname);\n};\n\n/**\n * Handles the scenario where the locale in the cookie does not match the locale in the URL pathname.\n *\n * @param request - The incoming Next.js request object.\n * @param pathname - The pathname from the request URL.\n * @param pathLocale - The locale extracted from the pathname.\n * @param localLocale - The locale from the cookie.\n * @param basePath - The base path of the application.\n * @returns - The new URL path with the correct locale.\n */\nconst handleCookieLocaleMismatch = (\n request: NextRequest,\n pathname: string,\n pathLocale: Locale,\n localLocale: Locale,\n basePath: string\n): string => {\n // Replace the pathLocale in the pathname with the localLocale\n const newPath = pathname.replace(`/${pathLocale}`, `/${localLocale}`);\n\n return constructPath(\n localLocale,\n newPath,\n basePath,\n appendLocaleSearchIfNeeded(request.nextUrl.search, localLocale)\n );\n};\n\n/**\n * Handles redirection when the default locale is used and prefixing is not required.\n *\n * @param request - The incoming Next.js request object.\n * @param pathLocale - The locale extracted from the pathname.\n * @param pathname - The pathname from the request URL.\n * @returns - The rewritten response without the locale prefix.\n */\nconst handleDefaultLocaleRedirect = (\n request: NextRequest,\n pathLocale: Locale,\n pathname: string\n): NextResponse => {\n if (\n // If default locale should not be prefixed and the pathLocale is the defaultLocale\n !prefixDefault &&\n pathLocale === defaultLocale\n ) {\n let pathWithoutLocale = pathname.slice(`/${pathLocale}`.length) || '/';\n\n const basePathTrailingSlash = basePath.endsWith('/');\n\n if (basePathTrailingSlash) {\n pathWithoutLocale = pathWithoutLocale.slice(1);\n }\n\n const searchWithLocale = appendLocaleSearchIfNeeded(\n request.nextUrl.search,\n pathLocale\n );\n if (searchWithLocale) {\n pathWithoutLocale += searchWithLocale;\n } else if (request.nextUrl.search) {\n pathWithoutLocale += request.nextUrl.search;\n }\n\n return redirectUrl(request, `${basePath}${pathWithoutLocale}`);\n }\n\n // If prefixing default locale is required or pathLocale is not the defaultLocale\n\n const searchWithLocale = appendLocaleSearchIfNeeded(\n request.nextUrl.search,\n pathLocale\n );\n const newPath = searchWithLocale\n ? `${pathname}${searchWithLocale}`\n : pathname;\n return rewriteUrl(request, newPath, pathLocale);\n};\n\n/**\n * Constructs a new path by combining the locale, path, basePath, and search parameters.\n *\n * @param locale - The locale to include in the path.\n * @param path - The original path from the request.\n * @param basePath - The base path of the application.\n * @param [search] - The query string from the request URL (optional).\n * @returns - The constructed new path.\n */\nconst constructPath = (\n locale: Locale,\n path: string,\n basePath: string,\n search?: string\n): string => {\n // In 'search-params' and 'no-prefix' modes, do not prefix the path with the locale\n // Also, strip any incoming locale prefix if present\n const pathWithoutPrefix = path.startsWith(`/${locale}`)\n ? path.slice(`/${locale}`.length) || '/'\n : path;\n\n if (effectiveMode === 'no-prefix') {\n if (search) {\n return `${pathWithoutPrefix}?${search}`;\n }\n\n return pathWithoutPrefix;\n }\n\n if (effectiveMode === 'search-params') {\n if (search) {\n return `${pathWithoutPrefix}?${search}`;\n }\n\n return pathWithoutPrefix;\n }\n\n const pathWithLocalePrefix = path.startsWith(`/${locale}`)\n ? path\n : `${locale}${path}`;\n\n const basePathTrailingSlash = basePath.endsWith('/');\n\n const newPath = `${basePath}${basePathTrailingSlash ? '' : '/'}${pathWithLocalePrefix}`;\n\n return newPath;\n};\n\n/**\n * Rewrites the URL to the new path and sets the locale header.\n *\n * @param request - The incoming Next.js request object.\n * @param newPath - The new path to rewrite to.\n * @param locale - The locale to set in the response header.\n * @returns - The rewritten response.\n */\nconst rewriteUrl = (\n request: NextRequest,\n newPath: string,\n locale: Locale\n): NextResponse => {\n // Ensure we preserve the original search params if they were present and not explicitly included in newPath\n const search = request.nextUrl.search;\n const pathWithSearch =\n search && !newPath.includes('?') ? `${newPath}${search}` : newPath;\n\n const response = NextResponse.rewrite(new URL(pathWithSearch, request.url));\n\n setLocaleInStorage(locale, {\n setHeader: (name: string, value: string) =>\n response.headers.set(name, value),\n });\n\n return response;\n};\n\n/**\n * Redirects the request to the new path.\n *\n * @param request - The incoming Next.js request object.\n * @param newPath - The new path to redirect to.\n * @returns - The redirect response.\n */\nconst redirectUrl = (request: NextRequest, newPath: string): NextResponse => {\n // Ensure we preserve the original search params if they were present and not explicitly included in newPath\n const search = request.nextUrl.search;\n const pathWithSearch =\n search && !newPath.includes('?') ? `${newPath}${search}` : newPath;\n\n return NextResponse.redirect(new URL(pathWithSearch, request.url));\n};\n"],"mappings":"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"}