next-intl 4.9.2 → 4.10.0
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/dist/esm/development/middleware/getAlternateLinksHeaderValue.js +4 -1
- package/dist/esm/development/middleware/middleware.js +8 -4
- package/dist/esm/development/navigation/shared/utils.js +8 -5
- package/dist/esm/production/middleware/getAlternateLinksHeaderValue.js +1 -1
- package/dist/esm/production/middleware/middleware.js +1 -1
- package/dist/esm/production/navigation/shared/utils.js +1 -1
- package/dist/types/routing/types.d.ts +1 -0
- package/package.json +5 -5
|
@@ -54,7 +54,10 @@ function getAlternateLinksHeaderValue({
|
|
|
54
54
|
// Important: Use `normalizedUrl` here, as `url` potentially uses
|
|
55
55
|
// a `basePath` that automatically gets applied to the pathname
|
|
56
56
|
url.pathname = getLocalizedPathname(normalizedUrl.pathname, locale);
|
|
57
|
-
|
|
57
|
+
|
|
58
|
+
// Use domain-specific localePrefix mode if available
|
|
59
|
+
const domainMode = domainConfig.localePrefix || routing.localePrefix.mode;
|
|
60
|
+
if (locale !== domainConfig.defaultLocale || domainMode === 'always') {
|
|
58
61
|
url.pathname = prefixPathname(url.pathname);
|
|
59
62
|
}
|
|
60
63
|
return getAlternateEntry(url, locale);
|
|
@@ -59,7 +59,8 @@ function createMiddleware(routing) {
|
|
|
59
59
|
const bestMatchingDomain = getBestMatchingDomain(domain, locale, domainsConfig);
|
|
60
60
|
if (bestMatchingDomain) {
|
|
61
61
|
redirectDomain = bestMatchingDomain.domain;
|
|
62
|
-
|
|
62
|
+
const redirectDomainMode = bestMatchingDomain.localePrefix || resolvedRouting.localePrefix.mode;
|
|
63
|
+
if (bestMatchingDomain.defaultLocale === locale && redirectDomainMode === 'as-needed') {
|
|
63
64
|
urlObj.pathname = getNormalizedPathname(urlObj.pathname, resolvedRouting.locales, resolvedRouting.localePrefix);
|
|
64
65
|
}
|
|
65
66
|
}
|
|
@@ -81,7 +82,10 @@ function createMiddleware(routing) {
|
|
|
81
82
|
const unprefixedExternalPathname = getNormalizedPathname(externalPathname, resolvedRouting.locales, resolvedRouting.localePrefix);
|
|
82
83
|
const pathnameMatch = getPathnameMatch(externalPathname, resolvedRouting.locales, resolvedRouting.localePrefix, domain);
|
|
83
84
|
const hasLocalePrefix = pathnameMatch != null;
|
|
84
|
-
|
|
85
|
+
|
|
86
|
+
// Use domain-specific localePrefix mode if available, otherwise use global mode
|
|
87
|
+
const effectiveLocalePrefixMode = domain?.localePrefix || resolvedRouting.localePrefix.mode;
|
|
88
|
+
const isUnprefixedRouting = effectiveLocalePrefixMode === 'never' || hasMatchedDefaultLocale && effectiveLocalePrefixMode === 'as-needed';
|
|
85
89
|
let response;
|
|
86
90
|
let internalTemplateName;
|
|
87
91
|
let hasRedirected;
|
|
@@ -122,7 +126,7 @@ function createMiddleware(routing) {
|
|
|
122
126
|
const internalHref = formatPathname(unprefixedInternalPathname, getLocaleAsPrefix(locale), request.nextUrl.search);
|
|
123
127
|
if (hasLocalePrefix) {
|
|
124
128
|
const externalHref = formatPathname(unprefixedExternalPathname, pathnameMatch.prefix, request.nextUrl.search);
|
|
125
|
-
if (
|
|
129
|
+
if (effectiveLocalePrefixMode === 'never') {
|
|
126
130
|
response = redirect(formatPathname(unprefixedExternalPathname, undefined, request.nextUrl.search));
|
|
127
131
|
} else if (pathnameMatch.exact) {
|
|
128
132
|
if (hasMatchedDefaultLocale && isUnprefixedRouting) {
|
|
@@ -152,7 +156,7 @@ function createMiddleware(routing) {
|
|
|
152
156
|
}
|
|
153
157
|
}
|
|
154
158
|
syncCookie(request, response, locale, resolvedRouting, domain);
|
|
155
|
-
if (!hasRedirected &&
|
|
159
|
+
if (!hasRedirected && effectiveLocalePrefixMode !== 'never' && resolvedRouting.alternateLinks && resolvedRouting.locales.length > 1) {
|
|
156
160
|
response.headers.set('Link', getAlternateLinksHeaderValue({
|
|
157
161
|
routing: resolvedRouting,
|
|
158
162
|
internalTemplateName,
|
|
@@ -139,19 +139,22 @@ function getBasePath(pathname, windowPathname = window.location.pathname) {
|
|
|
139
139
|
}
|
|
140
140
|
function applyPathnamePrefix(pathname, locale, routing, force) {
|
|
141
141
|
const {
|
|
142
|
-
mode
|
|
142
|
+
mode: routingMode
|
|
143
143
|
} = routing.localePrefix;
|
|
144
144
|
let shouldPrefix;
|
|
145
145
|
if (force !== undefined) {
|
|
146
146
|
shouldPrefix = force;
|
|
147
147
|
} else if (isLocalizableHref(pathname)) {
|
|
148
|
+
// Since locales are unique per domain, there should be
|
|
149
|
+
// only one domain that contains the locale
|
|
150
|
+
const domain = routing.domains?.find(cur => cur.locales.includes(locale));
|
|
151
|
+
|
|
152
|
+
// Domains can override the mode
|
|
153
|
+
const mode = domain?.localePrefix || routingMode;
|
|
148
154
|
if (mode === 'always') {
|
|
149
155
|
shouldPrefix = true;
|
|
150
156
|
} else if (mode === 'as-needed') {
|
|
151
|
-
shouldPrefix = routing.
|
|
152
|
-
// Since locales are unique per domain, any locale that is a
|
|
153
|
-
// default locale of a domain doesn't require a prefix
|
|
154
|
-
!routing.domains.some(cur => cur.defaultLocale === locale) : locale !== routing.defaultLocale;
|
|
157
|
+
shouldPrefix = domain ? locale !== domain.defaultLocale : locale !== routing.defaultLocale;
|
|
155
158
|
}
|
|
156
159
|
}
|
|
157
160
|
return shouldPrefix ? prefixPathname(getLocalePrefix(locale, routing.localePrefix), pathname) : pathname;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{normalizeTrailingSlash as e}from"../shared/utils.js";import{getHost as a,getNormalizedPathname as t,getLocalePrefixes as n,isLocaleSupportedOnDomain as o,applyBasePath as r,formatTemplatePathname as l}from"./utils.js";function s({internalTemplateName:s,localizedPathnames:
|
|
1
|
+
import{normalizeTrailingSlash as e}from"../shared/utils.js";import{getHost as a,getNormalizedPathname as t,getLocalePrefixes as n,isLocaleSupportedOnDomain as o,applyBasePath as r,formatTemplatePathname as l}from"./utils.js";function s({internalTemplateName:s,localizedPathnames:i,request:m,resolvedLocale:c,routing:p}){const f=m.nextUrl.clone(),h=a(m.headers);function u(a,t){return a.pathname=e(a.pathname),m.nextUrl.basePath&&((a=new URL(a)).pathname=r(a.pathname,m.nextUrl.basePath)),`<${a.toString()}>; rel="alternate"; hreflang="${t}"`}function d(e,a){if(i&&"object"==typeof i){const t=i[c];return l(e,t??s,i[a]??s)}return e}h&&(f.port="",f.host=h),f.protocol=m.headers.get("x-forwarded-proto")??f.protocol,f.pathname=t(f.pathname,p.locales,p.localePrefix);const x=n(p.locales,p.localePrefix,!1).flatMap((([e,a])=>{function t(e){return"/"===e?a:a+e}let n;if(p.domains){return p.domains.filter((a=>o(e,a))).map((a=>{n=new URL(f),n.port="",n.host=a.domain,n.pathname=d(f.pathname,e);const o=a.localePrefix||p.localePrefix.mode;return e===a.defaultLocale&&"always"!==o||(n.pathname=t(n.pathname)),u(n,e)}))}{let a;a=i&&"object"==typeof i?d(f.pathname,e):f.pathname,e===p.defaultLocale&&"always"!==p.localePrefix.mode||(a=t(a)),n=new URL(a,f)}return u(n,e)}));if(!p.domains||0===p.domains.length){const e=d(f.pathname,p.defaultLocale);if(e){const a=new URL(e,f);x.push(u(a,"x-default"))}}return x.join(", ")}export{s as default};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{NextResponse as e}from"next/server";import{receiveRoutingConfig as t}from"../routing/config.js";import{HEADER_LOCALE_NAME as r}from"../shared/constants.js";import{matchesPathname as a,normalizeTrailingSlash as o,getLocalePrefix as
|
|
1
|
+
import{NextResponse as e}from"next/server";import{receiveRoutingConfig as t}from"../routing/config.js";import{HEADER_LOCALE_NAME as r}from"../shared/constants.js";import{matchesPathname as a,normalizeTrailingSlash as o,getLocalePrefix as n,getLocalizedTemplate as l}from"../shared/utils.js";import s from"./getAlternateLinksHeaderValue.js";import i from"./resolveLocale.js";import c from"./syncCookie.js";import{sanitizePathname as d,isLocaleSupportedOnDomain as f,getNormalizedPathname as m,getPathnameMatch as h,getInternalTemplate as x,formatTemplatePathname as p,formatPathname as u,getBestMatchingDomain as U,applyBasePath as P,getLocaleAsPrefix as g}from"./utils.js";function v(v){const L=t(v);return function(t){let v;try{v=decodeURI(t.nextUrl.pathname)}catch{return e.next()}const j=d(v),{domain:w,locale:k}=i(L,t.headers,t.cookies,j),b=w?w.defaultLocale===k:k===L.defaultLocale,q=L.domains?.filter((e=>f(k,e)))||[],R=null!=L.domains&&!w;function y(a){const n=new URL(a,t.url);t.nextUrl.basePath&&(n.pathname=P(n.pathname,t.nextUrl.basePath));const l=new Headers(t.headers);l.set(r,k);return o(t.nextUrl.pathname)!==o(n.pathname)?e.rewrite(n,{request:{headers:l}}):e.next({request:{headers:l}})}function H(r,a){const n=new URL(r,t.url);if(n.pathname=o(n.pathname),q.length>0&&!a&&w){const e=U(w,k,q);if(e){a=e.domain;const t=e.localePrefix||L.localePrefix.mode;e.defaultLocale===k&&"as-needed"===t&&(n.pathname=m(n.pathname,L.locales,L.localePrefix))}}if(a&&(n.host=a,t.headers.get("x-forwarded-host"))){n.protocol=t.headers.get("x-forwarded-proto")??t.nextUrl.protocol;const e=a.split(":")[1];n.port=e??t.headers.get("x-forwarded-port")??""}return t.nextUrl.basePath&&(n.pathname=P(n.pathname,t.nextUrl.basePath)),V=!0,e.redirect(n.toString())}const z=m(j,L.locales,L.localePrefix),A=h(j,L.locales,L.localePrefix,w),C=null!=A,I=w?.localePrefix||L.localePrefix.mode,N="never"===I||b&&"as-needed"===I;let S,T,V,B=z;const D=L.pathnames;if(D){let e;if([e,T]=x(D,z,k),T){const r=D[T],o=l(r,k,T);if(a(o,z))B=p(z,o,T);else{let a;a=e?l(r,e,T):T;const s=N?void 0:n(k,L.localePrefix),i=p(z,a,o);S=H(u(i,s,t.nextUrl.search))}}}if(!S)if("/"!==B||C){const e=u(B,g(k),t.nextUrl.search);if(C){const r=u(z,A.prefix,t.nextUrl.search);if("never"===I)S=H(u(z,void 0,t.nextUrl.search));else if(A.exact)if(b&&N)S=H(u(z,void 0,t.nextUrl.search));else if(L.domains){const t=U(w,A.locale,q);S=w?.domain===t?.domain||R?y(e):H(r,t?.domain)}else S=y(e);else S=H(r)}else S=N?y(e):H(u(z,n(k,L.localePrefix),t.nextUrl.search))}else S=N?y(u(B,g(k),t.nextUrl.search)):H(u(z,n(k,L.localePrefix),t.nextUrl.search));return c(t,S,k,L,w),!V&&"never"!==I&&L.alternateLinks&&L.locales.length>1&&S.headers.set("Link",s({routing:L,internalTemplateName:T,localizedPathnames:null!=T&&D?D[T]:void 0,request:t,resolvedLocale:k})),S}}export{v as default};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{getSortedPathnames as e,matchesPathname as n,isLocalizableHref as t,prefixPathname as r,normalizeTrailingSlash as o,getLocalizedTemplate as a,getLocalePrefix as i}from"../../shared/utils.js";function c(e){return"string"==typeof e?{pathname:e}:e}function s(e){function n(e){return String(e)}const t=new URLSearchParams;for(const[r,o]of Object.entries(e))Array.isArray(o)?o.forEach((e=>{t.append(r,n(e))})):t.set(r,n(o));return"?"+t.toString()}function f({pathname:e,locale:n,params:t,pathnames:r,query:i}){function c(e){const c=r[e];let f;if(c){const r=a(c,n,e);f=r,t&&Object.entries(t).forEach((([e,n])=>{let t,r;Array.isArray(n)?(t=`(\\[)?\\[...${e}\\](\\])?`,r=n.map((e=>String(e))).join("/")):(t=`\\[${e}\\]`,r=String(n)),f=f.replace(new RegExp(t,"g"),r)})),f=f.replace(/\[\[\.\.\..+\]\]/g,""),f=function(e){return new URL(e,"http://l").pathname}(f)}else f=e;return f=o(f),i&&(f+=s(i)),f}if("string"==typeof e)return c(e);{const{pathname:n,...t}=e;return{...t,pathname:c(n)}}}function
|
|
1
|
+
import{getSortedPathnames as e,matchesPathname as n,isLocalizableHref as t,prefixPathname as r,normalizeTrailingSlash as o,getLocalizedTemplate as a,getLocalePrefix as i}from"../../shared/utils.js";function c(e){return"string"==typeof e?{pathname:e}:e}function s(e){function n(e){return String(e)}const t=new URLSearchParams;for(const[r,o]of Object.entries(e))Array.isArray(o)?o.forEach((e=>{t.append(r,n(e))})):t.set(r,n(o));return"?"+t.toString()}function f({pathname:e,locale:n,params:t,pathnames:r,query:i}){function c(e){const c=r[e];let f;if(c){const r=a(c,n,e);f=r,t&&Object.entries(t).forEach((([e,n])=>{let t,r;Array.isArray(n)?(t=`(\\[)?\\[...${e}\\](\\])?`,r=n.map((e=>String(e))).join("/")):(t=`\\[${e}\\]`,r=String(n)),f=f.replace(new RegExp(t,"g"),r)})),f=f.replace(/\[\[\.\.\..+\]\]/g,""),f=function(e){return new URL(e,"http://l").pathname}(f)}else f=e;return f=o(f),i&&(f+=s(i)),f}if("string"==typeof e)return c(e);{const{pathname:n,...t}=e;return{...t,pathname:c(n)}}}function l(t,r,o){const i=e(Object.keys(o)),c=decodeURI(r);for(const e of i){const r=o[e];if("string"==typeof r){if(n(r,c))return e}else if(n(a(r,t,e),c))return e}return r}function u(e,n=window.location.pathname){return"/"===e?n:n.replace(e,"")}function p(e,n,o,a){const{mode:c}=o.localePrefix;let s;if(void 0!==a)s=a;else if(t(e)){const e=o.domains?.find((e=>e.locales.includes(n))),t=e?.localePrefix||c;"always"===t?s=!0:"as-needed"===t&&(s=e?n!==e.defaultLocale:n!==o.defaultLocale)}return s?r(i(n,o.localePrefix),e):e}export{p as applyPathnamePrefix,f as compileLocalizedPathname,u as getBasePath,l as getRoute,c as normalizeNameOrNameWithParams,s as serializeSearchParams};
|
|
@@ -14,6 +14,7 @@ export type LocalePrefixConfigVerbose<AppLocales extends Locales, AppLocalePrefi
|
|
|
14
14
|
export type LocalePrefix<AppLocales extends Locales = [], AppLocalePrefixMode extends LocalePrefixMode = 'always'> = AppLocalePrefixMode | LocalePrefixConfigVerbose<AppLocales, AppLocalePrefixMode>;
|
|
15
15
|
export type Pathnames<AppLocales extends Locales> = Record<Pathname, Partial<Record<AppLocales[number], Pathname>> | Pathname>;
|
|
16
16
|
export type DomainConfig<AppLocales extends Locales> = {
|
|
17
|
+
localePrefix?: LocalePrefixMode;
|
|
17
18
|
defaultLocale: AppLocales[number];
|
|
18
19
|
/** The domain name (e.g. "example.com", "www.example.com" or "fr.example.com"). Note that the `x-forwarded-host` or alternatively the `host` header will be used to determine the requested domain. */
|
|
19
20
|
domain: string;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "next-intl",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.10.0",
|
|
4
4
|
"sideEffects": false,
|
|
5
5
|
"author": "Jan Amann <jan@amann.work>",
|
|
6
6
|
"funding": [
|
|
@@ -127,11 +127,11 @@
|
|
|
127
127
|
"@formatjs/intl-localematcher": "^0.8.1",
|
|
128
128
|
"@parcel/watcher": "^2.4.1",
|
|
129
129
|
"@swc/core": "^1.15.2",
|
|
130
|
-
"icu-minify": "^4.
|
|
130
|
+
"icu-minify": "^4.10.0",
|
|
131
131
|
"negotiator": "^1.0.0",
|
|
132
|
-
"next-intl-swc-plugin-extractor": "^4.
|
|
132
|
+
"next-intl-swc-plugin-extractor": "^4.10.0",
|
|
133
133
|
"po-parser": "^2.1.1",
|
|
134
|
-
"use-intl": "^4.
|
|
134
|
+
"use-intl": "^4.10.0"
|
|
135
135
|
},
|
|
136
136
|
"peerDependencies": {
|
|
137
137
|
"next": "^12.0.0 || ^13.0.0 || ^14.0.0 || ^15.0.0 || ^16.0.0",
|
|
@@ -142,5 +142,5 @@
|
|
|
142
142
|
"optional": true
|
|
143
143
|
}
|
|
144
144
|
},
|
|
145
|
-
"gitHead": "
|
|
145
|
+
"gitHead": "d4648b884c609400b53da58ab0def5feb22ab654"
|
|
146
146
|
}
|