next-intl 4.5.1 → 4.5.2

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.
@@ -107,10 +107,28 @@ export default messages;`;
107
107
 
108
108
  class SourceFileFilter {
109
109
  static EXTENSIONS = ['ts', 'tsx', 'js', 'jsx'];
110
+
111
+ // Will not be entered, except if explicitly asked for
112
+ // TODO: At some point we should infer these from .gitignore
113
+ static IGNORED_DIRECTORIES = ['node_modules', '.next', '.git'];
110
114
  static isSourceFile(filePath) {
111
115
  const ext = path.extname(filePath);
112
116
  return SourceFileFilter.EXTENSIONS.map(cur => '.' + cur).includes(ext);
113
117
  }
118
+ static shouldEnterDirectory(dirPath, srcPaths) {
119
+ const dirName = path.basename(dirPath);
120
+ if (SourceFileFilter.IGNORED_DIRECTORIES.includes(dirName)) {
121
+ return SourceFileFilter.isIgnoredDirectoryExplicitlyIncluded(dirPath, srcPaths);
122
+ }
123
+ return true;
124
+ }
125
+ static isIgnoredDirectoryExplicitlyIncluded(ignoredDirPath, srcPaths) {
126
+ return srcPaths.some(srcPath => SourceFileFilter.isWithinPath(srcPath, ignoredDirPath));
127
+ }
128
+ static isWithinPath(targetPath, basePath) {
129
+ const relativePath = path.relative(basePath, targetPath);
130
+ return relativePath === '' || !relativePath.startsWith('..');
131
+ }
114
132
  }
115
133
 
116
134
  function getCurrentVersion() {
@@ -238,12 +256,13 @@ function getNextConfig(pluginConfig, nextConfig) {
238
256
  throwError('Message extraction requires Next.js 16 or higher.');
239
257
  }
240
258
  rules ??= getTurboRules();
259
+ const srcPaths = (Array.isArray(pluginConfig.experimental.srcPath) ? pluginConfig.experimental.srcPath : [pluginConfig.experimental.srcPath]).map(srcPath => srcPath.endsWith('/') ? srcPath.slice(0, -1) : srcPath);
241
260
  addTurboRule(rules, `*.{${SourceFileFilter.EXTENSIONS.join(',')}}`, {
242
261
  loaders: [getExtractMessagesLoaderConfig()],
243
262
  condition: {
244
263
  // Note: We don't need `not: 'foreign'`, because this is
245
264
  // implied by the filter based on `srcPath`.
246
- path: (Array.isArray(pluginConfig.experimental.srcPath) ? `{${pluginConfig.experimental.srcPath.join(',')}}` : pluginConfig.experimental.srcPath) + '/**/*',
265
+ path: `{${srcPaths.join(',')}}` + '/**/*',
247
266
  content: /(useExtracted|getExtracted)/
248
267
  }
249
268
  });
@@ -137,6 +137,7 @@ class CatalogManager {
137
137
  references.push(ref);
138
138
  }
139
139
  });
140
+ references.sort((referenceA, referenceB) => referenceA.path.localeCompare(referenceB.path));
140
141
  message = {
141
142
  ...message,
142
143
  references
@@ -2,10 +2,28 @@ import path from 'path';
2
2
 
3
3
  class SourceFileFilter {
4
4
  static EXTENSIONS = ['ts', 'tsx', 'js', 'jsx'];
5
+
6
+ // Will not be entered, except if explicitly asked for
7
+ // TODO: At some point we should infer these from .gitignore
8
+ static IGNORED_DIRECTORIES = ['node_modules', '.next', '.git'];
5
9
  static isSourceFile(filePath) {
6
10
  const ext = path.extname(filePath);
7
11
  return SourceFileFilter.EXTENSIONS.map(cur => '.' + cur).includes(ext);
8
12
  }
13
+ static shouldEnterDirectory(dirPath, srcPaths) {
14
+ const dirName = path.basename(dirPath);
15
+ if (SourceFileFilter.IGNORED_DIRECTORIES.includes(dirName)) {
16
+ return SourceFileFilter.isIgnoredDirectoryExplicitlyIncluded(dirPath, srcPaths);
17
+ }
18
+ return true;
19
+ }
20
+ static isIgnoredDirectoryExplicitlyIncluded(ignoredDirPath, srcPaths) {
21
+ return srcPaths.some(srcPath => SourceFileFilter.isWithinPath(srcPath, ignoredDirPath));
22
+ }
23
+ static isWithinPath(targetPath, basePath) {
24
+ const relativePath = path.relative(basePath, targetPath);
25
+ return relativePath === '' || !relativePath.startsWith('..');
26
+ }
9
27
  }
10
28
 
11
29
  export { SourceFileFilter as default };
@@ -10,6 +10,9 @@ class SourceFileScanner {
10
10
  for (const entry of entries) {
11
11
  const entryPath = path.join(dir, entry.name);
12
12
  if (entry.isDirectory()) {
13
+ if (!SourceFileFilter.shouldEnterDirectory(entryPath, srcPaths)) {
14
+ continue;
15
+ }
13
16
  await SourceFileScanner.walkSourceFiles(entryPath, srcPaths, acc);
14
17
  } else {
15
18
  if (SourceFileFilter.isSourceFile(entry.name)) {
@@ -100,12 +100,13 @@ function getNextConfig(pluginConfig, nextConfig) {
100
100
  throwError('Message extraction requires Next.js 16 or higher.');
101
101
  }
102
102
  rules ??= getTurboRules();
103
+ const srcPaths = (Array.isArray(pluginConfig.experimental.srcPath) ? pluginConfig.experimental.srcPath : [pluginConfig.experimental.srcPath]).map(srcPath => srcPath.endsWith('/') ? srcPath.slice(0, -1) : srcPath);
103
104
  addTurboRule(rules, `*.{${SourceFileFilter.EXTENSIONS.join(',')}}`, {
104
105
  loaders: [getExtractMessagesLoaderConfig()],
105
106
  condition: {
106
107
  // Note: We don't need `not: 'foreign'`, because this is
107
108
  // implied by the filter based on `srcPath`.
108
- path: (Array.isArray(pluginConfig.experimental.srcPath) ? `{${pluginConfig.experimental.srcPath.join(',')}}` : pluginConfig.experimental.srcPath) + '/**/*',
109
+ path: `{${srcPaths.join(',')}}` + '/**/*',
109
110
  content: /(useExtracted|getExtracted)/
110
111
  }
111
112
  });
@@ -1 +1 @@
1
- import e from"fs/promises";import s from"path";import t from"../extractor/MessageExtractor.js";import a from"../formatters/index.js";import i from"../source/SourceFileScanner.js";import r from"./CatalogLocales.js";import o from"./CatalogPersister.js";import c from"./SaveScheduler.js";class n{messagesByFile=(()=>new Map)();messagesById=(()=>new Map)();translationsByTargetLocale=(()=>new Map)();lastWriteByLocale=(()=>new Map)();constructor(e,s={}){this.config=e,this.saveScheduler=new c(50),this.projectRoot=s.projectRoot||process.cwd(),this.isDevelopment=s.isDevelopment??!1,this.messageExtractor=new t({isDevelopment:this.isDevelopment,projectRoot:this.projectRoot})}async getFormatter(){if(this.formatter)return this.formatter;{const e=(await a[this.config.messages.format]()).default;return this.formatter=new e,this.formatter}}async getPersister(){return this.persister||(this.persister=new o(this.config.messages.path,await this.getFormatter())),this.persister}async getCatalogLocales(){if(this.catalogLocales)return this.catalogLocales;{const e=s.join(this.projectRoot,this.config.messages.path),t=await this.getFormatter();return this.catalogLocales=new r({messagesDir:e,sourceLocale:this.config.sourceLocale,extension:t.EXTENSION,locales:this.config.messages.locales}),this.catalogLocales}}async getTargetLocales(){return(await this.getCatalogLocales()).getTargetLocales()}getSrcPaths(){return(Array.isArray(this.config.srcPath)?this.config.srcPath:[this.config.srcPath]).map((e=>s.join(this.projectRoot,e)))}getFileMessages(e){return this.messagesByFile.get(e)}async loadMessages(){if(await this.loadSourceMessages(),await this.loadTargetMessages(),this.isDevelopment){(await this.getCatalogLocales()).subscribeLocalesChange(this.onLocalesChange)}}async loadSourceMessages(){await this.loadLocaleMessages(this.config.sourceLocale);const s=await i.getSourceFiles(this.getSrcPaths());await Promise.all(s.map((async s=>this.extractFileMessages(s,await e.readFile(s,"utf8")))))}async loadLocaleMessages(e){const s=await this.getPersister();try{const t=await s.read(e),a=await s.getLastModified(e);return this.lastWriteByLocale.set(e,a),t}catch{return[]}}async loadTargetMessages(){const e=await this.getTargetLocales();await Promise.all(e.map((async e=>{this.translationsByTargetLocale.set(e,new Map);const s=await this.loadLocaleMessages(e);for(const t of s){this.translationsByTargetLocale.get(e).set(t.id,t.message)}})))}async extractFileMessages(e,t){const a=await this.messageExtractor.processFileContent(e,t),i=this.messagesByFile.get(e),r=Array.from(i?.keys()??[]),o=new Map;for(let e of a.messages){const s=this.messagesById.get(e.id);if(s){const t=[...s.references??[]];e.references.forEach((e=>{t.some((s=>s.path===e.path))||t.push(e)})),e={...e,references:t},s.description&&!e.description&&(e={...e,description:s.description})}this.messagesById.set(e.id,e),o.set(e.id,e);const t=r.indexOf(e.id);-1!==t&&r.splice(t,1)}const c=s.relative(this.projectRoot,e);r.filter((e=>{const s=this.messagesById.get(e);return!s?.references?.some((e=>e.path!==c))})).forEach((e=>{this.messagesById.delete(e)}));a.messages.length>0?this.messagesByFile.set(e,o):this.messagesByFile.delete(e);const n=this.haveMessagesChanged(i,o);return{...a,changed:n}}haveMessagesChanged(e,s){if(!e)return s.size>0;if(e.size!==s.size)return!0;for(const[t,a]of e){const e=s.get(t);if(!e||!this.areMessagesEqual(a,e))return!0}return!1}areMessagesEqual(e,s){return e.id===s.id&&e.message===s.message&&e.description===s.description&&this.areReferencesEqual(e.references,s.references)}areReferencesEqual(e,s){if(!e&&!s)return!0;if(!e||!s)return!1;if(e.length!==s.length)return!1;for(let t=0;t<e.length;t++)if(e[t].path!==s[t].path)return!1;return!0}async save(){return this.saveScheduler.schedule((()=>this.saveImpl()))}async saveImpl(){const e=Array.from(this.messagesById.values()),s=await this.getPersister();await s.write(this.config.sourceLocale,e);for(const e of await this.getTargetLocales())await this.saveLocale(e);return e.length}async saveLocale(e){const s=Array.from(this.messagesById.values()),t=await this.getPersister(),a=this.lastWriteByLocale.get(e),i=await t.getLastModified(e);if(i&&a&&i>a){const s=await t.read(e),a=this.translationsByTargetLocale.get(e);for(const e of s)a.set(e.id,e.message)}const r=this.translationsByTargetLocale.get(e),o=s.map((e=>({...e,message:r.get(e.id)||""})));await t.write(e,o);const c=await t.getLastModified(e);this.lastWriteByLocale.set(e,c)}onLocalesChange=async e=>{for(const s of e.added){const e=new Map;this.translationsByTargetLocale.set(s,e);const t=await this.loadLocaleMessages(s);for(const s of t)e.set(s.id,s.message);await this.saveLocale(s)}for(const s of e.removed)this.translationsByTargetLocale.delete(s),this.lastWriteByLocale.delete(s)};destroy(){this.saveScheduler.destroy(),this.catalogLocales&&this.isDevelopment&&this.catalogLocales.unsubscribeLocalesChange(this.onLocalesChange)}}export{n as default};
1
+ import e from"fs/promises";import s from"path";import t from"../extractor/MessageExtractor.js";import a from"../formatters/index.js";import o from"../source/SourceFileScanner.js";import r from"./CatalogLocales.js";import i from"./CatalogPersister.js";import c from"./SaveScheduler.js";class n{messagesByFile=(()=>new Map)();messagesById=(()=>new Map)();translationsByTargetLocale=(()=>new Map)();lastWriteByLocale=(()=>new Map)();constructor(e,s={}){this.config=e,this.saveScheduler=new c(50),this.projectRoot=s.projectRoot||process.cwd(),this.isDevelopment=s.isDevelopment??!1,this.messageExtractor=new t({isDevelopment:this.isDevelopment,projectRoot:this.projectRoot})}async getFormatter(){if(this.formatter)return this.formatter;{const e=(await a[this.config.messages.format]()).default;return this.formatter=new e,this.formatter}}async getPersister(){return this.persister||(this.persister=new i(this.config.messages.path,await this.getFormatter())),this.persister}async getCatalogLocales(){if(this.catalogLocales)return this.catalogLocales;{const e=s.join(this.projectRoot,this.config.messages.path),t=await this.getFormatter();return this.catalogLocales=new r({messagesDir:e,sourceLocale:this.config.sourceLocale,extension:t.EXTENSION,locales:this.config.messages.locales}),this.catalogLocales}}async getTargetLocales(){return(await this.getCatalogLocales()).getTargetLocales()}getSrcPaths(){return(Array.isArray(this.config.srcPath)?this.config.srcPath:[this.config.srcPath]).map((e=>s.join(this.projectRoot,e)))}getFileMessages(e){return this.messagesByFile.get(e)}async loadMessages(){if(await this.loadSourceMessages(),await this.loadTargetMessages(),this.isDevelopment){(await this.getCatalogLocales()).subscribeLocalesChange(this.onLocalesChange)}}async loadSourceMessages(){await this.loadLocaleMessages(this.config.sourceLocale);const s=await o.getSourceFiles(this.getSrcPaths());await Promise.all(s.map((async s=>this.extractFileMessages(s,await e.readFile(s,"utf8")))))}async loadLocaleMessages(e){const s=await this.getPersister();try{const t=await s.read(e),a=await s.getLastModified(e);return this.lastWriteByLocale.set(e,a),t}catch{return[]}}async loadTargetMessages(){const e=await this.getTargetLocales();await Promise.all(e.map((async e=>{this.translationsByTargetLocale.set(e,new Map);const s=await this.loadLocaleMessages(e);for(const t of s){this.translationsByTargetLocale.get(e).set(t.id,t.message)}})))}async extractFileMessages(e,t){const a=await this.messageExtractor.processFileContent(e,t),o=this.messagesByFile.get(e),r=Array.from(o?.keys()??[]),i=new Map;for(let e of a.messages){const s=this.messagesById.get(e.id);if(s){const t=[...s.references??[]];e.references.forEach((e=>{t.some((s=>s.path===e.path))||t.push(e)})),t.sort(((e,s)=>e.path.localeCompare(s.path))),e={...e,references:t},s.description&&!e.description&&(e={...e,description:s.description})}this.messagesById.set(e.id,e),i.set(e.id,e);const t=r.indexOf(e.id);-1!==t&&r.splice(t,1)}const c=s.relative(this.projectRoot,e);r.filter((e=>{const s=this.messagesById.get(e);return!s?.references?.some((e=>e.path!==c))})).forEach((e=>{this.messagesById.delete(e)}));a.messages.length>0?this.messagesByFile.set(e,i):this.messagesByFile.delete(e);const n=this.haveMessagesChanged(o,i);return{...a,changed:n}}haveMessagesChanged(e,s){if(!e)return s.size>0;if(e.size!==s.size)return!0;for(const[t,a]of e){const e=s.get(t);if(!e||!this.areMessagesEqual(a,e))return!0}return!1}areMessagesEqual(e,s){return e.id===s.id&&e.message===s.message&&e.description===s.description&&this.areReferencesEqual(e.references,s.references)}areReferencesEqual(e,s){if(!e&&!s)return!0;if(!e||!s)return!1;if(e.length!==s.length)return!1;for(let t=0;t<e.length;t++)if(e[t].path!==s[t].path)return!1;return!0}async save(){return this.saveScheduler.schedule((()=>this.saveImpl()))}async saveImpl(){const e=Array.from(this.messagesById.values()),s=await this.getPersister();await s.write(this.config.sourceLocale,e);for(const e of await this.getTargetLocales())await this.saveLocale(e);return e.length}async saveLocale(e){const s=Array.from(this.messagesById.values()),t=await this.getPersister(),a=this.lastWriteByLocale.get(e),o=await t.getLastModified(e);if(o&&a&&o>a){const s=await t.read(e),a=this.translationsByTargetLocale.get(e);for(const e of s)a.set(e.id,e.message)}const r=this.translationsByTargetLocale.get(e),i=s.map((e=>({...e,message:r.get(e.id)||""})));await t.write(e,i);const c=await t.getLastModified(e);this.lastWriteByLocale.set(e,c)}onLocalesChange=async e=>{for(const s of e.added){const e=new Map;this.translationsByTargetLocale.set(s,e);const t=await this.loadLocaleMessages(s);for(const s of t)e.set(s.id,s.message);await this.saveLocale(s)}for(const s of e.removed)this.translationsByTargetLocale.delete(s),this.lastWriteByLocale.delete(s)};destroy(){this.saveScheduler.destroy(),this.catalogLocales&&this.isDevelopment&&this.catalogLocales.unsubscribeLocalesChange(this.onLocalesChange)}}export{n as default};
@@ -1 +1 @@
1
- import t from"path";class s{static EXTENSIONS=["ts","tsx","js","jsx"];static isSourceFile(a){const e=t.extname(a);return s.EXTENSIONS.map((t=>"."+t)).includes(e)}}export{s as default};
1
+ import t from"path";class i{static EXTENSIONS=["ts","tsx","js","jsx"];static IGNORED_DIRECTORIES=["node_modules",".next",".git"];static isSourceFile(s){const e=t.extname(s);return i.EXTENSIONS.map((t=>"."+t)).includes(e)}static shouldEnterDirectory(s,e){const r=t.basename(s);return!i.IGNORED_DIRECTORIES.includes(r)||i.isIgnoredDirectoryExplicitlyIncluded(s,e)}static isIgnoredDirectoryExplicitlyIncluded(t,s){return s.some((s=>i.isWithinPath(s,t)))}static isWithinPath(i,s){const e=t.relative(s,i);return""===e||!e.startsWith("..")}}export{i as default};
@@ -1 +1 @@
1
- import e from"fs/promises";import r from"path";import i from"./SourceFileFilter.js";class a{static async walkSourceFiles(s,t,o=[]){const l=await e.readdir(s,{withFileTypes:!0});for(const e of l){const l=r.join(s,e.name);e.isDirectory()?await a.walkSourceFiles(l,t,o):i.isSourceFile(e.name)&&o.push(l)}return o}static async getSourceFiles(e){return(await Promise.all(e.map((r=>a.walkSourceFiles(r,e))))).flat()}}export{a as default};
1
+ import e from"fs/promises";import i from"path";import r from"./SourceFileFilter.js";class t{static async walkSourceFiles(o,s,a=[]){const l=await e.readdir(o,{withFileTypes:!0});for(const e of l){const l=i.join(o,e.name);if(e.isDirectory()){if(!r.shouldEnterDirectory(l,s))continue;await t.walkSourceFiles(l,s,a)}else r.isSourceFile(e.name)&&a.push(l)}return a}static async getSourceFiles(e){return(await Promise.all(e.map((i=>t.walkSourceFiles(i,e))))).flat()}}export{t as default};
@@ -1 +1 @@
1
- import e from"fs";import t from"path";import r from"../extractor/source/SourceFileFilter.js";import{isNextJs16OrHigher as s,hasStableTurboConfig as n}from"./nextFlags.js";import{throwError as o}from"./utils.js";function a(e){return[`${e}.ts`,`${e}.tsx`,`${e}.js`,`${e}.jsx`]}function i(r,s){function n(r){return e.existsSync(function(e){const r=[];return s&&r.push(s),r.push(e),t.resolve(...r)}(r))}if(r)return n(r)||o(`Could not find i18n config at ${r}, please provide a valid path.`),r;for(const e of[...a("./i18n/request"),...a("./src/i18n/request")])if(n(e))return e;o("Could not locate request configuration module.\n\nThis path is supported by default: ./(src/)i18n/request.{js,jsx,ts,tsx}\n\nAlternatively, you can specify a custom location in your Next.js config:\n\nconst withNextIntl = createNextIntlPlugin(\n\nAlternatively, you can specify a custom location in your Next.js config:\n\nconst withNextIntl = createNextIntlPlugin(\n './path/to/i18n/request.tsx'\n);")}function l(e,a){const l={};function u(){const t=e.experimental;return t.srcPath&&t.messages||o("`srcPath` and `messages` are required when using `extractor`."),{loader:"next-intl/extractor/extractionLoader",options:{srcPath:t.srcPath,sourceLocale:t.extract.sourceLocale,messages:t.messages}}}function c(){return{loader:"next-intl/extractor/catalogLoader",options:{messages:e.experimental.messages}}}function p(){return a?.turbopack?.rules||a?.experimental?.turbo?.rules||{}}function x(e,t,r){e[t]?Array.isArray(e[t])?e[t].push(r):e[t]=[e[t],r]:e[t]=r}if(null!=process.env.TURBOPACK){e.requestConfig&&t.isAbsolute(e.requestConfig)&&o("Turbopack support for next-intl currently does not support absolute paths, please provide a relative one (e.g. './src/i18n/config.ts').\n\nFound: "+e.requestConfig);const m={"next-intl/config":i(e.requestConfig)};let f;e.experimental?.extract&&(s()||o("Message extraction requires Next.js 16 or higher."),f??=p(),x(f,`*.{${r.EXTENSIONS.join(",")}}`,{loaders:[u()],condition:{path:(Array.isArray(e.experimental.srcPath)?`{${e.experimental.srcPath.join(",")}}`:e.experimental.srcPath)+"/**/*",content:/(useExtracted|getExtracted)/}})),e.experimental?.messages&&(s()||o("Message catalog loading requires Next.js 16 or higher."),f??=p(),x(f,`*.${e.experimental.messages.format}`,{loaders:[c()],condition:{path:`${e.experimental.messages.path}/**/*`},as:"*.js"})),n()&&!a?.experimental?.turbo?l.turbopack={...a?.turbopack,...f&&{rules:f},resolveAlias:{...a?.turbopack?.resolveAlias,...m}}:l.experimental={...a?.experimental,turbo:{...a?.experimental?.turbo,...f&&{rules:f},resolveAlias:{...a?.experimental?.turbo?.resolveAlias,...m}}}}else l.webpack=function(s,n){if(s.resolve||(s.resolve={}),s.resolve.alias||(s.resolve.alias={}),s.resolve.alias["next-intl/config"]=t.resolve(s.context,i(e.requestConfig,s.context)),e.experimental?.extract){s.module||(s.module={}),s.module.rules||(s.module.rules=[]);const n=e.experimental.srcPath;s.module.rules.push({test:new RegExp(`\\.(${r.EXTENSIONS.join("|")})$`),include:Array.isArray(n)?n.map((e=>t.resolve(s.context,e))):t.resolve(s.context,n||""),use:[u()]})}return e.experimental?.messages&&(s.module||(s.module={}),s.module.rules||(s.module.rules=[]),s.module.rules.push({test:new RegExp(`\\.${e.experimental.messages.format}$`),include:t.resolve(s.context,e.experimental.messages.path),use:[c()],type:"javascript/auto"})),"function"==typeof a?.webpack?a.webpack(s,n):s};return a?.trailingSlash&&(l.env={...a.env,_next_intl_trailing_slash:"true"}),Object.assign({},a,l)}export{l as default};
1
+ import e from"fs";import t from"path";import r from"../extractor/source/SourceFileFilter.js";import{isNextJs16OrHigher as s,hasStableTurboConfig as n}from"./nextFlags.js";import{throwError as o}from"./utils.js";function a(e){return[`${e}.ts`,`${e}.tsx`,`${e}.js`,`${e}.jsx`]}function i(r,s){function n(r){return e.existsSync(function(e){const r=[];return s&&r.push(s),r.push(e),t.resolve(...r)}(r))}if(r)return n(r)||o(`Could not find i18n config at ${r}, please provide a valid path.`),r;for(const e of[...a("./i18n/request"),...a("./src/i18n/request")])if(n(e))return e;o("Could not locate request configuration module.\n\nThis path is supported by default: ./(src/)i18n/request.{js,jsx,ts,tsx}\n\nAlternatively, you can specify a custom location in your Next.js config:\n\nconst withNextIntl = createNextIntlPlugin(\n\nAlternatively, you can specify a custom location in your Next.js config:\n\nconst withNextIntl = createNextIntlPlugin(\n './path/to/i18n/request.tsx'\n);")}function l(e,a){const l={};function u(){const t=e.experimental;return t.srcPath&&t.messages||o("`srcPath` and `messages` are required when using `extractor`."),{loader:"next-intl/extractor/extractionLoader",options:{srcPath:t.srcPath,sourceLocale:t.extract.sourceLocale,messages:t.messages}}}function c(){return{loader:"next-intl/extractor/catalogLoader",options:{messages:e.experimental.messages}}}function p(){return a?.turbopack?.rules||a?.experimental?.turbo?.rules||{}}function x(e,t,r){e[t]?Array.isArray(e[t])?e[t].push(r):e[t]=[e[t],r]:e[t]=r}if(null!=process.env.TURBOPACK){e.requestConfig&&t.isAbsolute(e.requestConfig)&&o("Turbopack support for next-intl currently does not support absolute paths, please provide a relative one (e.g. './src/i18n/config.ts').\n\nFound: "+e.requestConfig);const m={"next-intl/config":i(e.requestConfig)};let f;if(e.experimental?.extract){s()||o("Message extraction requires Next.js 16 or higher."),f??=p();const t=(Array.isArray(e.experimental.srcPath)?e.experimental.srcPath:[e.experimental.srcPath]).map((e=>e.endsWith("/")?e.slice(0,-1):e));x(f,`*.{${r.EXTENSIONS.join(",")}}`,{loaders:[u()],condition:{path:`{${t.join(",")}}/**/*`,content:/(useExtracted|getExtracted)/}})}e.experimental?.messages&&(s()||o("Message catalog loading requires Next.js 16 or higher."),f??=p(),x(f,`*.${e.experimental.messages.format}`,{loaders:[c()],condition:{path:`${e.experimental.messages.path}/**/*`},as:"*.js"})),n()&&!a?.experimental?.turbo?l.turbopack={...a?.turbopack,...f&&{rules:f},resolveAlias:{...a?.turbopack?.resolveAlias,...m}}:l.experimental={...a?.experimental,turbo:{...a?.experimental?.turbo,...f&&{rules:f},resolveAlias:{...a?.experimental?.turbo?.resolveAlias,...m}}}}else l.webpack=function(s,n){if(s.resolve||(s.resolve={}),s.resolve.alias||(s.resolve.alias={}),s.resolve.alias["next-intl/config"]=t.resolve(s.context,i(e.requestConfig,s.context)),e.experimental?.extract){s.module||(s.module={}),s.module.rules||(s.module.rules=[]);const n=e.experimental.srcPath;s.module.rules.push({test:new RegExp(`\\.(${r.EXTENSIONS.join("|")})$`),include:Array.isArray(n)?n.map((e=>t.resolve(s.context,e))):t.resolve(s.context,n||""),use:[u()]})}return e.experimental?.messages&&(s.module||(s.module={}),s.module.rules||(s.module.rules=[]),s.module.rules.push({test:new RegExp(`\\.${e.experimental.messages.format}$`),include:t.resolve(s.context,e.experimental.messages.path),use:[c()],type:"javascript/auto"})),"function"==typeof a?.webpack?a.webpack(s,n):s};return a?.trailingSlash&&(l.env={...a.env,_next_intl_trailing_slash:"true"}),Object.assign({},a,l)}export{l as default};
@@ -1,4 +1,8 @@
1
1
  export default class SourceFileFilter {
2
2
  static readonly EXTENSIONS: string[];
3
+ private static readonly IGNORED_DIRECTORIES;
3
4
  static isSourceFile(filePath: string): boolean;
5
+ static shouldEnterDirectory(dirPath: string, srcPaths: Array<string>): boolean;
6
+ private static isIgnoredDirectoryExplicitlyIncluded;
7
+ private static isWithinPath;
4
8
  }
@@ -11,7 +11,7 @@ export type ExtractedMessage = {
11
11
  export type MessagesConfig = {
12
12
  path: string;
13
13
  format: MessagesFormat;
14
- locales: 'infer' | Array<Locale>;
14
+ locales: 'infer' | ReadonlyArray<Locale>;
15
15
  };
16
16
  export type ExtractorConfig = {
17
17
  srcPath: string | Array<string>;
@@ -14,7 +14,7 @@ export type PluginConfig = {
14
14
  /** Defines the format for how your messages are stored. */
15
15
  format: MessagesFormat;
16
16
  /** Either automatically infer the locales based on catalog files in `path` or explicitly define them. */
17
- locales: 'infer' | Array<string>;
17
+ locales: 'infer' | ReadonlyArray<string>;
18
18
  };
19
19
  /** Enables the usage of `useExtracted`, to be used in combination with `srcPath` and `messages`. */
20
20
  extract?: {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "next-intl",
3
- "version": "4.5.1",
3
+ "version": "4.5.2",
4
4
  "sideEffects": false,
5
5
  "author": "Jan Amann <jan@amann.work>",
6
6
  "funding": [
@@ -127,7 +127,7 @@
127
127
  "@formatjs/intl-localematcher": "^0.5.4",
128
128
  "@swc/core": "^1.13.19",
129
129
  "negotiator": "^1.0.0",
130
- "use-intl": "^4.5.1"
130
+ "use-intl": "^4.5.2"
131
131
  },
132
132
  "peerDependencies": {
133
133
  "next": "^12.0.0 || ^13.0.0 || ^14.0.0 || ^15.0.0 || ^16.0.0",
@@ -139,5 +139,5 @@
139
139
  "optional": true
140
140
  }
141
141
  },
142
- "gitHead": "7b3475d6299109a61fc30324d32175a37bfc16c9"
142
+ "gitHead": "56b7de6ac710a633e7880a295b6750b502f24edd"
143
143
  }