gt-next 11.0.2 → 11.0.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +26 -0
- package/dist/condition-store/AsyncConditionStore.d.ts.map +1 -1
- package/dist/condition-store/AsyncConditionStore.js +1 -4
- package/dist/condition-store/AsyncConditionStore.js.map +1 -1
- package/dist/condition-store/AsyncConditionStore.mjs +2 -5
- package/dist/condition-store/AsyncConditionStore.mjs.map +1 -1
- package/dist/config-dir/props/withGTConfigProps.d.ts +2 -0
- package/dist/config-dir/props/withGTConfigProps.d.ts.map +1 -1
- package/dist/config-dir/props/withGTConfigProps.js.map +1 -1
- package/dist/config-dir/props/withGTConfigProps.mjs.map +1 -1
- package/dist/config.d.ts +1 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +5 -1
- package/dist/config.js.map +1 -1
- package/dist/config.mjs +5 -1
- package/dist/config.mjs.map +1 -1
- package/dist/errors/createErrors.d.ts +3 -1
- package/dist/errors/createErrors.d.ts.map +1 -1
- package/dist/errors/createErrors.js +23 -5
- package/dist/errors/createErrors.js.map +1 -1
- package/dist/errors/createErrors.mjs +21 -5
- package/dist/errors/createErrors.mjs.map +1 -1
- package/dist/errors/ssg.d.ts +1 -0
- package/dist/errors/ssg.d.ts.map +1 -1
- package/dist/errors/ssg.js +9 -1
- package/dist/errors/ssg.js.map +1 -1
- package/dist/errors/ssg.mjs +7 -1
- package/dist/errors/ssg.mjs.map +1 -1
- package/dist/index.client.d.ts +3 -1
- package/dist/index.client.d.ts.map +1 -1
- package/dist/index.client.js +5 -0
- package/dist/index.client.js.map +1 -1
- package/dist/index.client.mjs +5 -1
- package/dist/index.client.mjs.map +1 -1
- package/dist/index.rsc.d.ts +7 -1
- package/dist/index.rsc.d.ts.map +1 -1
- package/dist/index.rsc.js +8 -0
- package/dist/index.rsc.js.map +1 -1
- package/dist/index.rsc.mjs +9 -2
- package/dist/index.rsc.mjs.map +1 -1
- package/dist/index.server.d.ts +2 -0
- package/dist/index.server.d.ts.map +1 -1
- package/dist/index.server.js +2 -0
- package/dist/index.server.js.map +1 -1
- package/dist/index.server.mjs +2 -1
- package/dist/index.server.mjs.map +1 -1
- package/dist/index.types.d.ts +7 -1
- package/dist/index.types.d.ts.map +1 -1
- package/dist/index.types.js +8 -0
- package/dist/index.types.js.map +1 -1
- package/dist/index.types.mjs +8 -1
- package/dist/index.types.mjs.map +1 -1
- package/dist/middleware-dir/createNextMiddleware.d.ts +1 -3
- package/dist/middleware-dir/createNextMiddleware.d.ts.map +1 -1
- package/dist/middleware-dir/createNextMiddleware.js +4 -9
- package/dist/middleware-dir/createNextMiddleware.js.map +1 -1
- package/dist/middleware-dir/createNextMiddleware.mjs +5 -10
- package/dist/middleware-dir/createNextMiddleware.mjs.map +1 -1
- package/dist/middleware-dir/utils.d.ts.map +1 -1
- package/dist/middleware-dir/utils.js +2 -4
- package/dist/middleware-dir/utils.js.map +1 -1
- package/dist/middleware-dir/utils.mjs +2 -4
- package/dist/middleware-dir/utils.mjs.map +1 -1
- package/dist/pages-dir/parseLocale.d.ts.map +1 -1
- package/dist/pages-dir/parseLocale.js +2 -4
- package/dist/pages-dir/parseLocale.js.map +1 -1
- package/dist/pages-dir/parseLocale.mjs +2 -4
- package/dist/pages-dir/parseLocale.mjs.map +1 -1
- package/dist/pages-dir/withGTStaticProps.d.ts +18 -0
- package/dist/pages-dir/withGTStaticProps.d.ts.map +1 -0
- package/dist/pages-dir/withGTStaticProps.js +34 -0
- package/dist/pages-dir/withGTStaticProps.js.map +1 -0
- package/dist/pages-dir/withGTStaticProps.mjs +32 -0
- package/dist/pages-dir/withGTStaticProps.mjs.map +1 -0
- package/dist/utils/client-boundary.d.ts.map +1 -1
- package/dist/utils/client-boundary.js +3 -1
- package/dist/utils/client-boundary.js.map +1 -1
- package/dist/utils/client-boundary.mjs +4 -2
- package/dist/utils/client-boundary.mjs.map +1 -1
- package/dist/utils/pathRegex.d.ts +3 -0
- package/dist/utils/pathRegex.d.ts.map +1 -0
- package/dist/utils/pathRegex.js +19 -0
- package/dist/utils/pathRegex.js.map +1 -0
- package/dist/utils/pathRegex.mjs +17 -0
- package/dist/utils/pathRegex.mjs.map +1 -0
- package/package.json +11 -7
|
@@ -11,15 +11,13 @@ import { PathConfig } from './utils';
|
|
|
11
11
|
* @param {boolean} [config.localeRouting=true] - Flag to enable or disable automatic locale-based routing.
|
|
12
12
|
* @param {boolean} [config.prefixDefaultLocale=false] - Flag to enable or disable prefixing the default locale to the pathname, i.e., /en/about -> /about
|
|
13
13
|
* @param {boolean} [config.ignoreSourceMaps=true] - Flag to enable or disable ignoring source maps
|
|
14
|
-
* @param {string} [config.regexFilter] - Regular expression that request pathnames must match for i18n middleware to be applied
|
|
15
14
|
* @param {PathConfig} [config.pathConfig] - Path configuration for locale routing
|
|
16
15
|
* @returns {function} - A middleware function that processes the request and response.
|
|
17
16
|
*/
|
|
18
|
-
export declare function createNextMiddleware({ localeRouting, prefixDefaultLocale, ignoreSourceMaps,
|
|
17
|
+
export declare function createNextMiddleware({ localeRouting, prefixDefaultLocale, ignoreSourceMaps, pathConfig, }?: {
|
|
19
18
|
localeRouting?: boolean;
|
|
20
19
|
prefixDefaultLocale?: boolean;
|
|
21
20
|
ignoreSourceMaps?: boolean;
|
|
22
|
-
regexFilter?: string;
|
|
23
21
|
pathConfig?: PathConfig;
|
|
24
22
|
}): (req: NextRequest) => NextResponse<unknown>;
|
|
25
23
|
//# sourceMappingURL=createNextMiddleware.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"createNextMiddleware.d.ts","sourceRoot":"","sources":["../../src/middleware-dir/createNextMiddleware.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"createNextMiddleware.d.ts","sourceRoot":"","sources":["../../src/middleware-dir/createNextMiddleware.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AASxD,OAAO,EACL,UAAU,EAQX,MAAM,SAAS,CAAC;AAejB;;;;;;;;;;;;;GAaG;AACH,wBAAgB,oBAAoB,CAAC,EACnC,aAAoB,EACpB,mBAA2B,EAC3B,gBAAuB,EACvB,UAAe,GAChB,GAAE;IACD,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAC9B,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,UAAU,CAAC,EAAE,UAAU,CAAC;CACpB,SA6GqB,WAAW,2BA6MrC"}
|
|
@@ -3,6 +3,7 @@ require("../_virtual/_rolldown/runtime.js");
|
|
|
3
3
|
require("../utils/headers.js");
|
|
4
4
|
require("../utils/cookies.js");
|
|
5
5
|
const require_errors_createErrors = require("../errors/createErrors.js");
|
|
6
|
+
const require_utils_pathRegex = require("../utils/pathRegex.js");
|
|
6
7
|
const require_middleware_dir_utils = require("./utils.js");
|
|
7
8
|
let generaltranslation_internal = require("generaltranslation/internal");
|
|
8
9
|
let _generaltranslation_react_core_pure = require("@generaltranslation/react-core/pure");
|
|
@@ -22,17 +23,11 @@ const NEXT_JS_SOURCE_MAP_PATH = "/__nextjs_source-map";
|
|
|
22
23
|
* @param {boolean} [config.localeRouting=true] - Flag to enable or disable automatic locale-based routing.
|
|
23
24
|
* @param {boolean} [config.prefixDefaultLocale=false] - Flag to enable or disable prefixing the default locale to the pathname, i.e., /en/about -> /about
|
|
24
25
|
* @param {boolean} [config.ignoreSourceMaps=true] - Flag to enable or disable ignoring source maps
|
|
25
|
-
* @param {string} [config.regexFilter] - Regular expression that request pathnames must match for i18n middleware to be applied
|
|
26
26
|
* @param {PathConfig} [config.pathConfig] - Path configuration for locale routing
|
|
27
27
|
* @returns {function} - A middleware function that processes the request and response.
|
|
28
28
|
*/
|
|
29
|
-
function createNextMiddleware({ localeRouting = true, prefixDefaultLocale = false, ignoreSourceMaps = true,
|
|
30
|
-
|
|
31
|
-
if (regexFilter !== void 0) try {
|
|
32
|
-
pathFilter = new RegExp(regexFilter);
|
|
33
|
-
} catch (error) {
|
|
34
|
-
throw new Error(require_errors_createErrors.createInvalidMiddlewareRegexError(regexFilter, error));
|
|
35
|
-
}
|
|
29
|
+
function createNextMiddleware({ localeRouting = true, prefixDefaultLocale = false, ignoreSourceMaps = true, pathConfig = {} } = {}) {
|
|
30
|
+
const pathRegex = require_utils_pathRegex.compilePathRegex(process.env._GENERALTRANSLATION_PATH_REGEX);
|
|
36
31
|
let envParams;
|
|
37
32
|
if (process.env._GENERALTRANSLATION_I18N_CONFIG_PARAMS) try {
|
|
38
33
|
envParams = JSON.parse(process.env._GENERALTRANSLATION_I18N_CONFIG_PARAMS);
|
|
@@ -77,7 +72,7 @@ function createNextMiddleware({ localeRouting = true, prefixDefaultLocale = fals
|
|
|
77
72
|
* @returns {NextResponse} - The Next.js response, either continuing the request or redirecting to the localized URL.
|
|
78
73
|
*/
|
|
79
74
|
function middleware(req) {
|
|
80
|
-
if (
|
|
75
|
+
if (!require_utils_pathRegex.pathnameMatchesRegex(req.nextUrl.pathname, pathRegex)) return next_server_js.NextResponse.next();
|
|
81
76
|
if (ignoreSourceMaps && req.nextUrl.pathname.startsWith(NEXT_JS_SOURCE_MAP_PATH)) return next_server_js.NextResponse.next();
|
|
82
77
|
const { userLocale, pathnameLocale, unstandardizedPathnameLocale, clearResetCookie } = require_middleware_dir_utils.getLocaleFromRequest(req, defaultLocale, locales, localeRouting, gtServicesEnabled, prefixDefaultLocale, defaultLocalePaths, referrerLocaleCookieName, localeCookieName, resetLocaleCookieName, gt);
|
|
83
78
|
const headerList = new Headers(req.headers);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"createNextMiddleware.js","names":["createInvalidMiddlewareRegexError","GTRuntime","libraryDefaultLocale","defaultLocaleCookieName","defaultResetLocaleCookieName","createUnsupportedLocalesWarning","createPathToSharedPathMap","NextResponse","getLocaleFromRequest","getResponse","getSharedPath","replaceDynamicSegments","getLocalizedPath"],"sources":["../../src/middleware-dir/createNextMiddleware.ts"],"sourcesContent":["import { isSameDialect, standardizeLocale } from '@generaltranslation/format';\nimport { GTRuntime } from 'generaltranslation/runtime';\nimport { libraryDefaultLocale } from 'generaltranslation/internal';\nimport {\n createInvalidMiddlewareRegexError,\n createUnsupportedLocalesWarning,\n} from '../errors/createErrors';\nimport { NextRequest, NextResponse } from 'next/server';\nimport {\n defaultLocaleRoutingEnabledCookieName,\n defaultReferrerLocaleCookieName,\n} from '../utils/cookies';\nimport {\n defaultLocaleCookieName,\n defaultResetLocaleCookieName,\n} from '@generaltranslation/react-core/pure';\nimport {\n PathConfig,\n getSharedPath,\n replaceDynamicSegments,\n getLocalizedPath,\n createPathToSharedPathMap,\n getLocaleFromRequest,\n getResponse,\n ResponseConfig,\n} from './utils';\nimport { defaultLocaleHeaderName } from '../utils/headers';\nimport type { CustomMapping } from '@generaltranslation/format/types';\nimport type { HeadersAndCookies } from '../config-dir/props/withGTConfigProps';\n\nconst NEXT_JS_SOURCE_MAP_PATH = '/__nextjs_source-map';\n\ntype MiddlewareEnvConfig = {\n customMapping?: CustomMapping;\n defaultLocale?: string;\n locales?: string[];\n headersAndCookies?: HeadersAndCookies;\n};\n\n/**\n * Middleware factory to create a Next.js middleware for i18n routing and locale detection.\n *\n * This middleware sets a cookie based on the locale derived from several sources\n * such as the request pathname, referer, or 'Accept-Language' header.\n * If locale routing is enabled, it redirects to the localized pathname and\n * updates the locale cookie.\n *\n * @param {boolean} [config.localeRouting=true] - Flag to enable or disable automatic locale-based routing.\n * @param {boolean} [config.prefixDefaultLocale=false] - Flag to enable or disable prefixing the default locale to the pathname, i.e., /en/about -> /about\n * @param {boolean} [config.ignoreSourceMaps=true] - Flag to enable or disable ignoring source maps\n * @param {string} [config.regexFilter] - Regular expression that request pathnames must match for i18n middleware to be applied\n * @param {PathConfig} [config.pathConfig] - Path configuration for locale routing\n * @returns {function} - A middleware function that processes the request and response.\n */\nexport function createNextMiddleware({\n localeRouting = true,\n prefixDefaultLocale = false,\n ignoreSourceMaps = true,\n regexFilter,\n pathConfig = {},\n}: {\n localeRouting?: boolean;\n prefixDefaultLocale?: boolean;\n ignoreSourceMaps?: boolean;\n regexFilter?: string;\n pathConfig?: PathConfig;\n} = {}) {\n let pathFilter: RegExp | undefined;\n if (regexFilter !== undefined) {\n try {\n pathFilter = new RegExp(regexFilter);\n } catch (error) {\n throw new Error(createInvalidMiddlewareRegexError(regexFilter, error));\n }\n }\n\n // i18n config\n let envParams: MiddlewareEnvConfig | undefined;\n if (process.env._GENERALTRANSLATION_I18N_CONFIG_PARAMS) {\n try {\n envParams = JSON.parse(\n process.env._GENERALTRANSLATION_I18N_CONFIG_PARAMS\n );\n } catch (error) {\n console.error(`gt-next middleware:`, error);\n }\n }\n\n // gt instance\n const gt = new GTRuntime({\n customMapping: envParams?.customMapping,\n });\n\n // using gt services\n const gtServicesEnabled =\n process.env._GENERALTRANSLATION_GT_SERVICES_ENABLED === 'true';\n\n // i18n config\n const defaultLocale: string =\n envParams?.defaultLocale || libraryDefaultLocale;\n const locales: string[] = envParams?.locales || [defaultLocale];\n\n // add canonical locales\n const canonicalLocales = Object.values(envParams?.customMapping || {})\n .filter(\n (locale): locale is { code: string } =>\n typeof locale === 'object' &&\n locale !== null &&\n 'code' in locale &&\n typeof locale.code === 'string' &&\n locale.code.length > 0\n )\n .map((locale) => locale.code);\n locales.push(...canonicalLocales);\n\n // cookies and header names\n const headersAndCookies = envParams?.headersAndCookies || {};\n const localeRoutingEnabledCookieName =\n headersAndCookies?.localeRoutingEnabledCookieName ||\n defaultLocaleRoutingEnabledCookieName;\n const referrerLocaleCookieName =\n headersAndCookies?.referrerLocaleCookieName ||\n defaultReferrerLocaleCookieName;\n const localeCookieName =\n headersAndCookies?.localeCookieName || defaultLocaleCookieName;\n const resetLocaleCookieName =\n headersAndCookies?.resetLocaleCookieName || defaultResetLocaleCookieName;\n const localeHeaderName =\n headersAndCookies?.localeHeaderName || defaultLocaleHeaderName;\n\n if (!gt.isValidLocale(defaultLocale))\n throw new Error(\n `gt-next middleware: defaultLocale \"${defaultLocale}\" is not a valid locale.`\n );\n\n const warningLocales = locales.filter((locale) => !gt.isValidLocale(locale));\n if (warningLocales.length)\n console.warn(createUnsupportedLocalesWarning(warningLocales));\n\n // ---------- PRE-PROCESSING PATHS ---------- //\n\n // Standardize pathConfig paths\n pathConfig = Object.entries(pathConfig).reduce<PathConfig>(\n (acc, [sharedPath, localizedPath]) => {\n if (typeof localizedPath === 'string') {\n acc[sharedPath] = localizedPath;\n } else {\n acc[sharedPath] = Object.entries(localizedPath).reduce<{\n [key: string]: string;\n }>((acc, [locale, localizedPath]) => {\n acc[gtServicesEnabled ? standardizeLocale(locale) : locale] =\n localizedPath;\n return acc;\n }, {});\n }\n return acc;\n },\n {}\n );\n\n // Create the path mapping\n const { pathToSharedPath, defaultLocalePaths } = createPathToSharedPathMap(\n pathConfig,\n prefixDefaultLocale,\n defaultLocale\n );\n\n /**\n * Processes the incoming request to determine the user's locale and sets a locale cookie.\n * Optionally redirects the user based on the locale if locale-based routing is enabled.\n *\n * - Checks if the request URL contains a locale.\n * - Falls back to the referer URL for locale if needed.\n * - If no locale is found in the URL or referer, it checks the 'Accept-Language' header.\n * - Sets a cookie with the detected or default locale.\n * - Redirects to the correct locale route if locale routing is enabled.\n *\n * @param {NextRequest} req - The incoming request object, containing URL and headers.\n * @returns {NextResponse} - The Next.js response, either continuing the request or redirecting to the localized URL.\n */\n function middleware(req: NextRequest) {\n if (pathFilter && !pathFilter.test(req.nextUrl.pathname)) {\n return NextResponse.next();\n }\n\n // Ignore source maps\n if (\n ignoreSourceMaps &&\n req.nextUrl.pathname.startsWith(NEXT_JS_SOURCE_MAP_PATH)\n ) {\n return NextResponse.next();\n }\n\n // ---------- LOCALE DETECTION ---------- //\n\n const {\n userLocale,\n pathnameLocale,\n unstandardizedPathnameLocale,\n clearResetCookie,\n } = getLocaleFromRequest(\n req,\n defaultLocale,\n locales,\n localeRouting,\n gtServicesEnabled,\n prefixDefaultLocale,\n defaultLocalePaths,\n referrerLocaleCookieName,\n localeCookieName,\n resetLocaleCookieName,\n gt\n );\n\n const headerList = new Headers(req.headers);\n\n const responseConfig: Omit<ResponseConfig, 'type'> = {\n originalUrl: req.nextUrl,\n headerList,\n userLocale,\n clearResetCookie,\n localeRouting,\n localeRoutingEnabledCookieName,\n resetLocaleCookieName,\n localeHeaderName,\n };\n\n const getRewriteResponse = (responsePath: string) =>\n getResponse({ responsePath, type: 'rewrite', ...responseConfig });\n\n const getRedirectResponse = (responsePath: string) =>\n getResponse({ responsePath, type: 'redirect', ...responseConfig });\n\n const getNextResponse = () =>\n getResponse({ type: 'next', ...responseConfig });\n\n if (localeRouting) {\n // ---------- GET PATHS ---------- //\n\n // get pathname\n const { pathname } = req.nextUrl;\n\n // standardize pathname (ie, /tg/welcome -> /fil/welcome), (/blog -> /blog)\n const standardizedPathname =\n pathnameLocale && pathnameLocale !== unstandardizedPathnameLocale\n ? pathname.replace(\n new RegExp(`^/${unstandardizedPathnameLocale}`),\n `/${userLocale}`\n )\n : pathname;\n\n // Get the shared path for the unprefixed pathname\n const sharedPath = getSharedPath(\n standardizedPathname,\n pathToSharedPath,\n pathnameLocale\n );\n\n // Get shared path with parameters (/en/dashboard/1/custom), for rewriting localized paths\n const sharedPathWithParameters =\n sharedPath !== undefined\n ? replaceDynamicSegments(\n pathnameLocale\n ? standardizedPathname\n : `/${userLocale}${standardizedPathname}`,\n `/${userLocale}${sharedPath}`\n )\n : undefined;\n\n // Localized path (/en/blog, /fr/fr-about, /fr/dashboard/[id]/custom)\n const localizedPath =\n sharedPath !== undefined\n ? getLocalizedPath(sharedPath, userLocale, pathConfig)\n : undefined;\n\n // Combine localized path with dynamic parameters (/en/blog, /fr/fr-about, /fr/dashboard/1/fr-custom)\n const localizedPathWithParameters =\n localizedPath !== undefined\n ? replaceDynamicSegments(\n pathnameLocale\n ? standardizedPathname\n : `/${userLocale}${standardizedPathname}`,\n localizedPath\n )\n : undefined;\n\n // ---------- ROUTING LOGIC ---------- //\n\n // ----- CASE: no localized path exists ----- //\n\n if (localizedPathWithParameters === undefined) {\n // --- CASE: remove defaultLocale prefix --- //\n\n if (!prefixDefaultLocale && isSameDialect(userLocale, defaultLocale)) {\n if (pathnameLocale) {\n // REDIRECT CASE: used setLocale (/fr/customers -> /customers) (/en/customers -> /customers)\n if (clearResetCookie) {\n return getRedirectResponse(\n pathname.replace(\n new RegExp(`^/${unstandardizedPathnameLocale}`),\n ``\n ) || '/'\n );\n }\n } else {\n // REWRITE CASE: no pathnameLocale (/customers -> /en/customers)\n return getRewriteResponse(`/${userLocale}${pathname}`);\n }\n }\n\n // --- CASE: defaultLocale prefix --- //\n // REDIRECT CASE: no pathnameLocale (ie, /customers -> /fr/customers)\n else if (!pathnameLocale) {\n return getRedirectResponse(`/${userLocale}${pathname}`);\n }\n\n // REDIRECT CASE: wrong pathnameLocale (ie, /fr/customers -> /en/customers) (this usually happens after a locale switch)\n if (pathnameLocale && userLocale !== unstandardizedPathnameLocale) {\n return getRedirectResponse(\n pathname.replace(\n new RegExp(`^/${unstandardizedPathnameLocale}`),\n `/${userLocale}`\n )\n );\n }\n\n // BASE CASE: has pathnameLocale and it's correct\n return getNextResponse();\n }\n\n // ----- CASE: localized path exists ----- //\n\n if (!prefixDefaultLocale && isSameDialect(userLocale, defaultLocale)) {\n // --- CASE: remove defaultLocale prefix --- //\n\n if (pathnameLocale) {\n // REDIRECT CASE: remove locale prefix when setLocale is used (/en/blog -> /blog) (/fr/fr-about -> /en-about)\n if (clearResetCookie) {\n return getRedirectResponse(\n localizedPathWithParameters.replace(\n new RegExp(`^/${unstandardizedPathnameLocale}`),\n ``\n ) || '/'\n );\n }\n } else {\n // REDIRECT CASE: unprefixed pathname is wrong (/about -> /en-about)\n if (\n !pathnameLocale &&\n localizedPathWithParameters !== `/${userLocale}${pathname}`\n ) {\n return getRedirectResponse(\n localizedPathWithParameters.replace(\n new RegExp(`^/${userLocale}`),\n ''\n ) || '/'\n );\n }\n\n // REWRITE CASE: displaying correct path (/blog -> /en/blog)\n return getRewriteResponse(sharedPathWithParameters as string);\n }\n }\n\n // --- CASE: add defaultLocale prefix --- //\n\n // REDIRECT CASE: incorrect pathnameLocale\n if (pathname !== localizedPathWithParameters) {\n return getRedirectResponse(localizedPathWithParameters);\n }\n\n // REWRITE CASE: displaying correct localized path, which is the same as the shared path (/fil/blog => /fil/blog) (/fr/fr-dashboard/1/fr-custom => /fr/dashboard/1/custom)\n if (\n standardizedPathname !== sharedPathWithParameters // no rewrite needed if it's already the shared path\n ) {\n // convert to shared path with dynamic parameters\n return getRewriteResponse(sharedPathWithParameters as string);\n }\n }\n\n // BASE CASE\n return getNextResponse();\n }\n\n return middleware;\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"createNextMiddleware.js","names":["compilePathRegex","GTRuntime","libraryDefaultLocale","defaultLocaleCookieName","defaultResetLocaleCookieName","createUnsupportedLocalesWarning","createPathToSharedPathMap","pathnameMatchesRegex","NextResponse","getLocaleFromRequest","getResponse","getSharedPath","replaceDynamicSegments","getLocalizedPath"],"sources":["../../src/middleware-dir/createNextMiddleware.ts"],"sourcesContent":["import { isSameDialect, standardizeLocale } from '@generaltranslation/format';\nimport { GTRuntime } from 'generaltranslation/runtime';\nimport { libraryDefaultLocale } from 'generaltranslation/internal';\nimport { createUnsupportedLocalesWarning } from '../errors/createErrors';\nimport { NextRequest, NextResponse } from 'next/server';\nimport {\n defaultLocaleRoutingEnabledCookieName,\n defaultReferrerLocaleCookieName,\n} from '../utils/cookies';\nimport {\n defaultLocaleCookieName,\n defaultResetLocaleCookieName,\n} from '@generaltranslation/react-core/pure';\nimport {\n PathConfig,\n getSharedPath,\n replaceDynamicSegments,\n getLocalizedPath,\n createPathToSharedPathMap,\n getLocaleFromRequest,\n getResponse,\n ResponseConfig,\n} from './utils';\nimport { defaultLocaleHeaderName } from '../utils/headers';\nimport type { CustomMapping } from '@generaltranslation/format/types';\nimport type { HeadersAndCookies } from '../config-dir/props/withGTConfigProps';\nimport { compilePathRegex, pathnameMatchesRegex } from '../utils/pathRegex';\n\nconst NEXT_JS_SOURCE_MAP_PATH = '/__nextjs_source-map';\n\ntype MiddlewareEnvConfig = {\n customMapping?: CustomMapping;\n defaultLocale?: string;\n locales?: string[];\n headersAndCookies?: HeadersAndCookies;\n};\n\n/**\n * Middleware factory to create a Next.js middleware for i18n routing and locale detection.\n *\n * This middleware sets a cookie based on the locale derived from several sources\n * such as the request pathname, referer, or 'Accept-Language' header.\n * If locale routing is enabled, it redirects to the localized pathname and\n * updates the locale cookie.\n *\n * @param {boolean} [config.localeRouting=true] - Flag to enable or disable automatic locale-based routing.\n * @param {boolean} [config.prefixDefaultLocale=false] - Flag to enable or disable prefixing the default locale to the pathname, i.e., /en/about -> /about\n * @param {boolean} [config.ignoreSourceMaps=true] - Flag to enable or disable ignoring source maps\n * @param {PathConfig} [config.pathConfig] - Path configuration for locale routing\n * @returns {function} - A middleware function that processes the request and response.\n */\nexport function createNextMiddleware({\n localeRouting = true,\n prefixDefaultLocale = false,\n ignoreSourceMaps = true,\n pathConfig = {},\n}: {\n localeRouting?: boolean;\n prefixDefaultLocale?: boolean;\n ignoreSourceMaps?: boolean;\n pathConfig?: PathConfig;\n} = {}) {\n const pathRegex = compilePathRegex(\n process.env._GENERALTRANSLATION_PATH_REGEX\n );\n\n // i18n config\n let envParams: MiddlewareEnvConfig | undefined;\n if (process.env._GENERALTRANSLATION_I18N_CONFIG_PARAMS) {\n try {\n envParams = JSON.parse(\n process.env._GENERALTRANSLATION_I18N_CONFIG_PARAMS\n );\n } catch (error) {\n console.error(`gt-next middleware:`, error);\n }\n }\n\n // gt instance\n const gt = new GTRuntime({\n customMapping: envParams?.customMapping,\n });\n\n // using gt services\n const gtServicesEnabled =\n process.env._GENERALTRANSLATION_GT_SERVICES_ENABLED === 'true';\n\n // i18n config\n const defaultLocale: string =\n envParams?.defaultLocale || libraryDefaultLocale;\n const locales: string[] = envParams?.locales || [defaultLocale];\n\n // add canonical locales\n const canonicalLocales = Object.values(envParams?.customMapping || {})\n .filter(\n (locale): locale is { code: string } =>\n typeof locale === 'object' &&\n locale !== null &&\n 'code' in locale &&\n typeof locale.code === 'string' &&\n locale.code.length > 0\n )\n .map((locale) => locale.code);\n locales.push(...canonicalLocales);\n\n // cookies and header names\n const headersAndCookies = envParams?.headersAndCookies || {};\n const localeRoutingEnabledCookieName =\n headersAndCookies?.localeRoutingEnabledCookieName ||\n defaultLocaleRoutingEnabledCookieName;\n const referrerLocaleCookieName =\n headersAndCookies?.referrerLocaleCookieName ||\n defaultReferrerLocaleCookieName;\n const localeCookieName =\n headersAndCookies?.localeCookieName || defaultLocaleCookieName;\n const resetLocaleCookieName =\n headersAndCookies?.resetLocaleCookieName || defaultResetLocaleCookieName;\n const localeHeaderName =\n headersAndCookies?.localeHeaderName || defaultLocaleHeaderName;\n\n if (!gt.isValidLocale(defaultLocale))\n throw new Error(\n `gt-next middleware: defaultLocale \"${defaultLocale}\" is not a valid locale.`\n );\n\n const warningLocales = locales.filter((locale) => !gt.isValidLocale(locale));\n if (warningLocales.length)\n console.warn(createUnsupportedLocalesWarning(warningLocales));\n\n // ---------- PRE-PROCESSING PATHS ---------- //\n\n // Standardize pathConfig paths\n pathConfig = Object.entries(pathConfig).reduce<PathConfig>(\n (acc, [sharedPath, localizedPath]) => {\n if (typeof localizedPath === 'string') {\n acc[sharedPath] = localizedPath;\n } else {\n acc[sharedPath] = Object.entries(localizedPath).reduce<{\n [key: string]: string;\n }>((acc, [locale, localizedPath]) => {\n acc[gtServicesEnabled ? standardizeLocale(locale) : locale] =\n localizedPath;\n return acc;\n }, {});\n }\n return acc;\n },\n {}\n );\n\n // Create the path mapping\n const { pathToSharedPath, defaultLocalePaths } = createPathToSharedPathMap(\n pathConfig,\n prefixDefaultLocale,\n defaultLocale\n );\n\n /**\n * Processes the incoming request to determine the user's locale and sets a locale cookie.\n * Optionally redirects the user based on the locale if locale-based routing is enabled.\n *\n * - Checks if the request URL contains a locale.\n * - Falls back to the referer URL for locale if needed.\n * - If no locale is found in the URL or referer, it checks the 'Accept-Language' header.\n * - Sets a cookie with the detected or default locale.\n * - Redirects to the correct locale route if locale routing is enabled.\n *\n * @param {NextRequest} req - The incoming request object, containing URL and headers.\n * @returns {NextResponse} - The Next.js response, either continuing the request or redirecting to the localized URL.\n */\n function middleware(req: NextRequest) {\n if (!pathnameMatchesRegex(req.nextUrl.pathname, pathRegex)) {\n return NextResponse.next();\n }\n\n // Ignore source maps\n if (\n ignoreSourceMaps &&\n req.nextUrl.pathname.startsWith(NEXT_JS_SOURCE_MAP_PATH)\n ) {\n return NextResponse.next();\n }\n\n // ---------- LOCALE DETECTION ---------- //\n\n const {\n userLocale,\n pathnameLocale,\n unstandardizedPathnameLocale,\n clearResetCookie,\n } = getLocaleFromRequest(\n req,\n defaultLocale,\n locales,\n localeRouting,\n gtServicesEnabled,\n prefixDefaultLocale,\n defaultLocalePaths,\n referrerLocaleCookieName,\n localeCookieName,\n resetLocaleCookieName,\n gt\n );\n\n const headerList = new Headers(req.headers);\n\n const responseConfig: Omit<ResponseConfig, 'type'> = {\n originalUrl: req.nextUrl,\n headerList,\n userLocale,\n clearResetCookie,\n localeRouting,\n localeRoutingEnabledCookieName,\n resetLocaleCookieName,\n localeHeaderName,\n };\n\n const getRewriteResponse = (responsePath: string) =>\n getResponse({ responsePath, type: 'rewrite', ...responseConfig });\n\n const getRedirectResponse = (responsePath: string) =>\n getResponse({ responsePath, type: 'redirect', ...responseConfig });\n\n const getNextResponse = () =>\n getResponse({ type: 'next', ...responseConfig });\n\n if (localeRouting) {\n // ---------- GET PATHS ---------- //\n\n // get pathname\n const { pathname } = req.nextUrl;\n\n // standardize pathname (ie, /tg/welcome -> /fil/welcome), (/blog -> /blog)\n const standardizedPathname =\n pathnameLocale && pathnameLocale !== unstandardizedPathnameLocale\n ? pathname.replace(\n new RegExp(`^/${unstandardizedPathnameLocale}`),\n `/${userLocale}`\n )\n : pathname;\n\n // Get the shared path for the unprefixed pathname\n const sharedPath = getSharedPath(\n standardizedPathname,\n pathToSharedPath,\n pathnameLocale\n );\n\n // Get shared path with parameters (/en/dashboard/1/custom), for rewriting localized paths\n const sharedPathWithParameters =\n sharedPath !== undefined\n ? replaceDynamicSegments(\n pathnameLocale\n ? standardizedPathname\n : `/${userLocale}${standardizedPathname}`,\n `/${userLocale}${sharedPath}`\n )\n : undefined;\n\n // Localized path (/en/blog, /fr/fr-about, /fr/dashboard/[id]/custom)\n const localizedPath =\n sharedPath !== undefined\n ? getLocalizedPath(sharedPath, userLocale, pathConfig)\n : undefined;\n\n // Combine localized path with dynamic parameters (/en/blog, /fr/fr-about, /fr/dashboard/1/fr-custom)\n const localizedPathWithParameters =\n localizedPath !== undefined\n ? replaceDynamicSegments(\n pathnameLocale\n ? standardizedPathname\n : `/${userLocale}${standardizedPathname}`,\n localizedPath\n )\n : undefined;\n\n // ---------- ROUTING LOGIC ---------- //\n\n // ----- CASE: no localized path exists ----- //\n\n if (localizedPathWithParameters === undefined) {\n // --- CASE: remove defaultLocale prefix --- //\n\n if (!prefixDefaultLocale && isSameDialect(userLocale, defaultLocale)) {\n if (pathnameLocale) {\n // REDIRECT CASE: used setLocale (/fr/customers -> /customers) (/en/customers -> /customers)\n if (clearResetCookie) {\n return getRedirectResponse(\n pathname.replace(\n new RegExp(`^/${unstandardizedPathnameLocale}`),\n ``\n ) || '/'\n );\n }\n } else {\n // REWRITE CASE: no pathnameLocale (/customers -> /en/customers)\n return getRewriteResponse(`/${userLocale}${pathname}`);\n }\n }\n\n // --- CASE: defaultLocale prefix --- //\n // REDIRECT CASE: no pathnameLocale (ie, /customers -> /fr/customers)\n else if (!pathnameLocale) {\n return getRedirectResponse(`/${userLocale}${pathname}`);\n }\n\n // REDIRECT CASE: wrong pathnameLocale (ie, /fr/customers -> /en/customers) (this usually happens after a locale switch)\n if (pathnameLocale && userLocale !== unstandardizedPathnameLocale) {\n return getRedirectResponse(\n pathname.replace(\n new RegExp(`^/${unstandardizedPathnameLocale}`),\n `/${userLocale}`\n )\n );\n }\n\n // BASE CASE: has pathnameLocale and it's correct\n return getNextResponse();\n }\n\n // ----- CASE: localized path exists ----- //\n\n if (!prefixDefaultLocale && isSameDialect(userLocale, defaultLocale)) {\n // --- CASE: remove defaultLocale prefix --- //\n\n if (pathnameLocale) {\n // REDIRECT CASE: remove locale prefix when setLocale is used (/en/blog -> /blog) (/fr/fr-about -> /en-about)\n if (clearResetCookie) {\n return getRedirectResponse(\n localizedPathWithParameters.replace(\n new RegExp(`^/${unstandardizedPathnameLocale}`),\n ``\n ) || '/'\n );\n }\n } else {\n // REDIRECT CASE: unprefixed pathname is wrong (/about -> /en-about)\n if (\n !pathnameLocale &&\n localizedPathWithParameters !== `/${userLocale}${pathname}`\n ) {\n return getRedirectResponse(\n localizedPathWithParameters.replace(\n new RegExp(`^/${userLocale}`),\n ''\n ) || '/'\n );\n }\n\n // REWRITE CASE: displaying correct path (/blog -> /en/blog)\n return getRewriteResponse(sharedPathWithParameters as string);\n }\n }\n\n // --- CASE: add defaultLocale prefix --- //\n\n // REDIRECT CASE: incorrect pathnameLocale\n if (pathname !== localizedPathWithParameters) {\n return getRedirectResponse(localizedPathWithParameters);\n }\n\n // REWRITE CASE: displaying correct localized path, which is the same as the shared path (/fil/blog => /fil/blog) (/fr/fr-dashboard/1/fr-custom => /fr/dashboard/1/custom)\n if (\n standardizedPathname !== sharedPathWithParameters // no rewrite needed if it's already the shared path\n ) {\n // convert to shared path with dynamic parameters\n return getRewriteResponse(sharedPathWithParameters as string);\n }\n }\n\n // BASE CASE\n return getNextResponse();\n }\n\n return middleware;\n}\n"],"mappings":"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"}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import "../utils/headers.mjs";
|
|
2
2
|
import "../utils/cookies.mjs";
|
|
3
|
-
import {
|
|
3
|
+
import { createUnsupportedLocalesWarning } from "../errors/createErrors.mjs";
|
|
4
|
+
import { compilePathRegex, pathnameMatchesRegex } from "../utils/pathRegex.mjs";
|
|
4
5
|
import { createPathToSharedPathMap, getLocaleFromRequest, getLocalizedPath, getResponse, getSharedPath, replaceDynamicSegments } from "./utils.mjs";
|
|
5
6
|
import { libraryDefaultLocale } from "generaltranslation/internal";
|
|
6
7
|
import { defaultLocaleCookieName, defaultResetLocaleCookieName } from "@generaltranslation/react-core/pure";
|
|
@@ -20,17 +21,11 @@ const NEXT_JS_SOURCE_MAP_PATH = "/__nextjs_source-map";
|
|
|
20
21
|
* @param {boolean} [config.localeRouting=true] - Flag to enable or disable automatic locale-based routing.
|
|
21
22
|
* @param {boolean} [config.prefixDefaultLocale=false] - Flag to enable or disable prefixing the default locale to the pathname, i.e., /en/about -> /about
|
|
22
23
|
* @param {boolean} [config.ignoreSourceMaps=true] - Flag to enable or disable ignoring source maps
|
|
23
|
-
* @param {string} [config.regexFilter] - Regular expression that request pathnames must match for i18n middleware to be applied
|
|
24
24
|
* @param {PathConfig} [config.pathConfig] - Path configuration for locale routing
|
|
25
25
|
* @returns {function} - A middleware function that processes the request and response.
|
|
26
26
|
*/
|
|
27
|
-
function createNextMiddleware({ localeRouting = true, prefixDefaultLocale = false, ignoreSourceMaps = true,
|
|
28
|
-
|
|
29
|
-
if (regexFilter !== void 0) try {
|
|
30
|
-
pathFilter = new RegExp(regexFilter);
|
|
31
|
-
} catch (error) {
|
|
32
|
-
throw new Error(createInvalidMiddlewareRegexError(regexFilter, error));
|
|
33
|
-
}
|
|
27
|
+
function createNextMiddleware({ localeRouting = true, prefixDefaultLocale = false, ignoreSourceMaps = true, pathConfig = {} } = {}) {
|
|
28
|
+
const pathRegex = compilePathRegex(process.env._GENERALTRANSLATION_PATH_REGEX);
|
|
34
29
|
let envParams;
|
|
35
30
|
if (process.env._GENERALTRANSLATION_I18N_CONFIG_PARAMS) try {
|
|
36
31
|
envParams = JSON.parse(process.env._GENERALTRANSLATION_I18N_CONFIG_PARAMS);
|
|
@@ -75,7 +70,7 @@ function createNextMiddleware({ localeRouting = true, prefixDefaultLocale = fals
|
|
|
75
70
|
* @returns {NextResponse} - The Next.js response, either continuing the request or redirecting to the localized URL.
|
|
76
71
|
*/
|
|
77
72
|
function middleware(req) {
|
|
78
|
-
if (
|
|
73
|
+
if (!pathnameMatchesRegex(req.nextUrl.pathname, pathRegex)) return NextResponse.next();
|
|
79
74
|
if (ignoreSourceMaps && req.nextUrl.pathname.startsWith(NEXT_JS_SOURCE_MAP_PATH)) return NextResponse.next();
|
|
80
75
|
const { userLocale, pathnameLocale, unstandardizedPathnameLocale, clearResetCookie } = getLocaleFromRequest(req, defaultLocale, locales, localeRouting, gtServicesEnabled, prefixDefaultLocale, defaultLocalePaths, referrerLocaleCookieName, localeCookieName, resetLocaleCookieName, gt);
|
|
81
76
|
const headerList = new Headers(req.headers);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"createNextMiddleware.mjs","names":[],"sources":["../../src/middleware-dir/createNextMiddleware.ts"],"sourcesContent":["import { isSameDialect, standardizeLocale } from '@generaltranslation/format';\nimport { GTRuntime } from 'generaltranslation/runtime';\nimport { libraryDefaultLocale } from 'generaltranslation/internal';\nimport {\n createInvalidMiddlewareRegexError,\n createUnsupportedLocalesWarning,\n} from '../errors/createErrors';\nimport { NextRequest, NextResponse } from 'next/server';\nimport {\n defaultLocaleRoutingEnabledCookieName,\n defaultReferrerLocaleCookieName,\n} from '../utils/cookies';\nimport {\n defaultLocaleCookieName,\n defaultResetLocaleCookieName,\n} from '@generaltranslation/react-core/pure';\nimport {\n PathConfig,\n getSharedPath,\n replaceDynamicSegments,\n getLocalizedPath,\n createPathToSharedPathMap,\n getLocaleFromRequest,\n getResponse,\n ResponseConfig,\n} from './utils';\nimport { defaultLocaleHeaderName } from '../utils/headers';\nimport type { CustomMapping } from '@generaltranslation/format/types';\nimport type { HeadersAndCookies } from '../config-dir/props/withGTConfigProps';\n\nconst NEXT_JS_SOURCE_MAP_PATH = '/__nextjs_source-map';\n\ntype MiddlewareEnvConfig = {\n customMapping?: CustomMapping;\n defaultLocale?: string;\n locales?: string[];\n headersAndCookies?: HeadersAndCookies;\n};\n\n/**\n * Middleware factory to create a Next.js middleware for i18n routing and locale detection.\n *\n * This middleware sets a cookie based on the locale derived from several sources\n * such as the request pathname, referer, or 'Accept-Language' header.\n * If locale routing is enabled, it redirects to the localized pathname and\n * updates the locale cookie.\n *\n * @param {boolean} [config.localeRouting=true] - Flag to enable or disable automatic locale-based routing.\n * @param {boolean} [config.prefixDefaultLocale=false] - Flag to enable or disable prefixing the default locale to the pathname, i.e., /en/about -> /about\n * @param {boolean} [config.ignoreSourceMaps=true] - Flag to enable or disable ignoring source maps\n * @param {string} [config.regexFilter] - Regular expression that request pathnames must match for i18n middleware to be applied\n * @param {PathConfig} [config.pathConfig] - Path configuration for locale routing\n * @returns {function} - A middleware function that processes the request and response.\n */\nexport function createNextMiddleware({\n localeRouting = true,\n prefixDefaultLocale = false,\n ignoreSourceMaps = true,\n regexFilter,\n pathConfig = {},\n}: {\n localeRouting?: boolean;\n prefixDefaultLocale?: boolean;\n ignoreSourceMaps?: boolean;\n regexFilter?: string;\n pathConfig?: PathConfig;\n} = {}) {\n let pathFilter: RegExp | undefined;\n if (regexFilter !== undefined) {\n try {\n pathFilter = new RegExp(regexFilter);\n } catch (error) {\n throw new Error(createInvalidMiddlewareRegexError(regexFilter, error));\n }\n }\n\n // i18n config\n let envParams: MiddlewareEnvConfig | undefined;\n if (process.env._GENERALTRANSLATION_I18N_CONFIG_PARAMS) {\n try {\n envParams = JSON.parse(\n process.env._GENERALTRANSLATION_I18N_CONFIG_PARAMS\n );\n } catch (error) {\n console.error(`gt-next middleware:`, error);\n }\n }\n\n // gt instance\n const gt = new GTRuntime({\n customMapping: envParams?.customMapping,\n });\n\n // using gt services\n const gtServicesEnabled =\n process.env._GENERALTRANSLATION_GT_SERVICES_ENABLED === 'true';\n\n // i18n config\n const defaultLocale: string =\n envParams?.defaultLocale || libraryDefaultLocale;\n const locales: string[] = envParams?.locales || [defaultLocale];\n\n // add canonical locales\n const canonicalLocales = Object.values(envParams?.customMapping || {})\n .filter(\n (locale): locale is { code: string } =>\n typeof locale === 'object' &&\n locale !== null &&\n 'code' in locale &&\n typeof locale.code === 'string' &&\n locale.code.length > 0\n )\n .map((locale) => locale.code);\n locales.push(...canonicalLocales);\n\n // cookies and header names\n const headersAndCookies = envParams?.headersAndCookies || {};\n const localeRoutingEnabledCookieName =\n headersAndCookies?.localeRoutingEnabledCookieName ||\n defaultLocaleRoutingEnabledCookieName;\n const referrerLocaleCookieName =\n headersAndCookies?.referrerLocaleCookieName ||\n defaultReferrerLocaleCookieName;\n const localeCookieName =\n headersAndCookies?.localeCookieName || defaultLocaleCookieName;\n const resetLocaleCookieName =\n headersAndCookies?.resetLocaleCookieName || defaultResetLocaleCookieName;\n const localeHeaderName =\n headersAndCookies?.localeHeaderName || defaultLocaleHeaderName;\n\n if (!gt.isValidLocale(defaultLocale))\n throw new Error(\n `gt-next middleware: defaultLocale \"${defaultLocale}\" is not a valid locale.`\n );\n\n const warningLocales = locales.filter((locale) => !gt.isValidLocale(locale));\n if (warningLocales.length)\n console.warn(createUnsupportedLocalesWarning(warningLocales));\n\n // ---------- PRE-PROCESSING PATHS ---------- //\n\n // Standardize pathConfig paths\n pathConfig = Object.entries(pathConfig).reduce<PathConfig>(\n (acc, [sharedPath, localizedPath]) => {\n if (typeof localizedPath === 'string') {\n acc[sharedPath] = localizedPath;\n } else {\n acc[sharedPath] = Object.entries(localizedPath).reduce<{\n [key: string]: string;\n }>((acc, [locale, localizedPath]) => {\n acc[gtServicesEnabled ? standardizeLocale(locale) : locale] =\n localizedPath;\n return acc;\n }, {});\n }\n return acc;\n },\n {}\n );\n\n // Create the path mapping\n const { pathToSharedPath, defaultLocalePaths } = createPathToSharedPathMap(\n pathConfig,\n prefixDefaultLocale,\n defaultLocale\n );\n\n /**\n * Processes the incoming request to determine the user's locale and sets a locale cookie.\n * Optionally redirects the user based on the locale if locale-based routing is enabled.\n *\n * - Checks if the request URL contains a locale.\n * - Falls back to the referer URL for locale if needed.\n * - If no locale is found in the URL or referer, it checks the 'Accept-Language' header.\n * - Sets a cookie with the detected or default locale.\n * - Redirects to the correct locale route if locale routing is enabled.\n *\n * @param {NextRequest} req - The incoming request object, containing URL and headers.\n * @returns {NextResponse} - The Next.js response, either continuing the request or redirecting to the localized URL.\n */\n function middleware(req: NextRequest) {\n if (pathFilter && !pathFilter.test(req.nextUrl.pathname)) {\n return NextResponse.next();\n }\n\n // Ignore source maps\n if (\n ignoreSourceMaps &&\n req.nextUrl.pathname.startsWith(NEXT_JS_SOURCE_MAP_PATH)\n ) {\n return NextResponse.next();\n }\n\n // ---------- LOCALE DETECTION ---------- //\n\n const {\n userLocale,\n pathnameLocale,\n unstandardizedPathnameLocale,\n clearResetCookie,\n } = getLocaleFromRequest(\n req,\n defaultLocale,\n locales,\n localeRouting,\n gtServicesEnabled,\n prefixDefaultLocale,\n defaultLocalePaths,\n referrerLocaleCookieName,\n localeCookieName,\n resetLocaleCookieName,\n gt\n );\n\n const headerList = new Headers(req.headers);\n\n const responseConfig: Omit<ResponseConfig, 'type'> = {\n originalUrl: req.nextUrl,\n headerList,\n userLocale,\n clearResetCookie,\n localeRouting,\n localeRoutingEnabledCookieName,\n resetLocaleCookieName,\n localeHeaderName,\n };\n\n const getRewriteResponse = (responsePath: string) =>\n getResponse({ responsePath, type: 'rewrite', ...responseConfig });\n\n const getRedirectResponse = (responsePath: string) =>\n getResponse({ responsePath, type: 'redirect', ...responseConfig });\n\n const getNextResponse = () =>\n getResponse({ type: 'next', ...responseConfig });\n\n if (localeRouting) {\n // ---------- GET PATHS ---------- //\n\n // get pathname\n const { pathname } = req.nextUrl;\n\n // standardize pathname (ie, /tg/welcome -> /fil/welcome), (/blog -> /blog)\n const standardizedPathname =\n pathnameLocale && pathnameLocale !== unstandardizedPathnameLocale\n ? pathname.replace(\n new RegExp(`^/${unstandardizedPathnameLocale}`),\n `/${userLocale}`\n )\n : pathname;\n\n // Get the shared path for the unprefixed pathname\n const sharedPath = getSharedPath(\n standardizedPathname,\n pathToSharedPath,\n pathnameLocale\n );\n\n // Get shared path with parameters (/en/dashboard/1/custom), for rewriting localized paths\n const sharedPathWithParameters =\n sharedPath !== undefined\n ? replaceDynamicSegments(\n pathnameLocale\n ? standardizedPathname\n : `/${userLocale}${standardizedPathname}`,\n `/${userLocale}${sharedPath}`\n )\n : undefined;\n\n // Localized path (/en/blog, /fr/fr-about, /fr/dashboard/[id]/custom)\n const localizedPath =\n sharedPath !== undefined\n ? getLocalizedPath(sharedPath, userLocale, pathConfig)\n : undefined;\n\n // Combine localized path with dynamic parameters (/en/blog, /fr/fr-about, /fr/dashboard/1/fr-custom)\n const localizedPathWithParameters =\n localizedPath !== undefined\n ? replaceDynamicSegments(\n pathnameLocale\n ? standardizedPathname\n : `/${userLocale}${standardizedPathname}`,\n localizedPath\n )\n : undefined;\n\n // ---------- ROUTING LOGIC ---------- //\n\n // ----- CASE: no localized path exists ----- //\n\n if (localizedPathWithParameters === undefined) {\n // --- CASE: remove defaultLocale prefix --- //\n\n if (!prefixDefaultLocale && isSameDialect(userLocale, defaultLocale)) {\n if (pathnameLocale) {\n // REDIRECT CASE: used setLocale (/fr/customers -> /customers) (/en/customers -> /customers)\n if (clearResetCookie) {\n return getRedirectResponse(\n pathname.replace(\n new RegExp(`^/${unstandardizedPathnameLocale}`),\n ``\n ) || '/'\n );\n }\n } else {\n // REWRITE CASE: no pathnameLocale (/customers -> /en/customers)\n return getRewriteResponse(`/${userLocale}${pathname}`);\n }\n }\n\n // --- CASE: defaultLocale prefix --- //\n // REDIRECT CASE: no pathnameLocale (ie, /customers -> /fr/customers)\n else if (!pathnameLocale) {\n return getRedirectResponse(`/${userLocale}${pathname}`);\n }\n\n // REDIRECT CASE: wrong pathnameLocale (ie, /fr/customers -> /en/customers) (this usually happens after a locale switch)\n if (pathnameLocale && userLocale !== unstandardizedPathnameLocale) {\n return getRedirectResponse(\n pathname.replace(\n new RegExp(`^/${unstandardizedPathnameLocale}`),\n `/${userLocale}`\n )\n );\n }\n\n // BASE CASE: has pathnameLocale and it's correct\n return getNextResponse();\n }\n\n // ----- CASE: localized path exists ----- //\n\n if (!prefixDefaultLocale && isSameDialect(userLocale, defaultLocale)) {\n // --- CASE: remove defaultLocale prefix --- //\n\n if (pathnameLocale) {\n // REDIRECT CASE: remove locale prefix when setLocale is used (/en/blog -> /blog) (/fr/fr-about -> /en-about)\n if (clearResetCookie) {\n return getRedirectResponse(\n localizedPathWithParameters.replace(\n new RegExp(`^/${unstandardizedPathnameLocale}`),\n ``\n ) || '/'\n );\n }\n } else {\n // REDIRECT CASE: unprefixed pathname is wrong (/about -> /en-about)\n if (\n !pathnameLocale &&\n localizedPathWithParameters !== `/${userLocale}${pathname}`\n ) {\n return getRedirectResponse(\n localizedPathWithParameters.replace(\n new RegExp(`^/${userLocale}`),\n ''\n ) || '/'\n );\n }\n\n // REWRITE CASE: displaying correct path (/blog -> /en/blog)\n return getRewriteResponse(sharedPathWithParameters as string);\n }\n }\n\n // --- CASE: add defaultLocale prefix --- //\n\n // REDIRECT CASE: incorrect pathnameLocale\n if (pathname !== localizedPathWithParameters) {\n return getRedirectResponse(localizedPathWithParameters);\n }\n\n // REWRITE CASE: displaying correct localized path, which is the same as the shared path (/fil/blog => /fil/blog) (/fr/fr-dashboard/1/fr-custom => /fr/dashboard/1/custom)\n if (\n standardizedPathname !== sharedPathWithParameters // no rewrite needed if it's already the shared path\n ) {\n // convert to shared path with dynamic parameters\n return getRewriteResponse(sharedPathWithParameters as string);\n }\n }\n\n // BASE CASE\n return getNextResponse();\n }\n\n return middleware;\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"createNextMiddleware.mjs","names":[],"sources":["../../src/middleware-dir/createNextMiddleware.ts"],"sourcesContent":["import { isSameDialect, standardizeLocale } from '@generaltranslation/format';\nimport { GTRuntime } from 'generaltranslation/runtime';\nimport { libraryDefaultLocale } from 'generaltranslation/internal';\nimport { createUnsupportedLocalesWarning } from '../errors/createErrors';\nimport { NextRequest, NextResponse } from 'next/server';\nimport {\n defaultLocaleRoutingEnabledCookieName,\n defaultReferrerLocaleCookieName,\n} from '../utils/cookies';\nimport {\n defaultLocaleCookieName,\n defaultResetLocaleCookieName,\n} from '@generaltranslation/react-core/pure';\nimport {\n PathConfig,\n getSharedPath,\n replaceDynamicSegments,\n getLocalizedPath,\n createPathToSharedPathMap,\n getLocaleFromRequest,\n getResponse,\n ResponseConfig,\n} from './utils';\nimport { defaultLocaleHeaderName } from '../utils/headers';\nimport type { CustomMapping } from '@generaltranslation/format/types';\nimport type { HeadersAndCookies } from '../config-dir/props/withGTConfigProps';\nimport { compilePathRegex, pathnameMatchesRegex } from '../utils/pathRegex';\n\nconst NEXT_JS_SOURCE_MAP_PATH = '/__nextjs_source-map';\n\ntype MiddlewareEnvConfig = {\n customMapping?: CustomMapping;\n defaultLocale?: string;\n locales?: string[];\n headersAndCookies?: HeadersAndCookies;\n};\n\n/**\n * Middleware factory to create a Next.js middleware for i18n routing and locale detection.\n *\n * This middleware sets a cookie based on the locale derived from several sources\n * such as the request pathname, referer, or 'Accept-Language' header.\n * If locale routing is enabled, it redirects to the localized pathname and\n * updates the locale cookie.\n *\n * @param {boolean} [config.localeRouting=true] - Flag to enable or disable automatic locale-based routing.\n * @param {boolean} [config.prefixDefaultLocale=false] - Flag to enable or disable prefixing the default locale to the pathname, i.e., /en/about -> /about\n * @param {boolean} [config.ignoreSourceMaps=true] - Flag to enable or disable ignoring source maps\n * @param {PathConfig} [config.pathConfig] - Path configuration for locale routing\n * @returns {function} - A middleware function that processes the request and response.\n */\nexport function createNextMiddleware({\n localeRouting = true,\n prefixDefaultLocale = false,\n ignoreSourceMaps = true,\n pathConfig = {},\n}: {\n localeRouting?: boolean;\n prefixDefaultLocale?: boolean;\n ignoreSourceMaps?: boolean;\n pathConfig?: PathConfig;\n} = {}) {\n const pathRegex = compilePathRegex(\n process.env._GENERALTRANSLATION_PATH_REGEX\n );\n\n // i18n config\n let envParams: MiddlewareEnvConfig | undefined;\n if (process.env._GENERALTRANSLATION_I18N_CONFIG_PARAMS) {\n try {\n envParams = JSON.parse(\n process.env._GENERALTRANSLATION_I18N_CONFIG_PARAMS\n );\n } catch (error) {\n console.error(`gt-next middleware:`, error);\n }\n }\n\n // gt instance\n const gt = new GTRuntime({\n customMapping: envParams?.customMapping,\n });\n\n // using gt services\n const gtServicesEnabled =\n process.env._GENERALTRANSLATION_GT_SERVICES_ENABLED === 'true';\n\n // i18n config\n const defaultLocale: string =\n envParams?.defaultLocale || libraryDefaultLocale;\n const locales: string[] = envParams?.locales || [defaultLocale];\n\n // add canonical locales\n const canonicalLocales = Object.values(envParams?.customMapping || {})\n .filter(\n (locale): locale is { code: string } =>\n typeof locale === 'object' &&\n locale !== null &&\n 'code' in locale &&\n typeof locale.code === 'string' &&\n locale.code.length > 0\n )\n .map((locale) => locale.code);\n locales.push(...canonicalLocales);\n\n // cookies and header names\n const headersAndCookies = envParams?.headersAndCookies || {};\n const localeRoutingEnabledCookieName =\n headersAndCookies?.localeRoutingEnabledCookieName ||\n defaultLocaleRoutingEnabledCookieName;\n const referrerLocaleCookieName =\n headersAndCookies?.referrerLocaleCookieName ||\n defaultReferrerLocaleCookieName;\n const localeCookieName =\n headersAndCookies?.localeCookieName || defaultLocaleCookieName;\n const resetLocaleCookieName =\n headersAndCookies?.resetLocaleCookieName || defaultResetLocaleCookieName;\n const localeHeaderName =\n headersAndCookies?.localeHeaderName || defaultLocaleHeaderName;\n\n if (!gt.isValidLocale(defaultLocale))\n throw new Error(\n `gt-next middleware: defaultLocale \"${defaultLocale}\" is not a valid locale.`\n );\n\n const warningLocales = locales.filter((locale) => !gt.isValidLocale(locale));\n if (warningLocales.length)\n console.warn(createUnsupportedLocalesWarning(warningLocales));\n\n // ---------- PRE-PROCESSING PATHS ---------- //\n\n // Standardize pathConfig paths\n pathConfig = Object.entries(pathConfig).reduce<PathConfig>(\n (acc, [sharedPath, localizedPath]) => {\n if (typeof localizedPath === 'string') {\n acc[sharedPath] = localizedPath;\n } else {\n acc[sharedPath] = Object.entries(localizedPath).reduce<{\n [key: string]: string;\n }>((acc, [locale, localizedPath]) => {\n acc[gtServicesEnabled ? standardizeLocale(locale) : locale] =\n localizedPath;\n return acc;\n }, {});\n }\n return acc;\n },\n {}\n );\n\n // Create the path mapping\n const { pathToSharedPath, defaultLocalePaths } = createPathToSharedPathMap(\n pathConfig,\n prefixDefaultLocale,\n defaultLocale\n );\n\n /**\n * Processes the incoming request to determine the user's locale and sets a locale cookie.\n * Optionally redirects the user based on the locale if locale-based routing is enabled.\n *\n * - Checks if the request URL contains a locale.\n * - Falls back to the referer URL for locale if needed.\n * - If no locale is found in the URL or referer, it checks the 'Accept-Language' header.\n * - Sets a cookie with the detected or default locale.\n * - Redirects to the correct locale route if locale routing is enabled.\n *\n * @param {NextRequest} req - The incoming request object, containing URL and headers.\n * @returns {NextResponse} - The Next.js response, either continuing the request or redirecting to the localized URL.\n */\n function middleware(req: NextRequest) {\n if (!pathnameMatchesRegex(req.nextUrl.pathname, pathRegex)) {\n return NextResponse.next();\n }\n\n // Ignore source maps\n if (\n ignoreSourceMaps &&\n req.nextUrl.pathname.startsWith(NEXT_JS_SOURCE_MAP_PATH)\n ) {\n return NextResponse.next();\n }\n\n // ---------- LOCALE DETECTION ---------- //\n\n const {\n userLocale,\n pathnameLocale,\n unstandardizedPathnameLocale,\n clearResetCookie,\n } = getLocaleFromRequest(\n req,\n defaultLocale,\n locales,\n localeRouting,\n gtServicesEnabled,\n prefixDefaultLocale,\n defaultLocalePaths,\n referrerLocaleCookieName,\n localeCookieName,\n resetLocaleCookieName,\n gt\n );\n\n const headerList = new Headers(req.headers);\n\n const responseConfig: Omit<ResponseConfig, 'type'> = {\n originalUrl: req.nextUrl,\n headerList,\n userLocale,\n clearResetCookie,\n localeRouting,\n localeRoutingEnabledCookieName,\n resetLocaleCookieName,\n localeHeaderName,\n };\n\n const getRewriteResponse = (responsePath: string) =>\n getResponse({ responsePath, type: 'rewrite', ...responseConfig });\n\n const getRedirectResponse = (responsePath: string) =>\n getResponse({ responsePath, type: 'redirect', ...responseConfig });\n\n const getNextResponse = () =>\n getResponse({ type: 'next', ...responseConfig });\n\n if (localeRouting) {\n // ---------- GET PATHS ---------- //\n\n // get pathname\n const { pathname } = req.nextUrl;\n\n // standardize pathname (ie, /tg/welcome -> /fil/welcome), (/blog -> /blog)\n const standardizedPathname =\n pathnameLocale && pathnameLocale !== unstandardizedPathnameLocale\n ? pathname.replace(\n new RegExp(`^/${unstandardizedPathnameLocale}`),\n `/${userLocale}`\n )\n : pathname;\n\n // Get the shared path for the unprefixed pathname\n const sharedPath = getSharedPath(\n standardizedPathname,\n pathToSharedPath,\n pathnameLocale\n );\n\n // Get shared path with parameters (/en/dashboard/1/custom), for rewriting localized paths\n const sharedPathWithParameters =\n sharedPath !== undefined\n ? replaceDynamicSegments(\n pathnameLocale\n ? standardizedPathname\n : `/${userLocale}${standardizedPathname}`,\n `/${userLocale}${sharedPath}`\n )\n : undefined;\n\n // Localized path (/en/blog, /fr/fr-about, /fr/dashboard/[id]/custom)\n const localizedPath =\n sharedPath !== undefined\n ? getLocalizedPath(sharedPath, userLocale, pathConfig)\n : undefined;\n\n // Combine localized path with dynamic parameters (/en/blog, /fr/fr-about, /fr/dashboard/1/fr-custom)\n const localizedPathWithParameters =\n localizedPath !== undefined\n ? replaceDynamicSegments(\n pathnameLocale\n ? standardizedPathname\n : `/${userLocale}${standardizedPathname}`,\n localizedPath\n )\n : undefined;\n\n // ---------- ROUTING LOGIC ---------- //\n\n // ----- CASE: no localized path exists ----- //\n\n if (localizedPathWithParameters === undefined) {\n // --- CASE: remove defaultLocale prefix --- //\n\n if (!prefixDefaultLocale && isSameDialect(userLocale, defaultLocale)) {\n if (pathnameLocale) {\n // REDIRECT CASE: used setLocale (/fr/customers -> /customers) (/en/customers -> /customers)\n if (clearResetCookie) {\n return getRedirectResponse(\n pathname.replace(\n new RegExp(`^/${unstandardizedPathnameLocale}`),\n ``\n ) || '/'\n );\n }\n } else {\n // REWRITE CASE: no pathnameLocale (/customers -> /en/customers)\n return getRewriteResponse(`/${userLocale}${pathname}`);\n }\n }\n\n // --- CASE: defaultLocale prefix --- //\n // REDIRECT CASE: no pathnameLocale (ie, /customers -> /fr/customers)\n else if (!pathnameLocale) {\n return getRedirectResponse(`/${userLocale}${pathname}`);\n }\n\n // REDIRECT CASE: wrong pathnameLocale (ie, /fr/customers -> /en/customers) (this usually happens after a locale switch)\n if (pathnameLocale && userLocale !== unstandardizedPathnameLocale) {\n return getRedirectResponse(\n pathname.replace(\n new RegExp(`^/${unstandardizedPathnameLocale}`),\n `/${userLocale}`\n )\n );\n }\n\n // BASE CASE: has pathnameLocale and it's correct\n return getNextResponse();\n }\n\n // ----- CASE: localized path exists ----- //\n\n if (!prefixDefaultLocale && isSameDialect(userLocale, defaultLocale)) {\n // --- CASE: remove defaultLocale prefix --- //\n\n if (pathnameLocale) {\n // REDIRECT CASE: remove locale prefix when setLocale is used (/en/blog -> /blog) (/fr/fr-about -> /en-about)\n if (clearResetCookie) {\n return getRedirectResponse(\n localizedPathWithParameters.replace(\n new RegExp(`^/${unstandardizedPathnameLocale}`),\n ``\n ) || '/'\n );\n }\n } else {\n // REDIRECT CASE: unprefixed pathname is wrong (/about -> /en-about)\n if (\n !pathnameLocale &&\n localizedPathWithParameters !== `/${userLocale}${pathname}`\n ) {\n return getRedirectResponse(\n localizedPathWithParameters.replace(\n new RegExp(`^/${userLocale}`),\n ''\n ) || '/'\n );\n }\n\n // REWRITE CASE: displaying correct path (/blog -> /en/blog)\n return getRewriteResponse(sharedPathWithParameters as string);\n }\n }\n\n // --- CASE: add defaultLocale prefix --- //\n\n // REDIRECT CASE: incorrect pathnameLocale\n if (pathname !== localizedPathWithParameters) {\n return getRedirectResponse(localizedPathWithParameters);\n }\n\n // REWRITE CASE: displaying correct localized path, which is the same as the shared path (/fil/blog => /fil/blog) (/fr/fr-dashboard/1/fr-custom => /fr/dashboard/1/custom)\n if (\n standardizedPathname !== sharedPathWithParameters // no rewrite needed if it's already the shared path\n ) {\n // convert to shared path with dynamic parameters\n return getRewriteResponse(sharedPathWithParameters as string);\n }\n }\n\n // BASE CASE\n return getNextResponse();\n }\n\n return middleware;\n}\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../src/middleware-dir/utils.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAExD,OAAO,EAAE,SAAS,EAAE,MAAM,4BAA4B,CAAC;AACvD,OAAO,EAAE,OAAO,EAAE,MAAM,+BAA+B,CAAC;
|
|
1
|
+
{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../src/middleware-dir/utils.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAExD,OAAO,EAAE,SAAS,EAAE,MAAM,4BAA4B,CAAC;AACvD,OAAO,EAAE,OAAO,EAAE,MAAM,+BAA+B,CAAC;AAGxD,MAAM,MAAM,UAAU,GAAG;IACvB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG;QAAE,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAAA;KAAE,CAAC;CACnD,CAAC;AAEF,MAAM,MAAM,cAAc,GAAG;IAC3B,IAAI,EAAE,MAAM,GAAG,SAAS,GAAG,UAAU,CAAC;IACtC,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,WAAW,EAAE,OAAO,CAAC;IACrB,UAAU,EAAE,MAAM,CAAC;IACnB,gBAAgB,EAAE,OAAO,CAAC;IAC1B,UAAU,EAAE,OAAO,CAAC;IACpB,aAAa,EAAE,OAAO,CAAC;IACvB,8BAA8B,EAAE,MAAM,CAAC;IACvC,qBAAqB,EAAE,MAAM,CAAC;IAC9B,gBAAgB,EAAE,MAAM,CAAC;CAC1B,CAAC;AASF,wBAAgB,WAAW,CAAC,EAC1B,IAAI,EACJ,WAAW,EACX,YAAmC,EACnC,UAAU,EACV,gBAAgB,EAChB,UAAU,EACV,aAAa,EACb,8BAA8B,EAC9B,qBAAqB,EACrB,gBAAgB,GACjB,EAAE,cAAc,GAAG,YAAY,CAAC,OAAO,CAAC,CAoCxC;AAED;;GAEG;AACH,wBAAgB,aAAa,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAG7D;AAED;;GAEG;AACH,wBAAgB,oBAAoB,CAClC,YAAY,EAAE,MAAM,EACpB,IAAI,EAAE,MAAM,GACX,MAAM,EAAE,CAcV;AAED;;GAEG;AACH,wBAAgB,sBAAsB,CACpC,IAAI,EAAE,MAAM,EACZ,YAAY,EAAE,MAAM,GACnB,MAAM,CASR;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAC9B,UAAU,EAAE,MAAM,EAClB,MAAM,EAAE,MAAM,EACd,UAAU,EAAE,UAAU,GACrB,MAAM,GAAG,SAAS,CAapB;AAED;;GAEG;AACH,wBAAgB,yBAAyB,CACvC,UAAU,EAAE,UAAU,EACtB,mBAAmB,EAAE,OAAO,EAC5B,aAAa,EAAE,MAAM,GACpB;IACD,gBAAgB,EAAE;QAAE,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAAA;KAAE,CAAC;IAC5C,kBAAkB,EAAE,MAAM,EAAE,CAAC;CAC9B,CA+BA;AAED;;GAEG;AACH,wBAAgB,aAAa,CAC3B,oBAAoB,EAAE,MAAM,EAC5B,gBAAgB,EAAE;IAAE,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAAA;CAAE,EAC3C,cAAc,EAAE,MAAM,GAAG,SAAS,GACjC,MAAM,GAAG,SAAS,CAqCpB;AA8BD;;GAEG;AACH,wBAAgB,oBAAoB,CAClC,GAAG,EAAE,WAAW,EAChB,aAAa,EAAE,MAAM,EACrB,eAAe,EAAE,MAAM,EAAE,EACzB,aAAa,EAAE,OAAO,EACtB,iBAAiB,EAAE,OAAO,EAC1B,mBAAmB,EAAE,OAAO,EAC5B,kBAAkB,EAAE,MAAM,EAAE,EAC5B,wBAAwB,EAAE,MAAM,EAChC,gBAAgB,EAAE,MAAM,EACxB,qBAAqB,EAAE,MAAM,EAC7B,EAAE,EAAE,SAAS,GACZ;IACD,UAAU,EAAE,MAAM,CAAC;IACnB,cAAc,EAAE,MAAM,GAAG,SAAS,CAAC;IACnC,4BAA4B,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC;IACxD,gBAAgB,EAAE,OAAO,CAAC;CAC3B,CA6FA"}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
2
|
require("../_virtual/_rolldown/runtime.js");
|
|
3
3
|
let _generaltranslation_format = require("@generaltranslation/format");
|
|
4
|
+
let gt_i18n_internal = require("gt-i18n/internal");
|
|
4
5
|
let next_server_js = require("next/server.js");
|
|
5
6
|
//#region src/middleware-dir/utils.ts
|
|
6
7
|
const DYNAMIC_PATH_SEGMENT_PATTERN = "/[^/]+";
|
|
@@ -147,10 +148,7 @@ function getLocaleFromRequest(req, defaultLocale, approvedLocales, localeRouting
|
|
|
147
148
|
const referrerLocale = referrerLocaleCookie.value;
|
|
148
149
|
if (gt.determineLocale([referrerLocale], approvedLocales)) candidates.push(referrerLocale);
|
|
149
150
|
}
|
|
150
|
-
if (process.env._GENERALTRANSLATION_IGNORE_BROWSER_LOCALES === "false")
|
|
151
|
-
const acceptedLocales = headerList.get("accept-language")?.split(",").map((item) => item.split(";")?.[0].trim()) || [];
|
|
152
|
-
if (acceptedLocales) candidates.push(...acceptedLocales);
|
|
153
|
-
}
|
|
151
|
+
if (process.env._GENERALTRANSLATION_IGNORE_BROWSER_LOCALES === "false") candidates.push(...(0, gt_i18n_internal.parseAcceptLanguage)(headerList.get("accept-language")));
|
|
154
152
|
candidates.push(defaultLocale);
|
|
155
153
|
const unstandardizedUserLocale = gt.determineLocale(candidates.filter((locale) => gt.isValidLocale(locale)), approvedLocales) || defaultLocale;
|
|
156
154
|
return {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"utils.js","names":["NextResponse"],"sources":["../../src/middleware-dir/utils.ts"],"sourcesContent":["import { NextRequest, NextResponse } from 'next/server';\nimport { standardizeLocale } from '@generaltranslation/format';\nimport { GTRuntime } from 'generaltranslation/runtime';\nimport { NextURL } from 'next/dist/server/web/next-url';\n\nexport type PathConfig = {\n [key: string]: string | { [key: string]: string };\n};\n\nexport type ResponseConfig = {\n type: 'next' | 'rewrite' | 'redirect';\n responsePath?: string;\n originalUrl: NextURL;\n userLocale: string;\n clearResetCookie: boolean;\n headerList: Headers;\n localeRouting: boolean;\n localeRoutingEnabledCookieName: string;\n resetLocaleCookieName: string;\n localeHeaderName: string;\n};\n\nconst DYNAMIC_PATH_SEGMENT_PATTERN = '/[^/]+';\nconst PATH_REGEX_SLASHES = /[\\\\/]/g;\n\nfunction escapePathRegexSlashes(pathPattern: string): string {\n return pathPattern.replace(PATH_REGEX_SLASHES, '\\\\$&');\n}\n\nexport function getResponse({\n type,\n originalUrl,\n responsePath = originalUrl.pathname,\n userLocale,\n clearResetCookie,\n headerList,\n localeRouting,\n localeRoutingEnabledCookieName,\n resetLocaleCookieName,\n localeHeaderName,\n}: ResponseConfig): NextResponse<unknown> {\n // Get Response\n let response;\n if (type === 'next') {\n response = NextResponse.next({\n request: {\n headers: headerList,\n },\n });\n } else {\n const responseUrl = new URL(responsePath, originalUrl);\n responseUrl.search = originalUrl.search;\n response =\n type === 'rewrite'\n ? NextResponse.rewrite(responseUrl, {\n request: {\n headers: headerList,\n },\n })\n : NextResponse.redirect(responseUrl);\n }\n\n // Set Headers & Cookies\n response.headers.set(localeHeaderName, userLocale);\n response.cookies.set(\n localeRoutingEnabledCookieName,\n localeRouting.toString()\n );\n // Clear the setLocale reset cookie once it has been processed. The locale\n // cookie must be kept: the client re-reads it on every render, and deleting\n // it here races with concurrent prefetch responses after a locale switch,\n // dropping client components back to the browser's default locale.\n if (clearResetCookie && type !== 'redirect') {\n response.cookies.delete(resetLocaleCookieName);\n }\n return response;\n}\n\n/**\n * Extracts the locale from the given pathname.\n */\nexport function extractLocale(pathname: string): string | null {\n const matches = pathname.match(/^\\/([^/]+)(?:\\/|$)/);\n return matches ? matches[1] : null;\n}\n\n/**\n * Extracts dynamic parameters from a path based on a shared path pattern\n */\nexport function extractDynamicParams(\n templatePath: string,\n path: string\n): string[] {\n if (!templatePath.includes('[')) return [];\n\n const params: string[] = [];\n const pathSegments = path.split('/');\n const sharedSegments = templatePath.split('/');\n\n sharedSegments.forEach((segment, index) => {\n if (segment.startsWith('[') && segment.endsWith(']')) {\n params.push(pathSegments[index]);\n }\n });\n\n return params;\n}\n\n/**\n * Replaces dynamic segments in a path with their actual values\n */\nexport function replaceDynamicSegments(\n path: string,\n templatePath: string\n): string {\n if (!templatePath.includes('[')) return templatePath;\n\n const params = extractDynamicParams(templatePath, path);\n let paramIndex = 0;\n const result = templatePath.replace(/\\[([^\\]]+)\\]/g, (match: string) => {\n return params[paramIndex++] || match;\n });\n return result;\n}\n\n/**\n * Gets the full localized path given a shared path and locale\n */\nexport function getLocalizedPath(\n sharedPath: string,\n locale: string,\n pathConfig: PathConfig\n): string | undefined {\n const localizedPath = pathConfig[sharedPath];\n let path: string | undefined;\n\n if (typeof localizedPath === 'string') {\n path = `/${locale}${localizedPath}`;\n } else if (typeof localizedPath === 'object') {\n path = localizedPath[locale]\n ? `/${locale}${localizedPath[locale]}`\n : `/${locale}${sharedPath}`;\n }\n\n return path;\n}\n\n/**\n * Creates a map of localized paths to shared paths using regex patterns\n */\nexport function createPathToSharedPathMap(\n pathConfig: PathConfig,\n prefixDefaultLocale: boolean,\n defaultLocale: string\n): {\n pathToSharedPath: { [key: string]: string };\n defaultLocalePaths: string[];\n} {\n return Object.entries(pathConfig).reduce<{\n pathToSharedPath: { [key: string]: string };\n defaultLocalePaths: string[];\n }>(\n (acc, [sharedPath, localizedPaths]) => {\n const { pathToSharedPath, defaultLocalePaths } = acc;\n // Add the shared path itself, converting to regex pattern if it has dynamic segments\n if (sharedPath.includes('[')) {\n const pattern = sharedPath.replace(/\\[([^\\]]+)\\]/g, '[^/]+');\n pathToSharedPath[pattern] = sharedPath;\n } else {\n pathToSharedPath[sharedPath] = sharedPath;\n }\n\n if (typeof localizedPaths === 'object') {\n Object.entries(localizedPaths).forEach(([locale, localizedPath]) => {\n // Convert the localized path to a regex pattern\n // Replace [param] with [^/]+ to match any non-slash characters\n const pattern = localizedPath.replace(/\\[([^\\]]+)\\]/g, '[^/]+');\n pathToSharedPath[`/${locale}${pattern}`] = sharedPath;\n if (!prefixDefaultLocale && locale === defaultLocale) {\n pathToSharedPath[pattern] = sharedPath;\n defaultLocalePaths.push(pattern);\n }\n });\n }\n return acc;\n },\n { pathToSharedPath: {}, defaultLocalePaths: [] }\n );\n}\n\n/**\n * Gets the shared path from a given pathname, handling both static and dynamic paths\n */\nexport function getSharedPath(\n standardizedPathname: string,\n pathToSharedPath: { [key: string]: string },\n pathnameLocale: string | undefined\n): string | undefined {\n // Try exact match first\n if (pathToSharedPath[standardizedPathname]) {\n return pathToSharedPath[standardizedPathname];\n }\n\n // Without locale prefix\n let pathnameWithoutLocale = undefined;\n // Only remove locale prefix if the locale prefix is valid\n if (pathnameLocale) {\n pathnameWithoutLocale = standardizedPathname.replace(/^\\/[^/]+/, '');\n if (pathToSharedPath[pathnameWithoutLocale]) {\n return pathToSharedPath[pathnameWithoutLocale];\n }\n }\n\n // Try regex pattern match\n let candidateSharedPath = undefined;\n for (const [pattern, sharedPath] of Object.entries(pathToSharedPath)) {\n if (pattern.includes(DYNAMIC_PATH_SEGMENT_PATTERN)) {\n // Convert the pattern to a strict regex that matches the exact path structure\n const regex = new RegExp(`^${escapePathRegexSlashes(pattern)}$`);\n // Exact match\n if (regex.test(standardizedPathname)) {\n return sharedPath;\n }\n // Without locale prefix\n if (\n !candidateSharedPath &&\n pathnameLocale &&\n regex.test(pathnameWithoutLocale as string)\n ) {\n candidateSharedPath = sharedPath;\n }\n }\n }\n return candidateSharedPath;\n}\n\n/**\n * Checks if the pathname is in the default locale paths\n * @param pathname - The pathname to check\n * @param defaultLocalePaths - The default locale paths\n * @returns true if the pathname is in the default locale paths, false otherwise\n */\n\nfunction inDefaultLocalePaths(\n pathname: string,\n defaultLocalePaths: string[]\n): boolean {\n // Try exact match first\n if (defaultLocalePaths.includes(pathname)) {\n return true;\n }\n\n // Try regex pattern match\n for (const path of defaultLocalePaths) {\n if (path.includes(DYNAMIC_PATH_SEGMENT_PATTERN)) {\n const regex = new RegExp(`^${escapePathRegexSlashes(path)}$`);\n if (regex.test(pathname)) {\n return true;\n }\n }\n }\n return false;\n}\n\n/**\n * Gets the locale from the request using various sources\n */\nexport function getLocaleFromRequest(\n req: NextRequest,\n defaultLocale: string,\n approvedLocales: string[],\n localeRouting: boolean,\n gtServicesEnabled: boolean,\n prefixDefaultLocale: boolean,\n defaultLocalePaths: string[],\n referrerLocaleCookieName: string,\n localeCookieName: string,\n resetLocaleCookieName: string,\n gt: GTRuntime\n): {\n userLocale: string;\n pathnameLocale: string | undefined;\n unstandardizedPathnameLocale: string | null | undefined;\n clearResetCookie: boolean;\n} {\n const headerList = new Headers(req.headers);\n const candidates: string[] = [];\n let clearResetCookie = false;\n const { pathname } = req.nextUrl;\n\n // Check pathname locales\n let pathnameLocale, unstandardizedPathnameLocale;\n if (localeRouting) {\n unstandardizedPathnameLocale = extractLocale(pathname);\n const extractedLocale = gtServicesEnabled\n ? standardizeLocale(unstandardizedPathnameLocale || '')\n : unstandardizedPathnameLocale;\n\n if (\n extractedLocale &&\n gt.isValidLocale(extractedLocale) &&\n gt.determineLocale([extractedLocale], approvedLocales)\n ) {\n const determinedLocale = gt.determineLocale(\n [extractedLocale],\n approvedLocales\n );\n if (determinedLocale) {\n pathnameLocale = gt.resolveAliasLocale(determinedLocale);\n candidates.push(pathnameLocale);\n }\n }\n }\n\n // Check pathname for a customized unprefixed default locale path (e.g. /en-about , /en-dashboard/1/en-custom)\n if (\n localeRouting &&\n !prefixDefaultLocale &&\n !pathnameLocale &&\n inDefaultLocalePaths(pathname, defaultLocalePaths)\n ) {\n candidates.push(defaultLocale); // will override other candidates\n }\n\n // Check cookie locale\n const cookieLocale = req.cookies.get(localeCookieName);\n if (cookieLocale?.value && gt.isValidLocale(cookieLocale?.value)) {\n const resetCookie = req.cookies.get(resetLocaleCookieName);\n if (resetCookie?.value) {\n // Add this back in when we support custom getLocale\n // addedCustomLocale\n // ? candidates.splice(1, 0, cookieLocale.value)\n // : candidates.unshift(cookieLocale.value);\n candidates.unshift(cookieLocale.value);\n clearResetCookie = true;\n } else {\n candidates.push(cookieLocale.value);\n }\n }\n\n // Check referrer locale\n const referrerLocaleCookie = req.cookies.get(referrerLocaleCookieName);\n if (\n referrerLocaleCookie?.value &&\n gt.isValidLocale(referrerLocaleCookie.value) &&\n !clearResetCookie\n ) {\n const referrerLocale = referrerLocaleCookie.value;\n if (gt.determineLocale([referrerLocale], approvedLocales)) {\n candidates.push(referrerLocale);\n }\n }\n\n // Get locales from accept-language header\n if (process.env._GENERALTRANSLATION_IGNORE_BROWSER_LOCALES === 'false') {\n const acceptedLocales =\n headerList\n .get('accept-language')\n ?.split(',')\n .map((item) => item.split(';')?.[0].trim()) || [];\n if (acceptedLocales) candidates.push(...acceptedLocales);\n }\n\n // Get default locale\n candidates.push(defaultLocale);\n\n // determine userLocale\n const unstandardizedUserLocale =\n gt.determineLocale(\n candidates.filter((locale) => gt.isValidLocale(locale)),\n approvedLocales\n ) || defaultLocale;\n const userLocale = gtServicesEnabled\n ? standardizeLocale(unstandardizedUserLocale)\n : unstandardizedUserLocale;\n\n return {\n userLocale,\n pathnameLocale,\n unstandardizedPathnameLocale,\n clearResetCookie,\n };\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"utils.js","names":["NextResponse"],"sources":["../../src/middleware-dir/utils.ts"],"sourcesContent":["import { NextRequest, NextResponse } from 'next/server';\nimport { standardizeLocale } from '@generaltranslation/format';\nimport { GTRuntime } from 'generaltranslation/runtime';\nimport { NextURL } from 'next/dist/server/web/next-url';\nimport { parseAcceptLanguage } from 'gt-i18n/internal';\n\nexport type PathConfig = {\n [key: string]: string | { [key: string]: string };\n};\n\nexport type ResponseConfig = {\n type: 'next' | 'rewrite' | 'redirect';\n responsePath?: string;\n originalUrl: NextURL;\n userLocale: string;\n clearResetCookie: boolean;\n headerList: Headers;\n localeRouting: boolean;\n localeRoutingEnabledCookieName: string;\n resetLocaleCookieName: string;\n localeHeaderName: string;\n};\n\nconst DYNAMIC_PATH_SEGMENT_PATTERN = '/[^/]+';\nconst PATH_REGEX_SLASHES = /[\\\\/]/g;\n\nfunction escapePathRegexSlashes(pathPattern: string): string {\n return pathPattern.replace(PATH_REGEX_SLASHES, '\\\\$&');\n}\n\nexport function getResponse({\n type,\n originalUrl,\n responsePath = originalUrl.pathname,\n userLocale,\n clearResetCookie,\n headerList,\n localeRouting,\n localeRoutingEnabledCookieName,\n resetLocaleCookieName,\n localeHeaderName,\n}: ResponseConfig): NextResponse<unknown> {\n // Get Response\n let response;\n if (type === 'next') {\n response = NextResponse.next({\n request: {\n headers: headerList,\n },\n });\n } else {\n const responseUrl = new URL(responsePath, originalUrl);\n responseUrl.search = originalUrl.search;\n response =\n type === 'rewrite'\n ? NextResponse.rewrite(responseUrl, {\n request: {\n headers: headerList,\n },\n })\n : NextResponse.redirect(responseUrl);\n }\n\n // Set Headers & Cookies\n response.headers.set(localeHeaderName, userLocale);\n response.cookies.set(\n localeRoutingEnabledCookieName,\n localeRouting.toString()\n );\n // Clear the setLocale reset cookie once it has been processed. The locale\n // cookie must be kept: the client re-reads it on every render, and deleting\n // it here races with concurrent prefetch responses after a locale switch,\n // dropping client components back to the browser's default locale.\n if (clearResetCookie && type !== 'redirect') {\n response.cookies.delete(resetLocaleCookieName);\n }\n return response;\n}\n\n/**\n * Extracts the locale from the given pathname.\n */\nexport function extractLocale(pathname: string): string | null {\n const matches = pathname.match(/^\\/([^/]+)(?:\\/|$)/);\n return matches ? matches[1] : null;\n}\n\n/**\n * Extracts dynamic parameters from a path based on a shared path pattern\n */\nexport function extractDynamicParams(\n templatePath: string,\n path: string\n): string[] {\n if (!templatePath.includes('[')) return [];\n\n const params: string[] = [];\n const pathSegments = path.split('/');\n const sharedSegments = templatePath.split('/');\n\n sharedSegments.forEach((segment, index) => {\n if (segment.startsWith('[') && segment.endsWith(']')) {\n params.push(pathSegments[index]);\n }\n });\n\n return params;\n}\n\n/**\n * Replaces dynamic segments in a path with their actual values\n */\nexport function replaceDynamicSegments(\n path: string,\n templatePath: string\n): string {\n if (!templatePath.includes('[')) return templatePath;\n\n const params = extractDynamicParams(templatePath, path);\n let paramIndex = 0;\n const result = templatePath.replace(/\\[([^\\]]+)\\]/g, (match: string) => {\n return params[paramIndex++] || match;\n });\n return result;\n}\n\n/**\n * Gets the full localized path given a shared path and locale\n */\nexport function getLocalizedPath(\n sharedPath: string,\n locale: string,\n pathConfig: PathConfig\n): string | undefined {\n const localizedPath = pathConfig[sharedPath];\n let path: string | undefined;\n\n if (typeof localizedPath === 'string') {\n path = `/${locale}${localizedPath}`;\n } else if (typeof localizedPath === 'object') {\n path = localizedPath[locale]\n ? `/${locale}${localizedPath[locale]}`\n : `/${locale}${sharedPath}`;\n }\n\n return path;\n}\n\n/**\n * Creates a map of localized paths to shared paths using regex patterns\n */\nexport function createPathToSharedPathMap(\n pathConfig: PathConfig,\n prefixDefaultLocale: boolean,\n defaultLocale: string\n): {\n pathToSharedPath: { [key: string]: string };\n defaultLocalePaths: string[];\n} {\n return Object.entries(pathConfig).reduce<{\n pathToSharedPath: { [key: string]: string };\n defaultLocalePaths: string[];\n }>(\n (acc, [sharedPath, localizedPaths]) => {\n const { pathToSharedPath, defaultLocalePaths } = acc;\n // Add the shared path itself, converting to regex pattern if it has dynamic segments\n if (sharedPath.includes('[')) {\n const pattern = sharedPath.replace(/\\[([^\\]]+)\\]/g, '[^/]+');\n pathToSharedPath[pattern] = sharedPath;\n } else {\n pathToSharedPath[sharedPath] = sharedPath;\n }\n\n if (typeof localizedPaths === 'object') {\n Object.entries(localizedPaths).forEach(([locale, localizedPath]) => {\n // Convert the localized path to a regex pattern\n // Replace [param] with [^/]+ to match any non-slash characters\n const pattern = localizedPath.replace(/\\[([^\\]]+)\\]/g, '[^/]+');\n pathToSharedPath[`/${locale}${pattern}`] = sharedPath;\n if (!prefixDefaultLocale && locale === defaultLocale) {\n pathToSharedPath[pattern] = sharedPath;\n defaultLocalePaths.push(pattern);\n }\n });\n }\n return acc;\n },\n { pathToSharedPath: {}, defaultLocalePaths: [] }\n );\n}\n\n/**\n * Gets the shared path from a given pathname, handling both static and dynamic paths\n */\nexport function getSharedPath(\n standardizedPathname: string,\n pathToSharedPath: { [key: string]: string },\n pathnameLocale: string | undefined\n): string | undefined {\n // Try exact match first\n if (pathToSharedPath[standardizedPathname]) {\n return pathToSharedPath[standardizedPathname];\n }\n\n // Without locale prefix\n let pathnameWithoutLocale = undefined;\n // Only remove locale prefix if the locale prefix is valid\n if (pathnameLocale) {\n pathnameWithoutLocale = standardizedPathname.replace(/^\\/[^/]+/, '');\n if (pathToSharedPath[pathnameWithoutLocale]) {\n return pathToSharedPath[pathnameWithoutLocale];\n }\n }\n\n // Try regex pattern match\n let candidateSharedPath = undefined;\n for (const [pattern, sharedPath] of Object.entries(pathToSharedPath)) {\n if (pattern.includes(DYNAMIC_PATH_SEGMENT_PATTERN)) {\n // Convert the pattern to a strict regex that matches the exact path structure\n const regex = new RegExp(`^${escapePathRegexSlashes(pattern)}$`);\n // Exact match\n if (regex.test(standardizedPathname)) {\n return sharedPath;\n }\n // Without locale prefix\n if (\n !candidateSharedPath &&\n pathnameLocale &&\n regex.test(pathnameWithoutLocale as string)\n ) {\n candidateSharedPath = sharedPath;\n }\n }\n }\n return candidateSharedPath;\n}\n\n/**\n * Checks if the pathname is in the default locale paths\n * @param pathname - The pathname to check\n * @param defaultLocalePaths - The default locale paths\n * @returns true if the pathname is in the default locale paths, false otherwise\n */\n\nfunction inDefaultLocalePaths(\n pathname: string,\n defaultLocalePaths: string[]\n): boolean {\n // Try exact match first\n if (defaultLocalePaths.includes(pathname)) {\n return true;\n }\n\n // Try regex pattern match\n for (const path of defaultLocalePaths) {\n if (path.includes(DYNAMIC_PATH_SEGMENT_PATTERN)) {\n const regex = new RegExp(`^${escapePathRegexSlashes(path)}$`);\n if (regex.test(pathname)) {\n return true;\n }\n }\n }\n return false;\n}\n\n/**\n * Gets the locale from the request using various sources\n */\nexport function getLocaleFromRequest(\n req: NextRequest,\n defaultLocale: string,\n approvedLocales: string[],\n localeRouting: boolean,\n gtServicesEnabled: boolean,\n prefixDefaultLocale: boolean,\n defaultLocalePaths: string[],\n referrerLocaleCookieName: string,\n localeCookieName: string,\n resetLocaleCookieName: string,\n gt: GTRuntime\n): {\n userLocale: string;\n pathnameLocale: string | undefined;\n unstandardizedPathnameLocale: string | null | undefined;\n clearResetCookie: boolean;\n} {\n const headerList = new Headers(req.headers);\n const candidates: string[] = [];\n let clearResetCookie = false;\n const { pathname } = req.nextUrl;\n\n // Check pathname locales\n let pathnameLocale, unstandardizedPathnameLocale;\n if (localeRouting) {\n unstandardizedPathnameLocale = extractLocale(pathname);\n const extractedLocale = gtServicesEnabled\n ? standardizeLocale(unstandardizedPathnameLocale || '')\n : unstandardizedPathnameLocale;\n\n if (\n extractedLocale &&\n gt.isValidLocale(extractedLocale) &&\n gt.determineLocale([extractedLocale], approvedLocales)\n ) {\n const determinedLocale = gt.determineLocale(\n [extractedLocale],\n approvedLocales\n );\n if (determinedLocale) {\n pathnameLocale = gt.resolveAliasLocale(determinedLocale);\n candidates.push(pathnameLocale);\n }\n }\n }\n\n // Check pathname for a customized unprefixed default locale path (e.g. /en-about , /en-dashboard/1/en-custom)\n if (\n localeRouting &&\n !prefixDefaultLocale &&\n !pathnameLocale &&\n inDefaultLocalePaths(pathname, defaultLocalePaths)\n ) {\n candidates.push(defaultLocale); // will override other candidates\n }\n\n // Check cookie locale\n const cookieLocale = req.cookies.get(localeCookieName);\n if (cookieLocale?.value && gt.isValidLocale(cookieLocale?.value)) {\n const resetCookie = req.cookies.get(resetLocaleCookieName);\n if (resetCookie?.value) {\n // Add this back in when we support custom getLocale\n // addedCustomLocale\n // ? candidates.splice(1, 0, cookieLocale.value)\n // : candidates.unshift(cookieLocale.value);\n candidates.unshift(cookieLocale.value);\n clearResetCookie = true;\n } else {\n candidates.push(cookieLocale.value);\n }\n }\n\n // Check referrer locale\n const referrerLocaleCookie = req.cookies.get(referrerLocaleCookieName);\n if (\n referrerLocaleCookie?.value &&\n gt.isValidLocale(referrerLocaleCookie.value) &&\n !clearResetCookie\n ) {\n const referrerLocale = referrerLocaleCookie.value;\n if (gt.determineLocale([referrerLocale], approvedLocales)) {\n candidates.push(referrerLocale);\n }\n }\n\n // Get locales from accept-language header\n if (process.env._GENERALTRANSLATION_IGNORE_BROWSER_LOCALES === 'false') {\n candidates.push(...parseAcceptLanguage(headerList.get('accept-language')));\n }\n\n // Get default locale\n candidates.push(defaultLocale);\n\n // determine userLocale\n const unstandardizedUserLocale =\n gt.determineLocale(\n candidates.filter((locale) => gt.isValidLocale(locale)),\n approvedLocales\n ) || defaultLocale;\n const userLocale = gtServicesEnabled\n ? standardizeLocale(unstandardizedUserLocale)\n : unstandardizedUserLocale;\n\n return {\n userLocale,\n pathnameLocale,\n unstandardizedPathnameLocale,\n clearResetCookie,\n };\n}\n"],"mappings":"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"}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { standardizeLocale } from "@generaltranslation/format";
|
|
2
|
+
import { parseAcceptLanguage } from "gt-i18n/internal";
|
|
2
3
|
import { NextResponse } from "next/server.js";
|
|
3
4
|
//#region src/middleware-dir/utils.ts
|
|
4
5
|
const DYNAMIC_PATH_SEGMENT_PATTERN = "/[^/]+";
|
|
@@ -145,10 +146,7 @@ function getLocaleFromRequest(req, defaultLocale, approvedLocales, localeRouting
|
|
|
145
146
|
const referrerLocale = referrerLocaleCookie.value;
|
|
146
147
|
if (gt.determineLocale([referrerLocale], approvedLocales)) candidates.push(referrerLocale);
|
|
147
148
|
}
|
|
148
|
-
if (process.env._GENERALTRANSLATION_IGNORE_BROWSER_LOCALES === "false")
|
|
149
|
-
const acceptedLocales = headerList.get("accept-language")?.split(",").map((item) => item.split(";")?.[0].trim()) || [];
|
|
150
|
-
if (acceptedLocales) candidates.push(...acceptedLocales);
|
|
151
|
-
}
|
|
149
|
+
if (process.env._GENERALTRANSLATION_IGNORE_BROWSER_LOCALES === "false") candidates.push(...parseAcceptLanguage(headerList.get("accept-language")));
|
|
152
150
|
candidates.push(defaultLocale);
|
|
153
151
|
const unstandardizedUserLocale = gt.determineLocale(candidates.filter((locale) => gt.isValidLocale(locale)), approvedLocales) || defaultLocale;
|
|
154
152
|
return {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"utils.mjs","names":[],"sources":["../../src/middleware-dir/utils.ts"],"sourcesContent":["import { NextRequest, NextResponse } from 'next/server';\nimport { standardizeLocale } from '@generaltranslation/format';\nimport { GTRuntime } from 'generaltranslation/runtime';\nimport { NextURL } from 'next/dist/server/web/next-url';\n\nexport type PathConfig = {\n [key: string]: string | { [key: string]: string };\n};\n\nexport type ResponseConfig = {\n type: 'next' | 'rewrite' | 'redirect';\n responsePath?: string;\n originalUrl: NextURL;\n userLocale: string;\n clearResetCookie: boolean;\n headerList: Headers;\n localeRouting: boolean;\n localeRoutingEnabledCookieName: string;\n resetLocaleCookieName: string;\n localeHeaderName: string;\n};\n\nconst DYNAMIC_PATH_SEGMENT_PATTERN = '/[^/]+';\nconst PATH_REGEX_SLASHES = /[\\\\/]/g;\n\nfunction escapePathRegexSlashes(pathPattern: string): string {\n return pathPattern.replace(PATH_REGEX_SLASHES, '\\\\$&');\n}\n\nexport function getResponse({\n type,\n originalUrl,\n responsePath = originalUrl.pathname,\n userLocale,\n clearResetCookie,\n headerList,\n localeRouting,\n localeRoutingEnabledCookieName,\n resetLocaleCookieName,\n localeHeaderName,\n}: ResponseConfig): NextResponse<unknown> {\n // Get Response\n let response;\n if (type === 'next') {\n response = NextResponse.next({\n request: {\n headers: headerList,\n },\n });\n } else {\n const responseUrl = new URL(responsePath, originalUrl);\n responseUrl.search = originalUrl.search;\n response =\n type === 'rewrite'\n ? NextResponse.rewrite(responseUrl, {\n request: {\n headers: headerList,\n },\n })\n : NextResponse.redirect(responseUrl);\n }\n\n // Set Headers & Cookies\n response.headers.set(localeHeaderName, userLocale);\n response.cookies.set(\n localeRoutingEnabledCookieName,\n localeRouting.toString()\n );\n // Clear the setLocale reset cookie once it has been processed. The locale\n // cookie must be kept: the client re-reads it on every render, and deleting\n // it here races with concurrent prefetch responses after a locale switch,\n // dropping client components back to the browser's default locale.\n if (clearResetCookie && type !== 'redirect') {\n response.cookies.delete(resetLocaleCookieName);\n }\n return response;\n}\n\n/**\n * Extracts the locale from the given pathname.\n */\nexport function extractLocale(pathname: string): string | null {\n const matches = pathname.match(/^\\/([^/]+)(?:\\/|$)/);\n return matches ? matches[1] : null;\n}\n\n/**\n * Extracts dynamic parameters from a path based on a shared path pattern\n */\nexport function extractDynamicParams(\n templatePath: string,\n path: string\n): string[] {\n if (!templatePath.includes('[')) return [];\n\n const params: string[] = [];\n const pathSegments = path.split('/');\n const sharedSegments = templatePath.split('/');\n\n sharedSegments.forEach((segment, index) => {\n if (segment.startsWith('[') && segment.endsWith(']')) {\n params.push(pathSegments[index]);\n }\n });\n\n return params;\n}\n\n/**\n * Replaces dynamic segments in a path with their actual values\n */\nexport function replaceDynamicSegments(\n path: string,\n templatePath: string\n): string {\n if (!templatePath.includes('[')) return templatePath;\n\n const params = extractDynamicParams(templatePath, path);\n let paramIndex = 0;\n const result = templatePath.replace(/\\[([^\\]]+)\\]/g, (match: string) => {\n return params[paramIndex++] || match;\n });\n return result;\n}\n\n/**\n * Gets the full localized path given a shared path and locale\n */\nexport function getLocalizedPath(\n sharedPath: string,\n locale: string,\n pathConfig: PathConfig\n): string | undefined {\n const localizedPath = pathConfig[sharedPath];\n let path: string | undefined;\n\n if (typeof localizedPath === 'string') {\n path = `/${locale}${localizedPath}`;\n } else if (typeof localizedPath === 'object') {\n path = localizedPath[locale]\n ? `/${locale}${localizedPath[locale]}`\n : `/${locale}${sharedPath}`;\n }\n\n return path;\n}\n\n/**\n * Creates a map of localized paths to shared paths using regex patterns\n */\nexport function createPathToSharedPathMap(\n pathConfig: PathConfig,\n prefixDefaultLocale: boolean,\n defaultLocale: string\n): {\n pathToSharedPath: { [key: string]: string };\n defaultLocalePaths: string[];\n} {\n return Object.entries(pathConfig).reduce<{\n pathToSharedPath: { [key: string]: string };\n defaultLocalePaths: string[];\n }>(\n (acc, [sharedPath, localizedPaths]) => {\n const { pathToSharedPath, defaultLocalePaths } = acc;\n // Add the shared path itself, converting to regex pattern if it has dynamic segments\n if (sharedPath.includes('[')) {\n const pattern = sharedPath.replace(/\\[([^\\]]+)\\]/g, '[^/]+');\n pathToSharedPath[pattern] = sharedPath;\n } else {\n pathToSharedPath[sharedPath] = sharedPath;\n }\n\n if (typeof localizedPaths === 'object') {\n Object.entries(localizedPaths).forEach(([locale, localizedPath]) => {\n // Convert the localized path to a regex pattern\n // Replace [param] with [^/]+ to match any non-slash characters\n const pattern = localizedPath.replace(/\\[([^\\]]+)\\]/g, '[^/]+');\n pathToSharedPath[`/${locale}${pattern}`] = sharedPath;\n if (!prefixDefaultLocale && locale === defaultLocale) {\n pathToSharedPath[pattern] = sharedPath;\n defaultLocalePaths.push(pattern);\n }\n });\n }\n return acc;\n },\n { pathToSharedPath: {}, defaultLocalePaths: [] }\n );\n}\n\n/**\n * Gets the shared path from a given pathname, handling both static and dynamic paths\n */\nexport function getSharedPath(\n standardizedPathname: string,\n pathToSharedPath: { [key: string]: string },\n pathnameLocale: string | undefined\n): string | undefined {\n // Try exact match first\n if (pathToSharedPath[standardizedPathname]) {\n return pathToSharedPath[standardizedPathname];\n }\n\n // Without locale prefix\n let pathnameWithoutLocale = undefined;\n // Only remove locale prefix if the locale prefix is valid\n if (pathnameLocale) {\n pathnameWithoutLocale = standardizedPathname.replace(/^\\/[^/]+/, '');\n if (pathToSharedPath[pathnameWithoutLocale]) {\n return pathToSharedPath[pathnameWithoutLocale];\n }\n }\n\n // Try regex pattern match\n let candidateSharedPath = undefined;\n for (const [pattern, sharedPath] of Object.entries(pathToSharedPath)) {\n if (pattern.includes(DYNAMIC_PATH_SEGMENT_PATTERN)) {\n // Convert the pattern to a strict regex that matches the exact path structure\n const regex = new RegExp(`^${escapePathRegexSlashes(pattern)}$`);\n // Exact match\n if (regex.test(standardizedPathname)) {\n return sharedPath;\n }\n // Without locale prefix\n if (\n !candidateSharedPath &&\n pathnameLocale &&\n regex.test(pathnameWithoutLocale as string)\n ) {\n candidateSharedPath = sharedPath;\n }\n }\n }\n return candidateSharedPath;\n}\n\n/**\n * Checks if the pathname is in the default locale paths\n * @param pathname - The pathname to check\n * @param defaultLocalePaths - The default locale paths\n * @returns true if the pathname is in the default locale paths, false otherwise\n */\n\nfunction inDefaultLocalePaths(\n pathname: string,\n defaultLocalePaths: string[]\n): boolean {\n // Try exact match first\n if (defaultLocalePaths.includes(pathname)) {\n return true;\n }\n\n // Try regex pattern match\n for (const path of defaultLocalePaths) {\n if (path.includes(DYNAMIC_PATH_SEGMENT_PATTERN)) {\n const regex = new RegExp(`^${escapePathRegexSlashes(path)}$`);\n if (regex.test(pathname)) {\n return true;\n }\n }\n }\n return false;\n}\n\n/**\n * Gets the locale from the request using various sources\n */\nexport function getLocaleFromRequest(\n req: NextRequest,\n defaultLocale: string,\n approvedLocales: string[],\n localeRouting: boolean,\n gtServicesEnabled: boolean,\n prefixDefaultLocale: boolean,\n defaultLocalePaths: string[],\n referrerLocaleCookieName: string,\n localeCookieName: string,\n resetLocaleCookieName: string,\n gt: GTRuntime\n): {\n userLocale: string;\n pathnameLocale: string | undefined;\n unstandardizedPathnameLocale: string | null | undefined;\n clearResetCookie: boolean;\n} {\n const headerList = new Headers(req.headers);\n const candidates: string[] = [];\n let clearResetCookie = false;\n const { pathname } = req.nextUrl;\n\n // Check pathname locales\n let pathnameLocale, unstandardizedPathnameLocale;\n if (localeRouting) {\n unstandardizedPathnameLocale = extractLocale(pathname);\n const extractedLocale = gtServicesEnabled\n ? standardizeLocale(unstandardizedPathnameLocale || '')\n : unstandardizedPathnameLocale;\n\n if (\n extractedLocale &&\n gt.isValidLocale(extractedLocale) &&\n gt.determineLocale([extractedLocale], approvedLocales)\n ) {\n const determinedLocale = gt.determineLocale(\n [extractedLocale],\n approvedLocales\n );\n if (determinedLocale) {\n pathnameLocale = gt.resolveAliasLocale(determinedLocale);\n candidates.push(pathnameLocale);\n }\n }\n }\n\n // Check pathname for a customized unprefixed default locale path (e.g. /en-about , /en-dashboard/1/en-custom)\n if (\n localeRouting &&\n !prefixDefaultLocale &&\n !pathnameLocale &&\n inDefaultLocalePaths(pathname, defaultLocalePaths)\n ) {\n candidates.push(defaultLocale); // will override other candidates\n }\n\n // Check cookie locale\n const cookieLocale = req.cookies.get(localeCookieName);\n if (cookieLocale?.value && gt.isValidLocale(cookieLocale?.value)) {\n const resetCookie = req.cookies.get(resetLocaleCookieName);\n if (resetCookie?.value) {\n // Add this back in when we support custom getLocale\n // addedCustomLocale\n // ? candidates.splice(1, 0, cookieLocale.value)\n // : candidates.unshift(cookieLocale.value);\n candidates.unshift(cookieLocale.value);\n clearResetCookie = true;\n } else {\n candidates.push(cookieLocale.value);\n }\n }\n\n // Check referrer locale\n const referrerLocaleCookie = req.cookies.get(referrerLocaleCookieName);\n if (\n referrerLocaleCookie?.value &&\n gt.isValidLocale(referrerLocaleCookie.value) &&\n !clearResetCookie\n ) {\n const referrerLocale = referrerLocaleCookie.value;\n if (gt.determineLocale([referrerLocale], approvedLocales)) {\n candidates.push(referrerLocale);\n }\n }\n\n // Get locales from accept-language header\n if (process.env._GENERALTRANSLATION_IGNORE_BROWSER_LOCALES === 'false') {\n const acceptedLocales =\n headerList\n .get('accept-language')\n ?.split(',')\n .map((item) => item.split(';')?.[0].trim()) || [];\n if (acceptedLocales) candidates.push(...acceptedLocales);\n }\n\n // Get default locale\n candidates.push(defaultLocale);\n\n // determine userLocale\n const unstandardizedUserLocale =\n gt.determineLocale(\n candidates.filter((locale) => gt.isValidLocale(locale)),\n approvedLocales\n ) || defaultLocale;\n const userLocale = gtServicesEnabled\n ? standardizeLocale(unstandardizedUserLocale)\n : unstandardizedUserLocale;\n\n return {\n userLocale,\n pathnameLocale,\n unstandardizedPathnameLocale,\n clearResetCookie,\n };\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"utils.mjs","names":[],"sources":["../../src/middleware-dir/utils.ts"],"sourcesContent":["import { NextRequest, NextResponse } from 'next/server';\nimport { standardizeLocale } from '@generaltranslation/format';\nimport { GTRuntime } from 'generaltranslation/runtime';\nimport { NextURL } from 'next/dist/server/web/next-url';\nimport { parseAcceptLanguage } from 'gt-i18n/internal';\n\nexport type PathConfig = {\n [key: string]: string | { [key: string]: string };\n};\n\nexport type ResponseConfig = {\n type: 'next' | 'rewrite' | 'redirect';\n responsePath?: string;\n originalUrl: NextURL;\n userLocale: string;\n clearResetCookie: boolean;\n headerList: Headers;\n localeRouting: boolean;\n localeRoutingEnabledCookieName: string;\n resetLocaleCookieName: string;\n localeHeaderName: string;\n};\n\nconst DYNAMIC_PATH_SEGMENT_PATTERN = '/[^/]+';\nconst PATH_REGEX_SLASHES = /[\\\\/]/g;\n\nfunction escapePathRegexSlashes(pathPattern: string): string {\n return pathPattern.replace(PATH_REGEX_SLASHES, '\\\\$&');\n}\n\nexport function getResponse({\n type,\n originalUrl,\n responsePath = originalUrl.pathname,\n userLocale,\n clearResetCookie,\n headerList,\n localeRouting,\n localeRoutingEnabledCookieName,\n resetLocaleCookieName,\n localeHeaderName,\n}: ResponseConfig): NextResponse<unknown> {\n // Get Response\n let response;\n if (type === 'next') {\n response = NextResponse.next({\n request: {\n headers: headerList,\n },\n });\n } else {\n const responseUrl = new URL(responsePath, originalUrl);\n responseUrl.search = originalUrl.search;\n response =\n type === 'rewrite'\n ? NextResponse.rewrite(responseUrl, {\n request: {\n headers: headerList,\n },\n })\n : NextResponse.redirect(responseUrl);\n }\n\n // Set Headers & Cookies\n response.headers.set(localeHeaderName, userLocale);\n response.cookies.set(\n localeRoutingEnabledCookieName,\n localeRouting.toString()\n );\n // Clear the setLocale reset cookie once it has been processed. The locale\n // cookie must be kept: the client re-reads it on every render, and deleting\n // it here races with concurrent prefetch responses after a locale switch,\n // dropping client components back to the browser's default locale.\n if (clearResetCookie && type !== 'redirect') {\n response.cookies.delete(resetLocaleCookieName);\n }\n return response;\n}\n\n/**\n * Extracts the locale from the given pathname.\n */\nexport function extractLocale(pathname: string): string | null {\n const matches = pathname.match(/^\\/([^/]+)(?:\\/|$)/);\n return matches ? matches[1] : null;\n}\n\n/**\n * Extracts dynamic parameters from a path based on a shared path pattern\n */\nexport function extractDynamicParams(\n templatePath: string,\n path: string\n): string[] {\n if (!templatePath.includes('[')) return [];\n\n const params: string[] = [];\n const pathSegments = path.split('/');\n const sharedSegments = templatePath.split('/');\n\n sharedSegments.forEach((segment, index) => {\n if (segment.startsWith('[') && segment.endsWith(']')) {\n params.push(pathSegments[index]);\n }\n });\n\n return params;\n}\n\n/**\n * Replaces dynamic segments in a path with their actual values\n */\nexport function replaceDynamicSegments(\n path: string,\n templatePath: string\n): string {\n if (!templatePath.includes('[')) return templatePath;\n\n const params = extractDynamicParams(templatePath, path);\n let paramIndex = 0;\n const result = templatePath.replace(/\\[([^\\]]+)\\]/g, (match: string) => {\n return params[paramIndex++] || match;\n });\n return result;\n}\n\n/**\n * Gets the full localized path given a shared path and locale\n */\nexport function getLocalizedPath(\n sharedPath: string,\n locale: string,\n pathConfig: PathConfig\n): string | undefined {\n const localizedPath = pathConfig[sharedPath];\n let path: string | undefined;\n\n if (typeof localizedPath === 'string') {\n path = `/${locale}${localizedPath}`;\n } else if (typeof localizedPath === 'object') {\n path = localizedPath[locale]\n ? `/${locale}${localizedPath[locale]}`\n : `/${locale}${sharedPath}`;\n }\n\n return path;\n}\n\n/**\n * Creates a map of localized paths to shared paths using regex patterns\n */\nexport function createPathToSharedPathMap(\n pathConfig: PathConfig,\n prefixDefaultLocale: boolean,\n defaultLocale: string\n): {\n pathToSharedPath: { [key: string]: string };\n defaultLocalePaths: string[];\n} {\n return Object.entries(pathConfig).reduce<{\n pathToSharedPath: { [key: string]: string };\n defaultLocalePaths: string[];\n }>(\n (acc, [sharedPath, localizedPaths]) => {\n const { pathToSharedPath, defaultLocalePaths } = acc;\n // Add the shared path itself, converting to regex pattern if it has dynamic segments\n if (sharedPath.includes('[')) {\n const pattern = sharedPath.replace(/\\[([^\\]]+)\\]/g, '[^/]+');\n pathToSharedPath[pattern] = sharedPath;\n } else {\n pathToSharedPath[sharedPath] = sharedPath;\n }\n\n if (typeof localizedPaths === 'object') {\n Object.entries(localizedPaths).forEach(([locale, localizedPath]) => {\n // Convert the localized path to a regex pattern\n // Replace [param] with [^/]+ to match any non-slash characters\n const pattern = localizedPath.replace(/\\[([^\\]]+)\\]/g, '[^/]+');\n pathToSharedPath[`/${locale}${pattern}`] = sharedPath;\n if (!prefixDefaultLocale && locale === defaultLocale) {\n pathToSharedPath[pattern] = sharedPath;\n defaultLocalePaths.push(pattern);\n }\n });\n }\n return acc;\n },\n { pathToSharedPath: {}, defaultLocalePaths: [] }\n );\n}\n\n/**\n * Gets the shared path from a given pathname, handling both static and dynamic paths\n */\nexport function getSharedPath(\n standardizedPathname: string,\n pathToSharedPath: { [key: string]: string },\n pathnameLocale: string | undefined\n): string | undefined {\n // Try exact match first\n if (pathToSharedPath[standardizedPathname]) {\n return pathToSharedPath[standardizedPathname];\n }\n\n // Without locale prefix\n let pathnameWithoutLocale = undefined;\n // Only remove locale prefix if the locale prefix is valid\n if (pathnameLocale) {\n pathnameWithoutLocale = standardizedPathname.replace(/^\\/[^/]+/, '');\n if (pathToSharedPath[pathnameWithoutLocale]) {\n return pathToSharedPath[pathnameWithoutLocale];\n }\n }\n\n // Try regex pattern match\n let candidateSharedPath = undefined;\n for (const [pattern, sharedPath] of Object.entries(pathToSharedPath)) {\n if (pattern.includes(DYNAMIC_PATH_SEGMENT_PATTERN)) {\n // Convert the pattern to a strict regex that matches the exact path structure\n const regex = new RegExp(`^${escapePathRegexSlashes(pattern)}$`);\n // Exact match\n if (regex.test(standardizedPathname)) {\n return sharedPath;\n }\n // Without locale prefix\n if (\n !candidateSharedPath &&\n pathnameLocale &&\n regex.test(pathnameWithoutLocale as string)\n ) {\n candidateSharedPath = sharedPath;\n }\n }\n }\n return candidateSharedPath;\n}\n\n/**\n * Checks if the pathname is in the default locale paths\n * @param pathname - The pathname to check\n * @param defaultLocalePaths - The default locale paths\n * @returns true if the pathname is in the default locale paths, false otherwise\n */\n\nfunction inDefaultLocalePaths(\n pathname: string,\n defaultLocalePaths: string[]\n): boolean {\n // Try exact match first\n if (defaultLocalePaths.includes(pathname)) {\n return true;\n }\n\n // Try regex pattern match\n for (const path of defaultLocalePaths) {\n if (path.includes(DYNAMIC_PATH_SEGMENT_PATTERN)) {\n const regex = new RegExp(`^${escapePathRegexSlashes(path)}$`);\n if (regex.test(pathname)) {\n return true;\n }\n }\n }\n return false;\n}\n\n/**\n * Gets the locale from the request using various sources\n */\nexport function getLocaleFromRequest(\n req: NextRequest,\n defaultLocale: string,\n approvedLocales: string[],\n localeRouting: boolean,\n gtServicesEnabled: boolean,\n prefixDefaultLocale: boolean,\n defaultLocalePaths: string[],\n referrerLocaleCookieName: string,\n localeCookieName: string,\n resetLocaleCookieName: string,\n gt: GTRuntime\n): {\n userLocale: string;\n pathnameLocale: string | undefined;\n unstandardizedPathnameLocale: string | null | undefined;\n clearResetCookie: boolean;\n} {\n const headerList = new Headers(req.headers);\n const candidates: string[] = [];\n let clearResetCookie = false;\n const { pathname } = req.nextUrl;\n\n // Check pathname locales\n let pathnameLocale, unstandardizedPathnameLocale;\n if (localeRouting) {\n unstandardizedPathnameLocale = extractLocale(pathname);\n const extractedLocale = gtServicesEnabled\n ? standardizeLocale(unstandardizedPathnameLocale || '')\n : unstandardizedPathnameLocale;\n\n if (\n extractedLocale &&\n gt.isValidLocale(extractedLocale) &&\n gt.determineLocale([extractedLocale], approvedLocales)\n ) {\n const determinedLocale = gt.determineLocale(\n [extractedLocale],\n approvedLocales\n );\n if (determinedLocale) {\n pathnameLocale = gt.resolveAliasLocale(determinedLocale);\n candidates.push(pathnameLocale);\n }\n }\n }\n\n // Check pathname for a customized unprefixed default locale path (e.g. /en-about , /en-dashboard/1/en-custom)\n if (\n localeRouting &&\n !prefixDefaultLocale &&\n !pathnameLocale &&\n inDefaultLocalePaths(pathname, defaultLocalePaths)\n ) {\n candidates.push(defaultLocale); // will override other candidates\n }\n\n // Check cookie locale\n const cookieLocale = req.cookies.get(localeCookieName);\n if (cookieLocale?.value && gt.isValidLocale(cookieLocale?.value)) {\n const resetCookie = req.cookies.get(resetLocaleCookieName);\n if (resetCookie?.value) {\n // Add this back in when we support custom getLocale\n // addedCustomLocale\n // ? candidates.splice(1, 0, cookieLocale.value)\n // : candidates.unshift(cookieLocale.value);\n candidates.unshift(cookieLocale.value);\n clearResetCookie = true;\n } else {\n candidates.push(cookieLocale.value);\n }\n }\n\n // Check referrer locale\n const referrerLocaleCookie = req.cookies.get(referrerLocaleCookieName);\n if (\n referrerLocaleCookie?.value &&\n gt.isValidLocale(referrerLocaleCookie.value) &&\n !clearResetCookie\n ) {\n const referrerLocale = referrerLocaleCookie.value;\n if (gt.determineLocale([referrerLocale], approvedLocales)) {\n candidates.push(referrerLocale);\n }\n }\n\n // Get locales from accept-language header\n if (process.env._GENERALTRANSLATION_IGNORE_BROWSER_LOCALES === 'false') {\n candidates.push(...parseAcceptLanguage(headerList.get('accept-language')));\n }\n\n // Get default locale\n candidates.push(defaultLocale);\n\n // determine userLocale\n const unstandardizedUserLocale =\n gt.determineLocale(\n candidates.filter((locale) => gt.isValidLocale(locale)),\n approvedLocales\n ) || defaultLocale;\n const userLocale = gtServicesEnabled\n ? standardizeLocale(unstandardizedUserLocale)\n : unstandardizedUserLocale;\n\n return {\n userLocale,\n pathnameLocale,\n unstandardizedPathnameLocale,\n clearResetCookie,\n };\n}\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"parseLocale.d.ts","sourceRoot":"","sources":["../../src/pages-dir/parseLocale.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,yBAAyB,EAAE,WAAW,EAAE,MAAM,MAAM,CAAC;AACnE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"parseLocale.d.ts","sourceRoot":"","sources":["../../src/pages-dir/parseLocale.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,yBAAyB,EAAE,WAAW,EAAE,MAAM,MAAM,CAAC;AACnE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAQlD;;GAEG;AACH,wBAAgB,WAAW,CACzB,MAAM,SAAS,cAAc,GAAG,cAAc,EAC9C,OAAO,SAAS,WAAW,GAAG,WAAW,EACzC,OAAO,EAAE,yBAAyB,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CA4B7D"}
|
|
@@ -3,6 +3,7 @@ require("../_virtual/_rolldown/runtime.js");
|
|
|
3
3
|
require("../utils/headers.js");
|
|
4
4
|
const require_errors_ssg = require("../errors/ssg.js");
|
|
5
5
|
let _generaltranslation_react_core_pure = require("@generaltranslation/react-core/pure");
|
|
6
|
+
let gt_i18n_internal = require("gt-i18n/internal");
|
|
6
7
|
//#region src/pages-dir/parseLocale.ts
|
|
7
8
|
/**
|
|
8
9
|
* Resolve the user's locale from a Next Pages Router server-side request.
|
|
@@ -14,7 +15,7 @@ function parseLocale(context) {
|
|
|
14
15
|
addHeaderCandidates(preferredLocales, context.req.headers[headerName]);
|
|
15
16
|
const cookieLocale = context.req.cookies?.[i18nConfig.getLocaleCookieName()];
|
|
16
17
|
if (cookieLocale) preferredLocales.push(cookieLocale);
|
|
17
|
-
if (!ignorePreferredLanguages) preferredLocales.push(...
|
|
18
|
+
if (!ignorePreferredLanguages) preferredLocales.push(...(0, gt_i18n_internal.parseAcceptLanguage)(context.req.headers["accept-language"]));
|
|
18
19
|
if (preferredLocales.length === 0 && !ignorePreferredLanguages) console.warn(require_errors_ssg.noLocalesCouldBeDeterminedWarning);
|
|
19
20
|
return i18nConfig.getGTClass().determineLocale(preferredLocales, i18nConfig.getLocales()) || i18nConfig.getDefaultLocale();
|
|
20
21
|
}
|
|
@@ -29,9 +30,6 @@ function addHeaderCandidates(candidates, headerValue) {
|
|
|
29
30
|
if (Array.isArray(headerValue)) candidates.push(...headerValue.filter(Boolean));
|
|
30
31
|
else if (headerValue) candidates.push(headerValue);
|
|
31
32
|
}
|
|
32
|
-
function getAcceptLanguageCandidates(headerValue) {
|
|
33
|
-
return (Array.isArray(headerValue) ? headerValue : [headerValue]).flatMap((value) => value?.split(",").map((item) => item.split(";")?.[0].trim()).filter(Boolean) || []);
|
|
34
|
-
}
|
|
35
33
|
//#endregion
|
|
36
34
|
exports.parseLocale = parseLocale;
|
|
37
35
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"parseLocale.js","names":["noLocalesCouldBeDeterminedWarning"],"sources":["../../src/pages-dir/parseLocale.ts"],"sourcesContent":["import type { GetServerSidePropsContext, PreviewData } from 'next';\nimport type { ParsedUrlQuery } from 'querystring';\nimport { getI18nConfig } from '@generaltranslation/react-core/pure';\nimport { noLocalesCouldBeDeterminedWarning } from '../errors/ssg';\nimport { defaultLocaleHeaderName } from '../utils/headers';\n\ntype HeaderValue = string | string[] | undefined;\n\n/**\n * Resolve the user's locale from a Next Pages Router server-side request.\n */\nexport function parseLocale<\n Params extends ParsedUrlQuery = ParsedUrlQuery,\n Preview extends PreviewData = PreviewData,\n>(context: GetServerSidePropsContext<Params, Preview>): string {\n const i18nConfig = getI18nConfig();\n const { headerName, ignorePreferredLanguages } = getParseLocaleParams();\n const preferredLocales: string[] = [];\n\n addHeaderCandidates(preferredLocales, context.req.headers[headerName]);\n\n const cookieLocale = context.req.cookies?.[i18nConfig.getLocaleCookieName()];\n if (cookieLocale) {\n preferredLocales.push(cookieLocale);\n }\n\n if (!ignorePreferredLanguages) {\n preferredLocales.push(\n ...
|
|
1
|
+
{"version":3,"file":"parseLocale.js","names":["noLocalesCouldBeDeterminedWarning"],"sources":["../../src/pages-dir/parseLocale.ts"],"sourcesContent":["import type { GetServerSidePropsContext, PreviewData } from 'next';\nimport type { ParsedUrlQuery } from 'querystring';\nimport { getI18nConfig } from '@generaltranslation/react-core/pure';\nimport { parseAcceptLanguage } from 'gt-i18n/internal';\nimport { noLocalesCouldBeDeterminedWarning } from '../errors/ssg';\nimport { defaultLocaleHeaderName } from '../utils/headers';\n\ntype HeaderValue = string | string[] | undefined;\n\n/**\n * Resolve the user's locale from a Next Pages Router server-side request.\n */\nexport function parseLocale<\n Params extends ParsedUrlQuery = ParsedUrlQuery,\n Preview extends PreviewData = PreviewData,\n>(context: GetServerSidePropsContext<Params, Preview>): string {\n const i18nConfig = getI18nConfig();\n const { headerName, ignorePreferredLanguages } = getParseLocaleParams();\n const preferredLocales: string[] = [];\n\n addHeaderCandidates(preferredLocales, context.req.headers[headerName]);\n\n const cookieLocale = context.req.cookies?.[i18nConfig.getLocaleCookieName()];\n if (cookieLocale) {\n preferredLocales.push(cookieLocale);\n }\n\n if (!ignorePreferredLanguages) {\n preferredLocales.push(\n ...parseAcceptLanguage(context.req.headers['accept-language'])\n );\n }\n\n if (preferredLocales.length === 0 && !ignorePreferredLanguages) {\n console.warn(noLocalesCouldBeDeterminedWarning);\n }\n\n return (\n i18nConfig\n .getGTClass()\n .determineLocale(preferredLocales, i18nConfig.getLocales()) ||\n i18nConfig.getDefaultLocale()\n );\n}\n\nfunction getParseLocaleParams(): {\n headerName: string;\n ignorePreferredLanguages: boolean;\n} {\n const privateConfig = JSON.parse(\n process.env._GENERALTRANSLATION_I18N_CONFIG_PARAMS || '{}'\n );\n\n return {\n headerName:\n privateConfig.headersAndCookies?.localeHeaderName ||\n defaultLocaleHeaderName,\n ignorePreferredLanguages: privateConfig.ignoreBrowserLocales || false,\n };\n}\n\nfunction addHeaderCandidates(candidates: string[], headerValue: HeaderValue) {\n if (Array.isArray(headerValue)) {\n candidates.push(...headerValue.filter(Boolean));\n } else if (headerValue) {\n candidates.push(headerValue);\n }\n}\n"],"mappings":";;;;;;;;;;AAYA,SAAgB,YAGd,SAA6D;CAC7D,MAAM,cAAA,GAAA,oCAAA,gBAA4B;CAClC,MAAM,EAAE,YAAY,6BAA6B,sBAAsB;CACvE,MAAM,mBAA6B,EAAE;AAErC,qBAAoB,kBAAkB,QAAQ,IAAI,QAAQ,YAAY;CAEtE,MAAM,eAAe,QAAQ,IAAI,UAAU,WAAW,qBAAqB;AAC3E,KAAI,aACF,kBAAiB,KAAK,aAAa;AAGrC,KAAI,CAAC,yBACH,kBAAiB,KACf,IAAA,GAAA,iBAAA,qBAAuB,QAAQ,IAAI,QAAQ,mBAAmB,CAC/D;AAGH,KAAI,iBAAiB,WAAW,KAAK,CAAC,yBACpC,SAAQ,KAAKA,mBAAAA,kCAAkC;AAGjD,QACE,WACG,YAAY,CACZ,gBAAgB,kBAAkB,WAAW,YAAY,CAAC,IAC7D,WAAW,kBAAkB;;AAIjC,SAAS,uBAGP;CACA,MAAM,gBAAgB,KAAK,MACzB,QAAQ,IAAI,0CAA0C,KACvD;AAED,QAAO;EACL,YACE,cAAc,mBAAmB,oBAAA;EAEnC,0BAA0B,cAAc,wBAAwB;EACjE;;AAGH,SAAS,oBAAoB,YAAsB,aAA0B;AAC3E,KAAI,MAAM,QAAQ,YAAY,CAC5B,YAAW,KAAK,GAAG,YAAY,OAAO,QAAQ,CAAC;UACtC,YACT,YAAW,KAAK,YAAY"}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import "../utils/headers.mjs";
|
|
2
2
|
import { noLocalesCouldBeDeterminedWarning } from "../errors/ssg.mjs";
|
|
3
3
|
import { getI18nConfig } from "@generaltranslation/react-core/pure";
|
|
4
|
+
import { parseAcceptLanguage } from "gt-i18n/internal";
|
|
4
5
|
//#region src/pages-dir/parseLocale.ts
|
|
5
6
|
/**
|
|
6
7
|
* Resolve the user's locale from a Next Pages Router server-side request.
|
|
@@ -12,7 +13,7 @@ function parseLocale(context) {
|
|
|
12
13
|
addHeaderCandidates(preferredLocales, context.req.headers[headerName]);
|
|
13
14
|
const cookieLocale = context.req.cookies?.[i18nConfig.getLocaleCookieName()];
|
|
14
15
|
if (cookieLocale) preferredLocales.push(cookieLocale);
|
|
15
|
-
if (!ignorePreferredLanguages) preferredLocales.push(...
|
|
16
|
+
if (!ignorePreferredLanguages) preferredLocales.push(...parseAcceptLanguage(context.req.headers["accept-language"]));
|
|
16
17
|
if (preferredLocales.length === 0 && !ignorePreferredLanguages) console.warn(noLocalesCouldBeDeterminedWarning);
|
|
17
18
|
return i18nConfig.getGTClass().determineLocale(preferredLocales, i18nConfig.getLocales()) || i18nConfig.getDefaultLocale();
|
|
18
19
|
}
|
|
@@ -27,9 +28,6 @@ function addHeaderCandidates(candidates, headerValue) {
|
|
|
27
28
|
if (Array.isArray(headerValue)) candidates.push(...headerValue.filter(Boolean));
|
|
28
29
|
else if (headerValue) candidates.push(headerValue);
|
|
29
30
|
}
|
|
30
|
-
function getAcceptLanguageCandidates(headerValue) {
|
|
31
|
-
return (Array.isArray(headerValue) ? headerValue : [headerValue]).flatMap((value) => value?.split(",").map((item) => item.split(";")?.[0].trim()).filter(Boolean) || []);
|
|
32
|
-
}
|
|
33
31
|
//#endregion
|
|
34
32
|
export { parseLocale };
|
|
35
33
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"parseLocale.mjs","names":[],"sources":["../../src/pages-dir/parseLocale.ts"],"sourcesContent":["import type { GetServerSidePropsContext, PreviewData } from 'next';\nimport type { ParsedUrlQuery } from 'querystring';\nimport { getI18nConfig } from '@generaltranslation/react-core/pure';\nimport { noLocalesCouldBeDeterminedWarning } from '../errors/ssg';\nimport { defaultLocaleHeaderName } from '../utils/headers';\n\ntype HeaderValue = string | string[] | undefined;\n\n/**\n * Resolve the user's locale from a Next Pages Router server-side request.\n */\nexport function parseLocale<\n Params extends ParsedUrlQuery = ParsedUrlQuery,\n Preview extends PreviewData = PreviewData,\n>(context: GetServerSidePropsContext<Params, Preview>): string {\n const i18nConfig = getI18nConfig();\n const { headerName, ignorePreferredLanguages } = getParseLocaleParams();\n const preferredLocales: string[] = [];\n\n addHeaderCandidates(preferredLocales, context.req.headers[headerName]);\n\n const cookieLocale = context.req.cookies?.[i18nConfig.getLocaleCookieName()];\n if (cookieLocale) {\n preferredLocales.push(cookieLocale);\n }\n\n if (!ignorePreferredLanguages) {\n preferredLocales.push(\n ...
|
|
1
|
+
{"version":3,"file":"parseLocale.mjs","names":[],"sources":["../../src/pages-dir/parseLocale.ts"],"sourcesContent":["import type { GetServerSidePropsContext, PreviewData } from 'next';\nimport type { ParsedUrlQuery } from 'querystring';\nimport { getI18nConfig } from '@generaltranslation/react-core/pure';\nimport { parseAcceptLanguage } from 'gt-i18n/internal';\nimport { noLocalesCouldBeDeterminedWarning } from '../errors/ssg';\nimport { defaultLocaleHeaderName } from '../utils/headers';\n\ntype HeaderValue = string | string[] | undefined;\n\n/**\n * Resolve the user's locale from a Next Pages Router server-side request.\n */\nexport function parseLocale<\n Params extends ParsedUrlQuery = ParsedUrlQuery,\n Preview extends PreviewData = PreviewData,\n>(context: GetServerSidePropsContext<Params, Preview>): string {\n const i18nConfig = getI18nConfig();\n const { headerName, ignorePreferredLanguages } = getParseLocaleParams();\n const preferredLocales: string[] = [];\n\n addHeaderCandidates(preferredLocales, context.req.headers[headerName]);\n\n const cookieLocale = context.req.cookies?.[i18nConfig.getLocaleCookieName()];\n if (cookieLocale) {\n preferredLocales.push(cookieLocale);\n }\n\n if (!ignorePreferredLanguages) {\n preferredLocales.push(\n ...parseAcceptLanguage(context.req.headers['accept-language'])\n );\n }\n\n if (preferredLocales.length === 0 && !ignorePreferredLanguages) {\n console.warn(noLocalesCouldBeDeterminedWarning);\n }\n\n return (\n i18nConfig\n .getGTClass()\n .determineLocale(preferredLocales, i18nConfig.getLocales()) ||\n i18nConfig.getDefaultLocale()\n );\n}\n\nfunction getParseLocaleParams(): {\n headerName: string;\n ignorePreferredLanguages: boolean;\n} {\n const privateConfig = JSON.parse(\n process.env._GENERALTRANSLATION_I18N_CONFIG_PARAMS || '{}'\n );\n\n return {\n headerName:\n privateConfig.headersAndCookies?.localeHeaderName ||\n defaultLocaleHeaderName,\n ignorePreferredLanguages: privateConfig.ignoreBrowserLocales || false,\n };\n}\n\nfunction addHeaderCandidates(candidates: string[], headerValue: HeaderValue) {\n if (Array.isArray(headerValue)) {\n candidates.push(...headerValue.filter(Boolean));\n } else if (headerValue) {\n candidates.push(headerValue);\n }\n}\n"],"mappings":";;;;;;;;AAYA,SAAgB,YAGd,SAA6D;CAC7D,MAAM,aAAa,eAAe;CAClC,MAAM,EAAE,YAAY,6BAA6B,sBAAsB;CACvE,MAAM,mBAA6B,EAAE;AAErC,qBAAoB,kBAAkB,QAAQ,IAAI,QAAQ,YAAY;CAEtE,MAAM,eAAe,QAAQ,IAAI,UAAU,WAAW,qBAAqB;AAC3E,KAAI,aACF,kBAAiB,KAAK,aAAa;AAGrC,KAAI,CAAC,yBACH,kBAAiB,KACf,GAAG,oBAAoB,QAAQ,IAAI,QAAQ,mBAAmB,CAC/D;AAGH,KAAI,iBAAiB,WAAW,KAAK,CAAC,yBACpC,SAAQ,KAAK,kCAAkC;AAGjD,QACE,WACG,YAAY,CACZ,gBAAgB,kBAAkB,WAAW,YAAY,CAAC,IAC7D,WAAW,kBAAkB;;AAIjC,SAAS,uBAGP;CACA,MAAM,gBAAgB,KAAK,MACzB,QAAQ,IAAI,0CAA0C,KACvD;AAED,QAAO;EACL,YACE,cAAc,mBAAmB,oBAAA;EAEnC,0BAA0B,cAAc,wBAAwB;EACjE;;AAGH,SAAS,oBAAoB,YAAsB,aAA0B;AAC3E,KAAI,MAAM,QAAQ,YAAY,CAC5B,YAAW,KAAK,GAAG,YAAY,OAAO,QAAQ,CAAC;UACtC,YACT,YAAW,KAAK,YAAY"}
|