next-intl 4.9.1 → 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.
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- var plugin = require('./plugin-YzBhQjAo.cjs');
3
+ var plugin = require('./plugin-Har7Ebj3.cjs');
4
4
  var ExtractorCodec = require('./ExtractorCodec-D9Tw618d.cjs');
5
5
  require('fs/promises');
6
6
  require('path');
@@ -35,6 +35,9 @@ var JSONCodec = ExtractorCodec.defineCodec(() => ({
35
35
  function traverseMessages(obj, callback, path = '') {
36
36
  const NAMESPACE_SEPARATOR = '.';
37
37
  for (const key of Object.keys(obj)) {
38
+ if (plugin.isForbiddenObjectKey(key)) {
39
+ throw new Error(`Invalid message catalog key: \`${key}\`.`);
40
+ }
38
41
  const newPath = path ? path + NAMESPACE_SEPARATOR + key : key;
39
42
  const value = obj[key];
40
43
  if (typeof value === 'string') {
@@ -1,7 +1,7 @@
1
1
  'use strict';
2
2
 
3
3
  var POParser = require('po-parser');
4
- var plugin = require('./plugin-YzBhQjAo.cjs');
4
+ var plugin = require('./plugin-Har7Ebj3.cjs');
5
5
  var ExtractorCodec = require('./ExtractorCodec-D9Tw618d.cjs');
6
6
  require('fs/promises');
7
7
  require('path');
@@ -122,11 +122,11 @@ export default messages;`;
122
122
 
123
123
  const formats = {
124
124
  json: {
125
- codec: () => Promise.resolve().then(function () { return require('./JSONCodec-rhejs716.cjs'); }),
125
+ codec: () => Promise.resolve().then(function () { return require('./JSONCodec-XU-elSg6.cjs'); }),
126
126
  extension: '.json'
127
127
  },
128
128
  po: {
129
- codec: () => Promise.resolve().then(function () { return require('./POCodec-Cv3VdXQG.cjs'); }),
129
+ codec: () => Promise.resolve().then(function () { return require('./POCodec-cA1pxFGQ.cjs'); }),
130
130
  extension: '.po'
131
131
  }
132
132
  };
@@ -342,15 +342,24 @@ function normalizePathToPosix(filePath) {
342
342
  // always use POSIX separators, regardless of the OS that ran extraction.
343
343
  return path__default.default.posix.normalize(filePath.split(path__default.default.win32.sep).join(path__default.default.posix.sep));
344
344
  }
345
+ const FORBIDDEN_OBJECT_KEYS = new Set(['__proto__', 'constructor', 'prototype']);
346
+ function isForbiddenObjectKey(key) {
347
+ return FORBIDDEN_OBJECT_KEYS.has(key);
348
+ }
345
349
 
346
350
  // Essentialls lodash/set, but we avoid this dependency
347
351
  function setNestedProperty(obj, keyPath, value) {
348
352
  const keys = keyPath.split('.');
353
+ for (const key of keys) {
354
+ if (isForbiddenObjectKey(key)) {
355
+ throw new Error(`Invalid message id segment: ${key}`);
356
+ }
357
+ }
349
358
  let current = obj;
350
359
  for (let i = 0; i < keys.length - 1; i++) {
351
360
  const key = keys[i];
352
- if (!(key in current) || typeof current[key] !== 'object' || current[key] === null) {
353
- current[key] = {};
361
+ if (!Object.prototype.hasOwnProperty.call(current, key) || typeof current[key] !== 'object' || current[key] === null) {
362
+ current[key] = Object.create(null);
354
363
  }
355
364
  current = current[key];
356
365
  }
@@ -990,7 +999,7 @@ class LRUCache {
990
999
  }
991
1000
  }
992
1001
 
993
- const require$2 = module$1.createRequire((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('plugin-YzBhQjAo.cjs', document.baseURI).href)));
1002
+ const require$2 = module$1.createRequire((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('plugin-Har7Ebj3.cjs', document.baseURI).href)));
994
1003
  class MessageExtractor {
995
1004
  compileCache = new LRUCache(750);
996
1005
  constructor(opts) {
@@ -1148,7 +1157,7 @@ function initExtractionCompiler(pluginConfig) {
1148
1157
 
1149
1158
  function getCurrentVersion() {
1150
1159
  try {
1151
- const require$1 = module$1.createRequire((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('plugin-YzBhQjAo.cjs', document.baseURI).href)));
1160
+ const require$1 = module$1.createRequire((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('plugin-Har7Ebj3.cjs', document.baseURI).href)));
1152
1161
  const pkg = require$1('next/package.json');
1153
1162
  return pkg.version;
1154
1163
  } catch (error) {
@@ -1175,7 +1184,7 @@ function isNextJs16OrHigher() {
1175
1184
  return compareVersions(getCurrentVersion(), '16.0.0') >= 0;
1176
1185
  }
1177
1186
 
1178
- const require$1 = module$1.createRequire((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('plugin-YzBhQjAo.cjs', document.baseURI).href)));
1187
+ const require$1 = module$1.createRequire((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('plugin-Har7Ebj3.cjs', document.baseURI).href)));
1179
1188
  function withExtensions(localPath) {
1180
1189
  return [`${localPath}.ts`, `${localPath}.tsx`, `${localPath}.js`, `${localPath}.jsx`];
1181
1190
  }
@@ -1454,4 +1463,5 @@ function createNextIntlPlugin(i18nPathOrConfig = {}) {
1454
1463
 
1455
1464
  exports.createNextIntlPlugin = createNextIntlPlugin;
1456
1465
  exports.getSortedMessages = getSortedMessages;
1466
+ exports.isForbiddenObjectKey = isForbiddenObjectKey;
1457
1467
  exports.setNestedProperty = setNestedProperty;
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- var plugin = require('./plugin-YzBhQjAo.cjs');
3
+ var plugin = require('./plugin-Har7Ebj3.cjs');
4
4
  require('fs/promises');
5
5
  require('path');
6
6
  require('@parcel/watcher');
@@ -60,7 +60,7 @@ function catalogLoader(source) {
60
60
  * using icu-minify/compile for smaller runtime bundles.
61
61
  */
62
62
  function precompileMessages(messages, cache) {
63
- const result = {};
63
+ const result = Object.create(null);
64
64
  const cacheKeysToEvict = new Set(cache.keys());
65
65
  for (const message of messages) {
66
66
  cacheKeysToEvict.delete(message.id);
@@ -1,4 +1,4 @@
1
- import { getSortedMessages, setNestedProperty } from '../../utils.js';
1
+ import { getSortedMessages, setNestedProperty, isForbiddenObjectKey } from '../../utils.js';
2
2
  import { defineCodec } from '../ExtractorCodec.js';
3
3
 
4
4
  var JSONCodec = defineCodec(() => ({
@@ -27,6 +27,9 @@ var JSONCodec = defineCodec(() => ({
27
27
  function traverseMessages(obj, callback, path = '') {
28
28
  const NAMESPACE_SEPARATOR = '.';
29
29
  for (const key of Object.keys(obj)) {
30
+ if (isForbiddenObjectKey(key)) {
31
+ throw new Error(`Invalid message catalog key: \`${key}\`.`);
32
+ }
30
33
  const newPath = path ? path + NAMESPACE_SEPARATOR + key : key;
31
34
  const value = obj[key];
32
35
  if (typeof value === 'string') {
@@ -5,15 +5,24 @@ function normalizePathToPosix(filePath) {
5
5
  // always use POSIX separators, regardless of the OS that ran extraction.
6
6
  return path.posix.normalize(filePath.split(path.win32.sep).join(path.posix.sep));
7
7
  }
8
+ const FORBIDDEN_OBJECT_KEYS = new Set(['__proto__', 'constructor', 'prototype']);
9
+ function isForbiddenObjectKey(key) {
10
+ return FORBIDDEN_OBJECT_KEYS.has(key);
11
+ }
8
12
 
9
13
  // Essentialls lodash/set, but we avoid this dependency
10
14
  function setNestedProperty(obj, keyPath, value) {
11
15
  const keys = keyPath.split('.');
16
+ for (const key of keys) {
17
+ if (isForbiddenObjectKey(key)) {
18
+ throw new Error(`Invalid message id segment: ${key}`);
19
+ }
20
+ }
12
21
  let current = obj;
13
22
  for (let i = 0; i < keys.length - 1; i++) {
14
23
  const key = keys[i];
15
- if (!(key in current) || typeof current[key] !== 'object' || current[key] === null) {
16
- current[key] = {};
24
+ if (!Object.prototype.hasOwnProperty.call(current, key) || typeof current[key] !== 'object' || current[key] === null) {
25
+ current[key] = Object.create(null);
17
26
  }
18
27
  current = current[key];
19
28
  }
@@ -43,4 +52,4 @@ function getDefaultProjectRoot() {
43
52
  return process.cwd();
44
53
  }
45
54
 
46
- export { compareReferences, getDefaultProjectRoot, getSortedMessages, localeCompare, normalizePathToPosix, setNestedProperty };
55
+ export { compareReferences, getDefaultProjectRoot, getSortedMessages, isForbiddenObjectKey, localeCompare, normalizePathToPosix, setNestedProperty };
@@ -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
- if (locale !== domainConfig.defaultLocale || routing.localePrefix.mode === 'always') {
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
- if (bestMatchingDomain.defaultLocale === locale && resolvedRouting.localePrefix.mode === 'as-needed') {
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
- const isUnprefixedRouting = resolvedRouting.localePrefix.mode === 'never' || hasMatchedDefaultLocale && resolvedRouting.localePrefix.mode === 'as-needed';
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 (resolvedRouting.localePrefix.mode === 'never') {
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 && resolvedRouting.localePrefix.mode !== 'never' && resolvedRouting.alternateLinks && resolvedRouting.locales.length > 1) {
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.domains ?
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 e from"path";import t from"icu-minify/compile";import{getFormatExtension as s,resolveCodec as o}from"./format/index.js";import{setNestedProperty as r}from"./utils.js";let a=null;const n=new Map;function i(i){const c=this.getOptions(),l=this.async(),f=s(c.messages.format);(async function(e,t){return a||(a=await o(e.messages.format,t)),a})(c,this.rootContext).then((s=>{const o=e.basename(this.resourcePath,f);let a;if(c.messages.precompile){const e=function(e,s){const o={},a=new Set(s.keys());for(const n of e){a.delete(n.id);const e=n.message;if(Array.isArray(e))throw new Error(`Message at \`${n.id}\` resolved to an array, but only strings are supported. See https://next-intl.dev/docs/usage/translations#arrays-of-messages`);if("object"==typeof e)throw new Error(`Message at \`${n.id}\` resolved to \`${typeof e}\`, but only strings are supported. Use a \`.\` to retrieve nested messages. See https://next-intl.dev/docs/usage/translations#structuring-messages`);const i=s.get(n.id);let c;i?.messageValue===e?c=i.compiledMessage:(c=t(e),s.set(n.id,{compiledMessage:c,messageValue:e})),r(o,n.id,c)}for(const e of a)s.delete(e);return o}(s.decode(i,{locale:o}),function(e){let t=n.get(e);return t||(t=new Map,n.set(e,t)),t}(this.resourcePath));a=JSON.stringify(e)}else a=s.toJSONString(i,{locale:o});const m=`export default JSON.parse(${JSON.stringify(a)});`;l(null,m)})).catch(l)}export{i as default};
1
+ import e from"path";import t from"icu-minify/compile";import{getFormatExtension as s,resolveCodec as o}from"./format/index.js";import{setNestedProperty as r}from"./utils.js";let a=null;const n=new Map;function i(i){const c=this.getOptions(),l=this.async(),f=s(c.messages.format);(async function(e,t){return a||(a=await o(e.messages.format,t)),a})(c,this.rootContext).then((s=>{const o=e.basename(this.resourcePath,f);let a;if(c.messages.precompile){const e=function(e,s){const o=Object.create(null),a=new Set(s.keys());for(const n of e){a.delete(n.id);const e=n.message;if(Array.isArray(e))throw new Error(`Message at \`${n.id}\` resolved to an array, but only strings are supported. See https://next-intl.dev/docs/usage/translations#arrays-of-messages`);if("object"==typeof e)throw new Error(`Message at \`${n.id}\` resolved to \`${typeof e}\`, but only strings are supported. Use a \`.\` to retrieve nested messages. See https://next-intl.dev/docs/usage/translations#structuring-messages`);const i=s.get(n.id);let c;i?.messageValue===e?c=i.compiledMessage:(c=t(e),s.set(n.id,{compiledMessage:c,messageValue:e})),r(o,n.id,c)}for(const e of a)s.delete(e);return o}(s.decode(i,{locale:o}),function(e){let t=n.get(e);return t||(t=new Map,n.set(e,t)),t}(this.resourcePath));a=JSON.stringify(e)}else a=s.toJSONString(i,{locale:o});const m=`export default JSON.parse(${JSON.stringify(a)});`;l(null,m)})).catch(l)}export{i as default};
@@ -1 +1 @@
1
- import{getSortedMessages as e,setNestedProperty as r}from"../../utils.js";import{defineCodec as s}from"../ExtractorCodec.js";var t=s((()=>({decode(e){const r=JSON.parse(e),s=[];return o(r,((e,r)=>{s.push({id:r,message:e})})),s},encode(s){const t={};for(const o of e(s))r(t,o.id,o.message);return JSON.stringify(t,null,2)+"\n"},toJSONString:e=>e})));function o(e,r,s=""){for(const t of Object.keys(e)){const n=s?s+"."+t:t,a=e[t];if("string"==typeof a)r(a,n);else{if(Array.isArray(a))throw new Error(`Message at \`${n}\` resolved to an array, but only strings are supported. See https://next-intl.dev/docs/usage/translations#arrays-of-messages`);"object"==typeof a&&o(a,r,n)}}}export{t as default};
1
+ import{getSortedMessages as e,setNestedProperty as r,isForbiddenObjectKey as s}from"../../utils.js";import{defineCodec as t}from"../ExtractorCodec.js";var o=t((()=>({decode(e){const r=JSON.parse(e),s=[];return a(r,((e,r)=>{s.push({id:r,message:e})})),s},encode(s){const t={};for(const o of e(s))r(t,o.id,o.message);return JSON.stringify(t,null,2)+"\n"},toJSONString:e=>e})));function a(e,r,t=""){for(const o of Object.keys(e)){if(s(o))throw new Error(`Invalid message catalog key: \`${o}\`.`);const n=t?t+"."+o:o,i=e[o];if("string"==typeof i)r(i,n);else{if(Array.isArray(i))throw new Error(`Message at \`${n}\` resolved to an array, but only strings are supported. See https://next-intl.dev/docs/usage/translations#arrays-of-messages`);"object"==typeof i&&a(i,r,n)}}}export{o as default};
@@ -1 +1 @@
1
- import n from"path";function e(e){return n.posix.normalize(e.split(n.win32.sep).join(n.posix.sep))}function t(n,e,t){const o=e.split(".");let r=n;for(let n=0;n<o.length-1;n++){const e=o[n];e in r&&"object"==typeof r[e]&&null!==r[e]||(r[e]={}),r=r[e]}r[o[o.length-1]]=t}function o(n){return n.toSorted(((n,e)=>{const t=n.references?.[0],o=e.references?.[0];return t&&o?i(t,o):0}))}function r(n,e){return n.localeCompare(e,"en")}function i(n,e){const t=r(n.path,e.path);return 0!==t?t:(n.line??0)-(e.line??0)}function c(){return process.cwd()}export{i as compareReferences,c as getDefaultProjectRoot,o as getSortedMessages,r as localeCompare,e as normalizePathToPosix,t as setNestedProperty};
1
+ import t from"path";function e(e){return t.posix.normalize(e.split(t.win32.sep).join(t.posix.sep))}const n=new Set(["__proto__","constructor","prototype"]);function o(t){return n.has(t)}function r(t,e,n){const r=e.split(".");for(const t of r)if(o(t))throw new Error(`Invalid message id segment: ${t}`);let c=t;for(let t=0;t<r.length-1;t++){const e=r[t];Object.prototype.hasOwnProperty.call(c,e)&&"object"==typeof c[e]&&null!==c[e]||(c[e]=Object.create(null)),c=c[e]}c[r[r.length-1]]=n}function c(t){return t.toSorted(((t,e)=>{const n=t.references?.[0],o=e.references?.[0];return n&&o?i(n,o):0}))}function s(t,e){return t.localeCompare(e,"en")}function i(t,e){const n=s(t.path,e.path);return 0!==n?n:(t.line??0)-(e.line??0)}function p(){return process.cwd()}export{i as compareReferences,p as getDefaultProjectRoot,c as getSortedMessages,o as isForbiddenObjectKey,s as localeCompare,e as normalizePathToPosix,r as setNestedProperty};
@@ -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:m,request:i,resolvedLocale:p,routing:c}){const f=i.nextUrl.clone(),h=a(i.headers);function u(a,t){return a.pathname=e(a.pathname),i.nextUrl.basePath&&((a=new URL(a)).pathname=r(a.pathname,i.nextUrl.basePath)),`<${a.toString()}>; rel="alternate"; hreflang="${t}"`}function d(e,a){if(m&&"object"==typeof m){const t=m[p];return l(e,t??s,m[a]??s)}return e}h&&(f.port="",f.host=h),f.protocol=i.headers.get("x-forwarded-proto")??f.protocol,f.pathname=t(f.pathname,c.locales,c.localePrefix);const x=n(c.locales,c.localePrefix,!1).flatMap((([e,a])=>{function t(e){return"/"===e?a:a+e}let n;if(c.domains){return c.domains.filter((a=>o(e,a))).map((a=>(n=new URL(f),n.port="",n.host=a.domain,n.pathname=d(f.pathname,e),e===a.defaultLocale&&"always"!==c.localePrefix.mode||(n.pathname=t(n.pathname)),u(n,e))))}{let a;a=m&&"object"==typeof m?d(f.pathname,e):f.pathname,e===c.defaultLocale&&"always"!==c.localePrefix.mode||(a=t(a)),n=new URL(a,f)}return u(n,e)}));if(!c.domains||0===c.domains.length){const e=d(f.pathname,c.defaultLocale);if(e){const a=new URL(e,f);x.push(u(a,"x-default"))}}return x.join(", ")}export{s as default};
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 l,getLocalizedTemplate as n}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 l=new URL(a,t.url);t.nextUrl.basePath&&(l.pathname=P(l.pathname,t.nextUrl.basePath));const n=new Headers(t.headers);n.set(r,k);return o(t.nextUrl.pathname)!==o(l.pathname)?e.rewrite(l,{request:{headers:n}}):e.next({request:{headers:n}})}function H(r,a){const l=new URL(r,t.url);if(l.pathname=o(l.pathname),q.length>0&&!a&&w){const e=U(w,k,q);e&&(a=e.domain,e.defaultLocale===k&&"as-needed"===L.localePrefix.mode&&(l.pathname=m(l.pathname,L.locales,L.localePrefix)))}if(a&&(l.host=a,t.headers.get("x-forwarded-host"))){l.protocol=t.headers.get("x-forwarded-proto")??t.nextUrl.protocol;const e=a.split(":")[1];l.port=e??t.headers.get("x-forwarded-port")??""}return t.nextUrl.basePath&&(l.pathname=P(l.pathname,t.nextUrl.basePath)),T=!0,e.redirect(l.toString())}const z=m(j,L.locales,L.localePrefix),A=h(j,L.locales,L.localePrefix,w),C=null!=A,I="never"===L.localePrefix.mode||b&&"as-needed"===L.localePrefix.mode;let N,S,T,V=z;const B=L.pathnames;if(B){let e;if([e,S]=x(B,z,k),S){const r=B[S],o=n(r,k,S);if(a(o,z))V=p(z,o,S);else{let a;a=e?n(r,e,S):S;const s=I?void 0:l(k,L.localePrefix),i=p(z,a,o);N=H(u(i,s,t.nextUrl.search))}}}if(!N)if("/"!==V||C){const e=u(V,g(k),t.nextUrl.search);if(C){const r=u(z,A.prefix,t.nextUrl.search);if("never"===L.localePrefix.mode)N=H(u(z,void 0,t.nextUrl.search));else if(A.exact)if(b&&I)N=H(u(z,void 0,t.nextUrl.search));else if(L.domains){const t=U(w,A.locale,q);N=w?.domain===t?.domain||R?y(e):H(r,t?.domain)}else N=y(e);else N=H(r)}else N=I?y(e):H(u(z,l(k,L.localePrefix),t.nextUrl.search))}else N=I?y(u(V,g(k),t.nextUrl.search)):H(u(z,l(k,L.localePrefix),t.nextUrl.search));return c(t,N,k,L,w),!T&&"never"!==L.localePrefix.mode&&L.alternateLinks&&L.locales.length>1&&N.headers.set("Link",s({routing:L,internalTemplateName:S,localizedPathnames:null!=S&&B?B[S]:void 0,request:t,resolvedLocale:k})),N}}export{v as default};
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 u(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 l(e,n=window.location.pathname){return"/"===e?n:n.replace(e,"")}function p(e,n,o,a){const{mode:c}=o.localePrefix;let s;return void 0!==a?s=a:t(e)&&("always"===c?s=!0:"as-needed"===c&&(s=o.domains?!o.domains.some((e=>e.defaultLocale===n)):n!==o.defaultLocale)),s?r(i(n,o.localePrefix),e):e}export{p as applyPathnamePrefix,f as compileLocalizedPathname,l as getBasePath,u as getRoute,c as normalizeNameOrNameWithParams,s as serializeSearchParams};
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};
@@ -1,5 +1,6 @@
1
1
  import type { ExtractorMessage, ExtractorMessageReference } from './types.js';
2
2
  export declare function normalizePathToPosix(filePath: string): string;
3
+ export declare function isForbiddenObjectKey(key: string): boolean;
3
4
  export declare function setNestedProperty(obj: Record<string, any>, keyPath: string, value: any): void;
4
5
  export declare function getSortedMessages(messages: Array<ExtractorMessage>): Array<ExtractorMessage>;
5
6
  export declare function localeCompare(a: string, b: string): number;
@@ -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.9.1",
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.9.1",
130
+ "icu-minify": "^4.10.0",
131
131
  "negotiator": "^1.0.0",
132
- "next-intl-swc-plugin-extractor": "^4.9.1",
132
+ "next-intl-swc-plugin-extractor": "^4.10.0",
133
133
  "po-parser": "^2.1.1",
134
- "use-intl": "^4.9.1"
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": "b4aa5380c50ad59a80d1dfdbc229590a4e0133a3"
145
+ "gitHead": "d4648b884c609400b53da58ab0def5feb22ab654"
146
146
  }