next-i18next 16.0.5 → 16.0.6

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/README.md CHANGED
@@ -87,6 +87,25 @@ The `resourceLoader` uses dynamic `import()` which the bundler can trace, ensuri
87
87
 
88
88
  > **Tip**: Import `I18nConfig` from `next-i18next/proxy` (not from `next-i18next`) to keep the config file Edge-safe.
89
89
 
90
+ > **Dev tip — hot-reloading translations**: set `reloadOnPrerender: process.env.NODE_ENV === 'development'` in your config to refetch translations on every render in dev so edits to locale files appear without restarting `next dev`. The flag is automatically a no-op in production, so it is safe to keep in your committed config — custom backends (HTTP, locize, chained) won't be hit per-request in production builds.
91
+ >
92
+ > **Caveat with `import()`-based `resourceLoader`**: dynamic `import()` of JSON is cached at the bundler level and is not reliably re-invalidated by Turbopack/Webpack HMR after the first edit, so hot-reload can stall after one change. For full hot-reload during development, gate your loader so dev uses `fs.readFile` and production keeps bundler-traceable `import()`:
93
+ > ```ts
94
+ > const resourceLoader: I18nConfig['resourceLoader'] =
95
+ > process.env.NODE_ENV === 'development'
96
+ > ? async (lng, ns) => {
97
+ > const fs = await import('fs/promises')
98
+ > const path = await import('path')
99
+ > const content = await fs.readFile(
100
+ > path.resolve(process.cwd(), `app/i18n/locales/${lng}/${ns}.json`),
101
+ > 'utf-8'
102
+ > )
103
+ > return JSON.parse(content)
104
+ > }
105
+ > : (lng, ns) => import(`./app/i18n/locales/${lng}/${ns}.json`)
106
+ > ```
107
+ > Pages Router and the App Router default backend already use `fs` and are unaffected.
108
+
90
109
  ### 4. Proxy
91
110
 
92
111
  Create `proxy.ts` at your project root (Next.js 16+ replaces `middleware.ts` with `proxy.ts`):
@@ -298,13 +317,12 @@ export function LanguageSwitcher() {
298
317
  }
299
318
  ```
300
319
 
301
- The root layout reads the language from `i18n.resolvedLanguage` instead of URL params:
320
+ The root layout reads the language from `getT()` instead of URL params:
302
321
 
303
322
  ```tsx
304
323
  // app/layout.tsx (no [lng] segment)
305
324
  export default async function RootLayout({ children }) {
306
- const { i18n } = await getT()
307
- const lng = i18n.resolvedLanguage
325
+ const { i18n, lng } = await getT()
308
326
  const resources = getResources(i18n)
309
327
 
310
328
  return (
@@ -474,7 +492,7 @@ See [`examples/pages-router-simple`](examples/pages-router-simple), [`examples/p
474
492
 
475
493
  ## Custom i18next Backends
476
494
 
477
- next-i18next supports any i18next backend plugin for loading translations from an API, CDN, or services like [Locize](https://www.locize.com).
495
+ next-i18next supports any i18next backend plugin for loading translations from an API, CDN, or services like [Locize](https://www.locize.com?utm_source=next_i18next_readme&utm_medium=github&utm_campaign=readme).
478
496
 
479
497
  When a custom backend is provided via `use`, next-i18next will **not** add its default resource loader, giving you full control.
480
498
 
@@ -700,7 +718,7 @@ Thanks goes to these wonderful people ([emoji key](https://github.com/kentcdodds
700
718
  <td align="center" valign="top" width="14.28%"><a href="https://isaachinman.com/"><img src="https://avatars.githubusercontent.com/u/10575782?v=4?s=100" width="100px;" alt="Isaac Hinman"/><br /><sub><b>Isaac Hinman</b></sub></a><br /><a href="https://github.com/i18next/next-i18next/commits?author=isaachinman" title="Code">💻</a> <a href="https://github.com/i18next/next-i18next/commits?author=isaachinman" title="Documentation">📖</a> <a href="#ideas-isaachinman" title="Ideas, Planning, & Feedback">🤔</a> <a href="#maintenance-isaachinman" title="Maintenance">🚧</a></td>
701
719
  </tr>
702
720
  <tr>
703
- <td align="center" valign="top" width="14.28%"><a href="https://locize.com/"><img src="https://avatars.githubusercontent.com/u/1086194?v=4?s=100" width="100px;" alt="Adriano Raiano"/><br /><sub><b>Adriano Raiano</b></sub></a><br /><a href="https://github.com/i18next/next-i18next/commits?author=adrai" title="Code">💻</a> <a href="https://github.com/i18next/next-i18next/commits?author=adrai" title="Documentation">📖</a> <a href="#ideas-adrai" title="Ideas, Planning, & Feedback">🤔</a> <a href="#maintenance-adrai" title="Maintenance">🚧</a></td>
721
+ <td align="center" valign="top" width="14.28%"><a href="https://www.locize.com/?utm_source=next_i18next_readme&utm_medium=github&utm_campaign=readme"><img src="https://avatars.githubusercontent.com/u/1086194?v=4?s=100" width="100px;" alt="Adriano Raiano"/><br /><sub><b>Adriano Raiano</b></sub></a><br /><a href="https://github.com/i18next/next-i18next/commits?author=adrai" title="Code">💻</a> <a href="https://github.com/i18next/next-i18next/commits?author=adrai" title="Documentation">📖</a> <a href="#ideas-adrai" title="Ideas, Planning, & Feedback">🤔</a> <a href="#maintenance-adrai" title="Maintenance">🚧</a></td>
704
722
  <td align="center" valign="top" width="14.28%"><a href="https://github.com/felixmosh"><img src="https://avatars.githubusercontent.com/u/9304194?v=4?s=100" width="100px;" alt="Felix Mosheev"/><br /><sub><b>Felix Mosheev</b></sub></a><br /><a href="#question-felixmosh" title="Answering Questions">💬</a> <a href="https://github.com/i18next/next-i18next/commits?author=felixmosh" title="Code">💻</a> <a href="https://github.com/i18next/next-i18next/commits?author=felixmosh" title="Tests">⚠️</a></td>
705
723
  <td align="center" valign="top" width="14.28%"><a href="https://soluble.io/pro"><img src="https://avatars.githubusercontent.com/u/259798?v=4?s=100" width="100px;" alt="Sébastien Vanvelthem"/><br /><sub><b>Sébastien Vanvelthem</b></sub></a><br /><a href="https://github.com/i18next/next-i18next/commits?author=belgattitude" title="Code">💻</a> <a href="https://github.com/i18next/next-i18next/commits?author=belgattitude" title="Documentation">📖</a></td>
706
724
  </tr>
@@ -719,21 +737,21 @@ This project follows the [all-contributors](https://github.com/kentcdodds/all-co
719
737
  <h3 align="center">Gold Sponsors</h3>
720
738
 
721
739
  <p align="center">
722
- <a href="https://locize.com/" target="_blank">
740
+ <a href="https://www.locize.com/?utm_source=next_i18next_readme&utm_medium=github&utm_campaign=readme" target="_blank">
723
741
  <img src="https://raw.githubusercontent.com/i18next/i18next/master/assets/locize_sponsor_240.gif" width="240px">
724
742
  </a>
725
743
  </p>
726
744
 
727
745
  ---
728
746
 
729
- **localization as a service - [Locize](https://www.locize.com)**
747
+ **localization as a service - [Locize](https://www.locize.com?utm_source=next_i18next_readme&utm_medium=github&utm_campaign=readme)**
730
748
 
731
749
  Needing a translation management? Want to edit your translations with an InContext Editor? Use the original provided to you by the maintainers of i18next!
732
750
 
733
- **Now with a [Free plan](https://www.locize.com/pricing) for small projects!** Perfect for hobbyists or getting started.
751
+ **Now with a [Free plan](https://www.locize.com/pricing?utm_source=next_i18next_readme&utm_medium=github&utm_campaign=readme) for small projects!** Perfect for hobbyists or getting started.
734
752
 
735
753
  ![Locize](https://www.locize.com/img/ads/github_locize.png)
736
754
 
737
- By using [Locize](http://www.locize.com/?utm_source=next_i18next_readme&utm_medium=github) you directly support the future of i18next and next-i18next.
755
+ By using [Locize](https://www.locize.com/?utm_source=next_i18next_readme&utm_medium=github&utm_campaign=readme) you directly support the future of i18next and next-i18next.
738
756
 
739
757
  ---
@@ -55,7 +55,11 @@ interface I18nConfig {
55
55
  };
56
56
  /** @deprecated Use i18nextOptions instead */
57
57
  serializeConfig?: boolean;
58
- /** @deprecated Pages Router only */
58
+ /**
59
+ * Dev-only: when true (and `NODE_ENV !== 'production'`), reload translation
60
+ * resources from the backend before each render so edits to locale files
61
+ * appear without restarting `next dev`. No effect in production builds.
62
+ */
59
63
  reloadOnPrerender?: boolean;
60
64
  /** Support non-explicit language codes like 'en' matching 'en-US' */
61
65
  nonExplicitSupportedLngs?: boolean;
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.cts","names":[],"sources":["../../src/appRouter/types.ts","../../src/appRouter/config.ts"],"mappings":";;;KAEY,cAAA,IAAkB,QAAA,UAAkB,SAAA,aAAsB,OAAA;AAAA,UAErD,UAAA;EAFL;EAIV,aAAA;;EAEA,WAAA;EAN4B;EAQ5B,SAAA;EARoE;EAUpE,EAAA;EAV2E;EAc3E,UAAA;EAZyB;EAczB,eAAA;EAIY;EAFZ,eAAA;EA8BsB;EA5BtB,SAAA,GAAY,QAAA;EA4BS;EA1BrB,cAAA,GAAiB,cAAA;EAlBjB;EAsBA,YAAA;EAlBA;;;EAsBA,iBAAA;EAZA;EAgBA,UAAA;EAdY;EAgBZ,UAAA;EAdiB;EAgBjB,YAAA;EARA;EAUA,YAAA;EAJA;EAMA,QAAA;EAFA;EAMA,GAAA;EAAA;EAEA,cAAA,GAAiB,IAAA,CAAK,WAAA;EAAL;EAIjB,IAAA;IACE,aAAA;IACA,OAAA;IACA,OAAA;MACE,aAAA;MACA,MAAA;MACA,IAAA;MACA,OAAA;IAAA;IAEF,eAAA;EAAA;EAKF;EAFA,eAAA;EAIwB;EAFxB,iBAAA;EAKe;EAHf,wBAAA;AAAA;AAAA,UAGe,gBAAA;EACf,aAAA;EACA,WAAA;EACA,SAAA;EACA,EAAA;EACA,YAAA;EACA,iBAAA;EACA,UAAA;EACA,eAAA;EACA,eAAA;EACA,UAAA;EACA,UAAA;EACA,YAAA;EACA,YAAA;EACA,QAAA;EACA,SAAA,GAAY,QAAA;EACZ,cAAA,GAAiB,cAAA;EACjB,GAAA;EACA,cAAA,EAAgB,MAAA;EAChB,wBAAA;EAEA,IAAA,GAAO,UAAA;EACP,eAAA;EACA,iBAAA;AAAA;AAAA,KAGU,UAAA,YAAsB,aAAA,GAAgB,aAAA;EAChD,CAAA,EAAG,SAAA,CAAU,EAAA,EAAI,OAAA;EACjB,IAAA,EAAM,IAAA,EATN;EAWA,GAAA;AAAA;;;iBCrGc,YAAA,CAAa,MAAA,EAAQ,UAAA,GAAa,UAAA;AAAA,iBAIlC,eAAA,CAAgB,UAAA,EAAY,UAAA,GAAa,gBAAA"}
1
+ {"version":3,"file":"index.d.cts","names":[],"sources":["../../src/appRouter/types.ts","../../src/appRouter/config.ts"],"mappings":";;;KAEY,cAAA,IAAkB,QAAA,UAAkB,SAAA,aAAsB,OAAA;AAAA,UAErD,UAAA;EAFL;EAIV,aAAA;;EAEA,WAAA;EAN4B;EAQ5B,SAAA;EARoE;EAUpE,EAAA;EAV2E;EAc3E,UAAA;EAZyB;EAczB,eAAA;EAIY;EAFZ,eAAA;EA8BsB;EA5BtB,SAAA,GAAY,QAAA;EA4BS;EA1BrB,cAAA,GAAiB,cAAA;EAlBjB;EAsBA,YAAA;EAlBA;;;EAsBA,iBAAA;EAZA;EAgBA,UAAA;EAdY;EAgBZ,UAAA;EAdiB;EAgBjB,YAAA;EARA;EAUA,YAAA;EAJA;EAMA,QAAA;EAFA;EAMA,GAAA;EAAA;EAEA,cAAA,GAAiB,IAAA,CAAK,WAAA;EAAL;EAIjB,IAAA;IACE,aAAA;IACA,OAAA;IACA,OAAA;MACE,aAAA;MACA,MAAA;MACA,IAAA;MACA,OAAA;IAAA;IAEF,eAAA;EAAA;EASF;EANA,eAAA;EAQwB;;AAG1B;;;EALE,iBAAA;EAqBiB;EAnBjB,wBAAA;AAAA;AAAA,UAGe,gBAAA;EACf,aAAA;EACA,WAAA;EACA,SAAA;EACA,EAAA;EACA,YAAA;EACA,iBAAA;EACA,UAAA;EACA,eAAA;EACA,eAAA;EACA,UAAA;EACA,UAAA;EACA,YAAA;EACA,YAAA;EACA,QAAA;EACA,SAAA,GAAY,QAAA;EACZ,cAAA,GAAiB,cAAA;EACjB,GAAA;EACA,cAAA,EAAgB,MAAA;EAChB,wBAAA;EAEA,IAAA,GAAO,UAAA;EACP,eAAA;EACA,iBAAA;AAAA;AAAA,KAGU,UAAA,YAAsB,aAAA,GAAgB,aAAA;EAChD,CAAA,EAAG,SAAA,CAAU,EAAA,EAAI,OAAA;EACjB,IAAA,EAAM,IAAA,EALN;EAOA,GAAA;AAAA;;;iBCzGc,YAAA,CAAa,MAAA,EAAQ,UAAA,GAAa,UAAA;AAAA,iBAIlC,eAAA,CAAgB,UAAA,EAAY,UAAA,GAAa,gBAAA"}
@@ -55,7 +55,11 @@ interface I18nConfig {
55
55
  };
56
56
  /** @deprecated Use i18nextOptions instead */
57
57
  serializeConfig?: boolean;
58
- /** @deprecated Pages Router only */
58
+ /**
59
+ * Dev-only: when true (and `NODE_ENV !== 'production'`), reload translation
60
+ * resources from the backend before each render so edits to locale files
61
+ * appear without restarting `next dev`. No effect in production builds.
62
+ */
59
63
  reloadOnPrerender?: boolean;
60
64
  /** Support non-explicit language codes like 'en' matching 'en-US' */
61
65
  nonExplicitSupportedLngs?: boolean;
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.mts","names":[],"sources":["../../src/appRouter/types.ts","../../src/appRouter/config.ts"],"mappings":";;;KAEY,cAAA,IAAkB,QAAA,UAAkB,SAAA,aAAsB,OAAA;AAAA,UAErD,UAAA;EAFL;EAIV,aAAA;;EAEA,WAAA;EAN4B;EAQ5B,SAAA;EARoE;EAUpE,EAAA;EAV2E;EAc3E,UAAA;EAZyB;EAczB,eAAA;EAIY;EAFZ,eAAA;EA8BsB;EA5BtB,SAAA,GAAY,QAAA;EA4BS;EA1BrB,cAAA,GAAiB,cAAA;EAlBjB;EAsBA,YAAA;EAlBA;;;EAsBA,iBAAA;EAZA;EAgBA,UAAA;EAdY;EAgBZ,UAAA;EAdiB;EAgBjB,YAAA;EARA;EAUA,YAAA;EAJA;EAMA,QAAA;EAFA;EAMA,GAAA;EAAA;EAEA,cAAA,GAAiB,IAAA,CAAK,WAAA;EAAL;EAIjB,IAAA;IACE,aAAA;IACA,OAAA;IACA,OAAA;MACE,aAAA;MACA,MAAA;MACA,IAAA;MACA,OAAA;IAAA;IAEF,eAAA;EAAA;EAKF;EAFA,eAAA;EAIwB;EAFxB,iBAAA;EAKe;EAHf,wBAAA;AAAA;AAAA,UAGe,gBAAA;EACf,aAAA;EACA,WAAA;EACA,SAAA;EACA,EAAA;EACA,YAAA;EACA,iBAAA;EACA,UAAA;EACA,eAAA;EACA,eAAA;EACA,UAAA;EACA,UAAA;EACA,YAAA;EACA,YAAA;EACA,QAAA;EACA,SAAA,GAAY,QAAA;EACZ,cAAA,GAAiB,cAAA;EACjB,GAAA;EACA,cAAA,EAAgB,MAAA;EAChB,wBAAA;EAEA,IAAA,GAAO,UAAA;EACP,eAAA;EACA,iBAAA;AAAA;AAAA,KAGU,UAAA,YAAsB,aAAA,GAAgB,aAAA;EAChD,CAAA,EAAG,SAAA,CAAU,EAAA,EAAI,OAAA;EACjB,IAAA,EAAM,IAAA,EATN;EAWA,GAAA;AAAA;;;iBCrGc,YAAA,CAAa,MAAA,EAAQ,UAAA,GAAa,UAAA;AAAA,iBAIlC,eAAA,CAAgB,UAAA,EAAY,UAAA,GAAa,gBAAA"}
1
+ {"version":3,"file":"index.d.mts","names":[],"sources":["../../src/appRouter/types.ts","../../src/appRouter/config.ts"],"mappings":";;;KAEY,cAAA,IAAkB,QAAA,UAAkB,SAAA,aAAsB,OAAA;AAAA,UAErD,UAAA;EAFL;EAIV,aAAA;;EAEA,WAAA;EAN4B;EAQ5B,SAAA;EARoE;EAUpE,EAAA;EAV2E;EAc3E,UAAA;EAZyB;EAczB,eAAA;EAIY;EAFZ,eAAA;EA8BsB;EA5BtB,SAAA,GAAY,QAAA;EA4BS;EA1BrB,cAAA,GAAiB,cAAA;EAlBjB;EAsBA,YAAA;EAlBA;;;EAsBA,iBAAA;EAZA;EAgBA,UAAA;EAdY;EAgBZ,UAAA;EAdiB;EAgBjB,YAAA;EARA;EAUA,YAAA;EAJA;EAMA,QAAA;EAFA;EAMA,GAAA;EAAA;EAEA,cAAA,GAAiB,IAAA,CAAK,WAAA;EAAL;EAIjB,IAAA;IACE,aAAA;IACA,OAAA;IACA,OAAA;MACE,aAAA;MACA,MAAA;MACA,IAAA;MACA,OAAA;IAAA;IAEF,eAAA;EAAA;EASF;EANA,eAAA;EAQwB;;AAG1B;;;EALE,iBAAA;EAqBiB;EAnBjB,wBAAA;AAAA;AAAA,UAGe,gBAAA;EACf,aAAA;EACA,WAAA;EACA,SAAA;EACA,EAAA;EACA,YAAA;EACA,iBAAA;EACA,UAAA;EACA,eAAA;EACA,eAAA;EACA,UAAA;EACA,UAAA;EACA,YAAA;EACA,YAAA;EACA,QAAA;EACA,SAAA,GAAY,QAAA;EACZ,cAAA,GAAiB,cAAA;EACjB,GAAA;EACA,cAAA,EAAgB,MAAA;EAChB,wBAAA;EAEA,IAAA,GAAO,UAAA;EACP,eAAA;EACA,iBAAA;AAAA;AAAA,KAGU,UAAA,YAAsB,aAAA,GAAgB,aAAA;EAChD,CAAA,EAAG,SAAA,CAAU,EAAA,EAAI,OAAA;EACjB,IAAA,EAAM,IAAA,EALN;EAOA,GAAA;AAAA;;;iBCzGc,YAAA,CAAa,MAAA,EAAQ,UAAA,GAAa,UAAA;AAAA,iBAIlC,eAAA,CAAgB,UAAA,EAAY,UAAA,GAAa,gBAAA"}
@@ -56,7 +56,11 @@ interface I18nConfig {
56
56
  };
57
57
  /** @deprecated Use i18nextOptions instead */
58
58
  serializeConfig?: boolean;
59
- /** @deprecated Pages Router only */
59
+ /**
60
+ * Dev-only: when true (and `NODE_ENV !== 'production'`), reload translation
61
+ * resources from the backend before each render so edits to locale files
62
+ * appear without restarting `next dev`. No effect in production builds.
63
+ */
60
64
  reloadOnPrerender?: boolean;
61
65
  /** Support non-explicit language codes like 'en' matching 'en-US' */
62
66
  nonExplicitSupportedLngs?: boolean;
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.cts","names":[],"sources":["../../../src/appRouter/types.ts","../../../src/appRouter/config.ts","../../../src/appRouter/proxy/index.ts"],"mappings":";;;;KAEY,cAAA,IAAkB,QAAA,UAAkB,SAAA,aAAsB,OAAA;AAAA,UAErD,UAAA;;EAEf,aAAA;EAJwB;EAMxB,WAAA;EAN2E;EAQ3E,SAAA;EAR8C;EAU9C,EAAA;EAV2E;EAc3E,UAAA;EAZe;EAcf,eAAA;;EAEA,eAAA;EAIiB;EAFjB,SAAA,GAAY,QAAA;EA4BK;EA1BjB,cAAA,GAAiB,cAAA;EA0BI;EAtBrB,YAAA;EApBA;;;EAwBA,iBAAA;EAdA;EAkBA,UAAA;EAdA;EAgBA,UAAA;EAdA;EAgBA,YAAA;EAZA;EAcA,YAAA;EANA;EAQA,QAAA;EAJA;EAQA,GAAA;EAJA;EAMA,cAAA,GAAiB,IAAA,CAAK,WAAA;EAAtB;EAIA,IAAA;IACE,aAAA;IACA,OAAA;IACA,OAAA;MACE,aAAA;MACA,MAAA;MACA,IAAA;MACA,OAAA;IAAA;IAEF,eAAA;EAAA;EAGF;EAAA,eAAA;EAIA;EAFA,iBAAA;EAEwB;EAAxB,wBAAA;AAAA;AAAA,UAGe,gBAAA;EACf,aAAA;EACA,WAAA;EACA,SAAA;EACA,EAAA;EACA,YAAA;EACA,iBAAA;EACA,UAAA;EACA,eAAA;EACA,eAAA;EACA,UAAA;EACA,UAAA;EACA,YAAA;EACA,YAAA;EACA,QAAA;EACA,SAAA,GAAY,QAAA;EACZ,cAAA,GAAiB,cAAA;EACjB,GAAA;EACA,cAAA,EAAgB,MAAA;EAChB,wBAAA;EAEA,IAAA,GAAO,UAAA;EACP,eAAA;EACA,iBAAA;AAAA;;;iBC9Fc,YAAA,CAAa,MAAA,EAAQ,UAAA,GAAa,UAAA;AAAA,iBAIlC,eAAA,CAAgB,UAAA,EAAY,UAAA,GAAa,gBAAA;;;iBCczC,WAAA,CAAY,UAAA,EAAY,UAAA,IAQX,GAAA,EAAK,WAAA,KAAc,YAAA;;;;;cA2HnC,gBAAA,SAAgB,WAAA"}
1
+ {"version":3,"file":"index.d.cts","names":[],"sources":["../../../src/appRouter/types.ts","../../../src/appRouter/config.ts","../../../src/appRouter/proxy/index.ts"],"mappings":";;;;KAEY,cAAA,IAAkB,QAAA,UAAkB,SAAA,aAAsB,OAAA;AAAA,UAErD,UAAA;;EAEf,aAAA;EAJwB;EAMxB,WAAA;EAN2E;EAQ3E,SAAA;EAR8C;EAU9C,EAAA;EAV2E;EAc3E,UAAA;EAZe;EAcf,eAAA;;EAEA,eAAA;EAIiB;EAFjB,SAAA,GAAY,QAAA;EA4BK;EA1BjB,cAAA,GAAiB,cAAA;EA0BI;EAtBrB,YAAA;EApBA;;;EAwBA,iBAAA;EAdA;EAkBA,UAAA;EAdA;EAgBA,UAAA;EAdA;EAgBA,YAAA;EAZA;EAcA,YAAA;EANA;EAQA,QAAA;EAJA;EAQA,GAAA;EAJA;EAMA,cAAA,GAAiB,IAAA,CAAK,WAAA;EAAtB;EAIA,IAAA;IACE,aAAA;IACA,OAAA;IACA,OAAA;MACE,aAAA;MACA,MAAA;MACA,IAAA;MACA,OAAA;IAAA;IAEF,eAAA;EAAA;EAGF;EAAA,eAAA;EAQA;;;AAGF;;EALE,iBAAA;EAoBY;EAlBZ,wBAAA;AAAA;AAAA,UAGe,gBAAA;EACf,aAAA;EACA,WAAA;EACA,SAAA;EACA,EAAA;EACA,YAAA;EACA,iBAAA;EACA,UAAA;EACA,eAAA;EACA,eAAA;EACA,UAAA;EACA,UAAA;EACA,YAAA;EACA,YAAA;EACA,QAAA;EACA,SAAA,GAAY,QAAA;EACZ,cAAA,GAAiB,cAAA;EACjB,GAAA;EACA,cAAA,EAAgB,MAAA;EAChB,wBAAA;EAEA,IAAA,GAAO,UAAA;EACP,eAAA;EACA,iBAAA;AAAA;;;iBClGc,YAAA,CAAa,MAAA,EAAQ,UAAA,GAAa,UAAA;AAAA,iBAIlC,eAAA,CAAgB,UAAA,EAAY,UAAA,GAAa,gBAAA;;;iBCczC,WAAA,CAAY,UAAA,EAAY,UAAA,IAQX,GAAA,EAAK,WAAA,KAAc,YAAA;;;;;cA2HnC,gBAAA,SAAgB,WAAA"}
@@ -56,7 +56,11 @@ interface I18nConfig {
56
56
  };
57
57
  /** @deprecated Use i18nextOptions instead */
58
58
  serializeConfig?: boolean;
59
- /** @deprecated Pages Router only */
59
+ /**
60
+ * Dev-only: when true (and `NODE_ENV !== 'production'`), reload translation
61
+ * resources from the backend before each render so edits to locale files
62
+ * appear without restarting `next dev`. No effect in production builds.
63
+ */
60
64
  reloadOnPrerender?: boolean;
61
65
  /** Support non-explicit language codes like 'en' matching 'en-US' */
62
66
  nonExplicitSupportedLngs?: boolean;
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.mts","names":[],"sources":["../../../src/appRouter/types.ts","../../../src/appRouter/config.ts","../../../src/appRouter/proxy/index.ts"],"mappings":";;;;KAEY,cAAA,IAAkB,QAAA,UAAkB,SAAA,aAAsB,OAAA;AAAA,UAErD,UAAA;;EAEf,aAAA;EAJwB;EAMxB,WAAA;EAN2E;EAQ3E,SAAA;EAR8C;EAU9C,EAAA;EAV2E;EAc3E,UAAA;EAZe;EAcf,eAAA;;EAEA,eAAA;EAIiB;EAFjB,SAAA,GAAY,QAAA;EA4BK;EA1BjB,cAAA,GAAiB,cAAA;EA0BI;EAtBrB,YAAA;EApBA;;;EAwBA,iBAAA;EAdA;EAkBA,UAAA;EAdA;EAgBA,UAAA;EAdA;EAgBA,YAAA;EAZA;EAcA,YAAA;EANA;EAQA,QAAA;EAJA;EAQA,GAAA;EAJA;EAMA,cAAA,GAAiB,IAAA,CAAK,WAAA;EAAtB;EAIA,IAAA;IACE,aAAA;IACA,OAAA;IACA,OAAA;MACE,aAAA;MACA,MAAA;MACA,IAAA;MACA,OAAA;IAAA;IAEF,eAAA;EAAA;EAGF;EAAA,eAAA;EAIA;EAFA,iBAAA;EAEwB;EAAxB,wBAAA;AAAA;AAAA,UAGe,gBAAA;EACf,aAAA;EACA,WAAA;EACA,SAAA;EACA,EAAA;EACA,YAAA;EACA,iBAAA;EACA,UAAA;EACA,eAAA;EACA,eAAA;EACA,UAAA;EACA,UAAA;EACA,YAAA;EACA,YAAA;EACA,QAAA;EACA,SAAA,GAAY,QAAA;EACZ,cAAA,GAAiB,cAAA;EACjB,GAAA;EACA,cAAA,EAAgB,MAAA;EAChB,wBAAA;EAEA,IAAA,GAAO,UAAA;EACP,eAAA;EACA,iBAAA;AAAA;;;iBC9Fc,YAAA,CAAa,MAAA,EAAQ,UAAA,GAAa,UAAA;AAAA,iBAIlC,eAAA,CAAgB,UAAA,EAAY,UAAA,GAAa,gBAAA;;;iBCczC,WAAA,CAAY,UAAA,EAAY,UAAA,IAQX,GAAA,EAAK,WAAA,KAAc,YAAA;;;;;cA2HnC,gBAAA,SAAgB,WAAA"}
1
+ {"version":3,"file":"index.d.mts","names":[],"sources":["../../../src/appRouter/types.ts","../../../src/appRouter/config.ts","../../../src/appRouter/proxy/index.ts"],"mappings":";;;;KAEY,cAAA,IAAkB,QAAA,UAAkB,SAAA,aAAsB,OAAA;AAAA,UAErD,UAAA;;EAEf,aAAA;EAJwB;EAMxB,WAAA;EAN2E;EAQ3E,SAAA;EAR8C;EAU9C,EAAA;EAV2E;EAc3E,UAAA;EAZe;EAcf,eAAA;;EAEA,eAAA;EAIiB;EAFjB,SAAA,GAAY,QAAA;EA4BK;EA1BjB,cAAA,GAAiB,cAAA;EA0BI;EAtBrB,YAAA;EApBA;;;EAwBA,iBAAA;EAdA;EAkBA,UAAA;EAdA;EAgBA,UAAA;EAdA;EAgBA,YAAA;EAZA;EAcA,YAAA;EANA;EAQA,QAAA;EAJA;EAQA,GAAA;EAJA;EAMA,cAAA,GAAiB,IAAA,CAAK,WAAA;EAAtB;EAIA,IAAA;IACE,aAAA;IACA,OAAA;IACA,OAAA;MACE,aAAA;MACA,MAAA;MACA,IAAA;MACA,OAAA;IAAA;IAEF,eAAA;EAAA;EAGF;EAAA,eAAA;EAQA;;;AAGF;;EALE,iBAAA;EAoBY;EAlBZ,wBAAA;AAAA;AAAA,UAGe,gBAAA;EACf,aAAA;EACA,WAAA;EACA,SAAA;EACA,EAAA;EACA,YAAA;EACA,iBAAA;EACA,UAAA;EACA,eAAA;EACA,eAAA;EACA,UAAA;EACA,UAAA;EACA,YAAA;EACA,YAAA;EACA,QAAA;EACA,SAAA,GAAY,QAAA;EACZ,cAAA,GAAiB,cAAA;EACjB,GAAA;EACA,cAAA,EAAgB,MAAA;EAChB,wBAAA;EAEA,IAAA,GAAO,UAAA;EACP,eAAA;EACA,iBAAA;AAAA;;;iBClGc,YAAA,CAAa,MAAA,EAAQ,UAAA,GAAa,UAAA;AAAA,iBAIlC,eAAA,CAAgB,UAAA,EAAY,UAAA,GAAa,gBAAA;;;iBCczC,WAAA,CAAY,UAAA,EAAY,UAAA,IAQX,GAAA,EAAK,WAAA,KAAc,YAAA;;;;;cA2HnC,gBAAA,SAAgB,WAAA"}
@@ -132,6 +132,10 @@ async function getSharedInstance(config) {
132
132
  })();
133
133
  return _sharedInstancePromise;
134
134
  }
135
+ const reloadResourcesForRender = (0, react.cache)(async (i18n, lng) => {
136
+ const ns = i18n.options.ns ?? [];
137
+ await i18n.reloadResources([lng], ns);
138
+ });
135
139
  const detectLanguage = (0, react.cache)(async (config) => {
136
140
  const fromHeader = (await (0, next_headers.headers)()).get(config.headerName);
137
141
  if (fromHeader) return fromHeader;
@@ -167,6 +171,7 @@ async function getT(ns, options = {}) {
167
171
  const config = getConfig();
168
172
  const lng = options.lng || await detectLanguage(config);
169
173
  const i18nInstance = await getSharedInstance(config);
174
+ if (config.reloadOnPrerender && process.env.NODE_ENV !== "production") await reloadResourcesForRender(i18nInstance, lng);
170
175
  const missingNs = (ns ? Array.isArray(ns) ? ns : [ns] : config.ns).filter((n) => !i18nInstance.hasLoadedNamespace(n));
171
176
  if (missingNs.length > 0) await i18nInstance.loadNamespaces(missingNs);
172
177
  const resolvedNs = ns ? Array.isArray(ns) ? ns[0] : ns : config.defaultNS;
@@ -1 +1 @@
1
- {"version":3,"file":"server.cjs","names":[],"sources":["../../src/appRouter/config.ts","../../src/appRouter/server.ts"],"sourcesContent":["import type { I18nConfig, NormalizedConfig } from './types'\n\nexport function defineConfig(config: I18nConfig): I18nConfig {\n return config\n}\n\nexport function normalizeConfig(userConfig: I18nConfig): NormalizedConfig {\n // Support legacy format: { i18n: { defaultLocale, locales } }\n const supportedLngs = userConfig.supportedLngs ??\n userConfig.i18n?.locales?.filter((l: string) => l !== 'default') ??\n ['en']\n const fallbackLng = userConfig.fallbackLng ??\n userConfig.i18n?.defaultLocale ??\n supportedLngs[0]\n\n if (!fallbackLng) {\n throw new Error('next-i18next: fallbackLng (or i18n.defaultLocale) is required')\n }\n if (supportedLngs.length === 0) {\n throw new Error('next-i18next: supportedLngs (or i18n.locales) must contain at least one language')\n }\n\n const defaultNS = userConfig.defaultNS ?? 'common'\n\n return {\n supportedLngs,\n fallbackLng,\n defaultNS,\n ns: userConfig.ns ?? [defaultNS],\n localeInPath: userConfig.localeInPath ?? true,\n hideDefaultLocale: userConfig.hideDefaultLocale ?? false,\n localePath: userConfig.localePath ?? '/locales',\n localeStructure: userConfig.localeStructure ?? '{{lng}}/{{ns}}',\n localeExtension: userConfig.localeExtension ?? 'json',\n cookieName: userConfig.cookieName ?? 'i18next',\n headerName: userConfig.headerName ?? 'x-i18next-current-language',\n cookieMaxAge: userConfig.cookieMaxAge ?? 365 * 24 * 60 * 60,\n ignoredPaths: userConfig.ignoredPaths ?? ['/api', '/_next', '/static'],\n basePath: userConfig.basePath,\n resources: userConfig.resources,\n resourceLoader: userConfig.resourceLoader,\n use: userConfig.use ?? [],\n i18nextOptions: (userConfig.i18nextOptions ?? {}) as Record<string, any>,\n nonExplicitSupportedLngs: userConfig.nonExplicitSupportedLngs ?? false,\n // Preserve legacy fields\n i18n: userConfig.i18n,\n serializeConfig: userConfig.serializeConfig,\n reloadOnPrerender: userConfig.reloadOnPrerender,\n }\n}\n","import { createInstance } from 'i18next'\nimport type { i18n as I18NextClient, Resource, Module, FlatNamespace, KeyPrefix } from 'i18next'\nimport resourcesToBackend from 'i18next-resources-to-backend'\nimport { cache } from 'react'\nimport { headers, cookies } from 'next/headers'\n\nimport type { I18nConfig, NormalizedConfig, GetTResult } from './types'\nimport { normalizeConfig } from './config'\n\nlet _config: NormalizedConfig | null = null\n\n// Module-level singleton: persists across requests within the same server process.\n// This is critical for custom backends (i18next-http-backend, i18next-locize-backend)\n// to avoid re-fetching translations on every request.\n// In serverless environments (Lambda, Cloud Functions, etc.), this lives as long as\n// the warm function instance — backends with reloadInterval will refresh automatically.\nlet _sharedInstance: I18NextClient | null = null\nlet _sharedInstancePromise: Promise<I18NextClient> | null = null\n\nfunction getConfig(): NormalizedConfig {\n if (!_config) {\n throw new Error(\n 'next-i18next: Server module not initialized. Call initServerI18next(config) in your root layout.'\n )\n }\n return _config\n}\n\n/**\n * Initialize the server-side i18next configuration.\n * Call this once in your root layout or a shared setup file.\n */\nexport function initServerI18next(userConfig: I18nConfig): void {\n _config = normalizeConfig(userConfig)\n}\n\nfunction hasCustomBackend(plugins: any[]): boolean {\n return plugins.some((b: Module) => b.type === 'backend')\n}\n\nfunction createResourceBackend(config: NormalizedConfig) {\n if (config.resourceLoader) {\n return resourcesToBackend(config.resourceLoader)\n }\n return resourcesToBackend(async (language: string, namespace: string) => {\n const filePath = `${config.localePath}/${config.localeStructure\n .replace('{{lng}}', language)\n .replace('{{ns}}', namespace)}.${config.localeExtension}`\n\n // Node.js runtime: read from filesystem\n if (typeof process !== 'undefined' && process.versions?.node) {\n try {\n const fs = await import('fs/promises')\n const pathMod = await import('path')\n const resolved = pathMod.resolve(process.cwd(), `public${filePath}`)\n const content = await fs.readFile(resolved, 'utf-8')\n return JSON.parse(content)\n } catch {\n throw new Error(\n `next-i18next: Could not read locale file \"public${filePath}\". ` +\n 'On serverless platforms (Vercel, AWS Lambda, etc.), files in public/ are served via CDN ' +\n 'but are NOT available on the filesystem at runtime. Use the `resourceLoader` option with ' +\n 'dynamic imports instead:\\n\\n' +\n ' resourceLoader: (language, namespace) =>\\n' +\n // eslint-disable-next-line no-template-curly-in-string\n ' import(`./public/locales/${language}/${namespace}.json`)\\n'\n )\n }\n }\n\n // Edge runtime: filesystem not available\n throw new Error(\n `next-i18next: Cannot load locale file \"${filePath}\" in Edge Runtime. ` +\n 'Provide pre-bundled `resources`, a custom `resourceLoader`, or use a custom backend (e.g. i18next-http-backend) via the `use` option.'\n )\n })\n}\n\n/**\n * Get or create the shared i18next instance.\n * The instance is created once and reused across all requests.\n * All languages are preloaded so that getFixedT(lng) works for any supported language.\n * Additional namespaces are loaded on demand and cached in the instance store.\n */\nasync function getSharedInstance(config: NormalizedConfig): Promise<I18NextClient> {\n if (_sharedInstance?.isInitialized) return _sharedInstance\n\n // Deduplicate concurrent init calls (multiple requests arriving while first init is in flight)\n if (_sharedInstancePromise) return _sharedInstancePromise\n\n _sharedInstancePromise = (async () => {\n const i18nInstance = createInstance()\n\n // Add a backend when needed:\n // - No resources provided → backend loads everything\n // - Resources provided with partialBundledLanguages → backend loads the rest\n // - Custom backend in config.use → user handles it, skip default backend\n const partialBundled = config.i18nextOptions?.partialBundledLanguages\n if ((!config.resources || partialBundled) && !hasCustomBackend(config.use)) {\n i18nInstance.use(createResourceBackend(config))\n }\n\n config.use.forEach((plugin: any) => i18nInstance.use(plugin))\n\n await i18nInstance.init({\n // No `lng` — the shared instance is language-neutral.\n // We use getFixedT(lng, ns) to get language-specific translators.\n lng: config.fallbackLng,\n ns: config.ns,\n defaultNS: config.defaultNS,\n fallbackLng: config.fallbackLng,\n supportedLngs: config.supportedLngs,\n nonExplicitSupportedLngs: config.nonExplicitSupportedLngs,\n fallbackNS: config.defaultNS,\n preload: config.supportedLngs, // preload ALL languages upfront\n interpolation: { escapeValue: false },\n ...(config.resources ? { resources: config.resources } : {}),\n ...config.i18nextOptions,\n })\n\n _sharedInstance = i18nInstance\n return i18nInstance\n })()\n\n return _sharedInstancePromise\n}\n\n// Per-request language detection, deduplicated within a single React render\nconst detectLanguage = cache(async (config: NormalizedConfig): Promise<string> => {\n const headerList = await headers()\n const fromHeader = headerList.get(config.headerName)\n if (fromHeader) return fromHeader\n\n const cookieStore = await cookies()\n const cookieValue = cookieStore.get(config.cookieName)?.value\n if (cookieValue) {\n if (config.supportedLngs.includes(cookieValue)) {\n return cookieValue\n }\n // nonExplicitSupportedLngs: e.g. cookie 'en' matches supported 'en-US'\n if (config.nonExplicitSupportedLngs) {\n const prefix = cookieValue.toLowerCase().split('-')[0]\n const match = config.supportedLngs.find(\n l => l.toLowerCase() === prefix || l.toLowerCase().split('-')[0] === prefix\n )\n if (match) return match\n }\n }\n\n return config.fallbackLng\n})\n\n/**\n * Get a translation function for use in Server Components, layouts, and generateMetadata.\n *\n * The underlying i18next instance is a **module-level singleton** that persists across\n * requests. This means custom backends (i18next-http-backend, i18next-locize-backend, etc.)\n * only fetch translations once (or according to their own reloadInterval), not on every request.\n *\n * @example\n * ```tsx\n * import { getT } from 'next-i18next/server'\n *\n * export default async function Page() {\n * const { t, i18n } = await getT('home')\n * return <h1>{t('heading')}</h1>\n * }\n * ```\n */\nexport async function getT<\n Ns extends FlatNamespace = FlatNamespace,\n KPrefix extends KeyPrefix<Ns> = undefined,\n>(\n ns?: Ns | Ns[],\n options: { keyPrefix?: KPrefix; lng?: string } = {},\n): Promise<GetTResult<Ns, KPrefix>> {\n const config = getConfig()\n\n const lng = options.lng || await detectLanguage(config)\n const i18nInstance = await getSharedInstance(config)\n\n // Load additional namespaces on demand if not already loaded\n const nsArray: string[] = ns\n ? (Array.isArray(ns) ? ns as string[] : [ns as string])\n : config.ns\n const missingNs = nsArray.filter(n => !i18nInstance.hasLoadedNamespace(n))\n if (missingNs.length > 0) {\n await i18nInstance.loadNamespaces(missingNs)\n }\n\n const resolvedNs = ns\n ? (Array.isArray(ns) ? ns[0] : ns) as string\n : config.defaultNS\n\n return {\n t: i18nInstance.getFixedT(lng, resolvedNs, options.keyPrefix as string | undefined),\n i18n: i18nInstance,\n lng,\n } as any\n}\n\n/**\n * Extract loaded resources from the server i18next instance for passing to I18nProvider.\n *\n * @example\n * ```tsx\n * const { i18n } = await getT()\n * const resources = getResources(i18n, ['common', 'footer'])\n * return <I18nProvider language={i18n.language} resources={resources}>{children}</I18nProvider>\n * ```\n */\nexport function getResources(\n i18n: I18NextClient,\n namespaces?: string[],\n): Resource {\n const resources: Resource = {}\n const store = i18n.store?.data || {}\n const nsFilter = namespaces ? new Set(namespaces) : null\n\n for (const lng of Object.keys(store)) {\n resources[lng] = {}\n for (const ns of Object.keys(store[lng])) {\n if (!nsFilter || nsFilter.has(ns)) {\n resources[lng][ns] = store[lng][ns]\n }\n }\n }\n\n return resources\n}\n\n/**\n * Helper for generateStaticParams — returns params for all supported languages.\n *\n * @example\n * ```tsx\n * import { generateI18nStaticParams } from 'next-i18next/server'\n *\n * export async function generateStaticParams() {\n * return generateI18nStaticParams()\n * }\n * ```\n */\nexport function generateI18nStaticParams(): { lng: string }[] {\n const config = getConfig()\n return config.supportedLngs.map(lng => ({ lng }))\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"server.cjs","names":[],"sources":["../../src/appRouter/config.ts","../../src/appRouter/server.ts"],"sourcesContent":["import type { I18nConfig, NormalizedConfig } from './types'\n\nexport function defineConfig(config: I18nConfig): I18nConfig {\n return config\n}\n\nexport function normalizeConfig(userConfig: I18nConfig): NormalizedConfig {\n // Support legacy format: { i18n: { defaultLocale, locales } }\n const supportedLngs = userConfig.supportedLngs ??\n userConfig.i18n?.locales?.filter((l: string) => l !== 'default') ??\n ['en']\n const fallbackLng = userConfig.fallbackLng ??\n userConfig.i18n?.defaultLocale ??\n supportedLngs[0]\n\n if (!fallbackLng) {\n throw new Error('next-i18next: fallbackLng (or i18n.defaultLocale) is required')\n }\n if (supportedLngs.length === 0) {\n throw new Error('next-i18next: supportedLngs (or i18n.locales) must contain at least one language')\n }\n\n const defaultNS = userConfig.defaultNS ?? 'common'\n\n return {\n supportedLngs,\n fallbackLng,\n defaultNS,\n ns: userConfig.ns ?? [defaultNS],\n localeInPath: userConfig.localeInPath ?? true,\n hideDefaultLocale: userConfig.hideDefaultLocale ?? false,\n localePath: userConfig.localePath ?? '/locales',\n localeStructure: userConfig.localeStructure ?? '{{lng}}/{{ns}}',\n localeExtension: userConfig.localeExtension ?? 'json',\n cookieName: userConfig.cookieName ?? 'i18next',\n headerName: userConfig.headerName ?? 'x-i18next-current-language',\n cookieMaxAge: userConfig.cookieMaxAge ?? 365 * 24 * 60 * 60,\n ignoredPaths: userConfig.ignoredPaths ?? ['/api', '/_next', '/static'],\n basePath: userConfig.basePath,\n resources: userConfig.resources,\n resourceLoader: userConfig.resourceLoader,\n use: userConfig.use ?? [],\n i18nextOptions: (userConfig.i18nextOptions ?? {}) as Record<string, any>,\n nonExplicitSupportedLngs: userConfig.nonExplicitSupportedLngs ?? false,\n // Preserve legacy fields\n i18n: userConfig.i18n,\n serializeConfig: userConfig.serializeConfig,\n reloadOnPrerender: userConfig.reloadOnPrerender,\n }\n}\n","import { createInstance } from 'i18next'\nimport type { i18n as I18NextClient, Resource, Module, FlatNamespace, KeyPrefix } from 'i18next'\nimport resourcesToBackend from 'i18next-resources-to-backend'\nimport { cache } from 'react'\nimport { headers, cookies } from 'next/headers'\n\nimport type { I18nConfig, NormalizedConfig, GetTResult } from './types'\nimport { normalizeConfig } from './config'\n\nlet _config: NormalizedConfig | null = null\n\n// Module-level singleton: persists across requests within the same server process.\n// This is critical for custom backends (i18next-http-backend, i18next-locize-backend)\n// to avoid re-fetching translations on every request.\n// In serverless environments (Lambda, Cloud Functions, etc.), this lives as long as\n// the warm function instance — backends with reloadInterval will refresh automatically.\nlet _sharedInstance: I18NextClient | null = null\nlet _sharedInstancePromise: Promise<I18NextClient> | null = null\n\nfunction getConfig(): NormalizedConfig {\n if (!_config) {\n throw new Error(\n 'next-i18next: Server module not initialized. Call initServerI18next(config) in your root layout.'\n )\n }\n return _config\n}\n\n/**\n * Initialize the server-side i18next configuration.\n * Call this once in your root layout or a shared setup file.\n */\nexport function initServerI18next(userConfig: I18nConfig): void {\n _config = normalizeConfig(userConfig)\n}\n\nfunction hasCustomBackend(plugins: any[]): boolean {\n return plugins.some((b: Module) => b.type === 'backend')\n}\n\nfunction createResourceBackend(config: NormalizedConfig) {\n if (config.resourceLoader) {\n return resourcesToBackend(config.resourceLoader)\n }\n return resourcesToBackend(async (language: string, namespace: string) => {\n const filePath = `${config.localePath}/${config.localeStructure\n .replace('{{lng}}', language)\n .replace('{{ns}}', namespace)}.${config.localeExtension}`\n\n // Node.js runtime: read from filesystem\n if (typeof process !== 'undefined' && process.versions?.node) {\n try {\n const fs = await import('fs/promises')\n const pathMod = await import('path')\n const resolved = pathMod.resolve(process.cwd(), `public${filePath}`)\n const content = await fs.readFile(resolved, 'utf-8')\n return JSON.parse(content)\n } catch {\n throw new Error(\n `next-i18next: Could not read locale file \"public${filePath}\". ` +\n 'On serverless platforms (Vercel, AWS Lambda, etc.), files in public/ are served via CDN ' +\n 'but are NOT available on the filesystem at runtime. Use the `resourceLoader` option with ' +\n 'dynamic imports instead:\\n\\n' +\n ' resourceLoader: (language, namespace) =>\\n' +\n // eslint-disable-next-line no-template-curly-in-string\n ' import(`./public/locales/${language}/${namespace}.json`)\\n'\n )\n }\n }\n\n // Edge runtime: filesystem not available\n throw new Error(\n `next-i18next: Cannot load locale file \"${filePath}\" in Edge Runtime. ` +\n 'Provide pre-bundled `resources`, a custom `resourceLoader`, or use a custom backend (e.g. i18next-http-backend) via the `use` option.'\n )\n })\n}\n\n/**\n * Get or create the shared i18next instance.\n * The instance is created once and reused across all requests.\n * All languages are preloaded so that getFixedT(lng) works for any supported language.\n * Additional namespaces are loaded on demand and cached in the instance store.\n */\nasync function getSharedInstance(config: NormalizedConfig): Promise<I18NextClient> {\n if (_sharedInstance?.isInitialized) return _sharedInstance\n\n // Deduplicate concurrent init calls (multiple requests arriving while first init is in flight)\n if (_sharedInstancePromise) return _sharedInstancePromise\n\n _sharedInstancePromise = (async () => {\n const i18nInstance = createInstance()\n\n // Add a backend when needed:\n // - No resources provided → backend loads everything\n // - Resources provided with partialBundledLanguages → backend loads the rest\n // - Custom backend in config.use → user handles it, skip default backend\n const partialBundled = config.i18nextOptions?.partialBundledLanguages\n if ((!config.resources || partialBundled) && !hasCustomBackend(config.use)) {\n i18nInstance.use(createResourceBackend(config))\n }\n\n config.use.forEach((plugin: any) => i18nInstance.use(plugin))\n\n await i18nInstance.init({\n // No `lng` — the shared instance is language-neutral.\n // We use getFixedT(lng, ns) to get language-specific translators.\n lng: config.fallbackLng,\n ns: config.ns,\n defaultNS: config.defaultNS,\n fallbackLng: config.fallbackLng,\n supportedLngs: config.supportedLngs,\n nonExplicitSupportedLngs: config.nonExplicitSupportedLngs,\n fallbackNS: config.defaultNS,\n preload: config.supportedLngs, // preload ALL languages upfront\n interpolation: { escapeValue: false },\n ...(config.resources ? { resources: config.resources } : {}),\n ...config.i18nextOptions,\n })\n\n _sharedInstance = i18nInstance\n return i18nInstance\n })()\n\n return _sharedInstancePromise\n}\n\n// Dev-only hot-reload: refetch resources for the requested language so edits\n// to locale files appear without restarting `next dev`. Wrapped in `cache()`\n// so multiple `getT` calls within the same render dedupe to a single reload.\n// Gated on `NODE_ENV !== 'production'` at the call site so HTTP/locize/chained\n// backends are never refetched per-request in prod.\nconst reloadResourcesForRender = cache(\n async (i18n: I18NextClient, lng: string): Promise<void> => {\n const ns = (i18n.options.ns as string[] | undefined) ?? []\n await i18n.reloadResources([lng], ns)\n }\n)\n\n// Per-request language detection, deduplicated within a single React render\nconst detectLanguage = cache(async (config: NormalizedConfig): Promise<string> => {\n const headerList = await headers()\n const fromHeader = headerList.get(config.headerName)\n if (fromHeader) return fromHeader\n\n const cookieStore = await cookies()\n const cookieValue = cookieStore.get(config.cookieName)?.value\n if (cookieValue) {\n if (config.supportedLngs.includes(cookieValue)) {\n return cookieValue\n }\n // nonExplicitSupportedLngs: e.g. cookie 'en' matches supported 'en-US'\n if (config.nonExplicitSupportedLngs) {\n const prefix = cookieValue.toLowerCase().split('-')[0]\n const match = config.supportedLngs.find(\n l => l.toLowerCase() === prefix || l.toLowerCase().split('-')[0] === prefix\n )\n if (match) return match\n }\n }\n\n return config.fallbackLng\n})\n\n/**\n * Get a translation function for use in Server Components, layouts, and generateMetadata.\n *\n * The underlying i18next instance is a **module-level singleton** that persists across\n * requests. This means custom backends (i18next-http-backend, i18next-locize-backend, etc.)\n * only fetch translations once (or according to their own reloadInterval), not on every request.\n *\n * @example\n * ```tsx\n * import { getT } from 'next-i18next/server'\n *\n * export default async function Page() {\n * const { t, i18n } = await getT('home')\n * return <h1>{t('heading')}</h1>\n * }\n * ```\n */\nexport async function getT<\n Ns extends FlatNamespace = FlatNamespace,\n KPrefix extends KeyPrefix<Ns> = undefined,\n>(\n ns?: Ns | Ns[],\n options: { keyPrefix?: KPrefix; lng?: string } = {},\n): Promise<GetTResult<Ns, KPrefix>> {\n const config = getConfig()\n\n const lng = options.lng || await detectLanguage(config)\n const i18nInstance = await getSharedInstance(config)\n\n if (config.reloadOnPrerender && process.env.NODE_ENV !== 'production') {\n await reloadResourcesForRender(i18nInstance, lng)\n }\n\n // Load additional namespaces on demand if not already loaded\n const nsArray: string[] = ns\n ? (Array.isArray(ns) ? ns as string[] : [ns as string])\n : config.ns\n const missingNs = nsArray.filter(n => !i18nInstance.hasLoadedNamespace(n))\n if (missingNs.length > 0) {\n await i18nInstance.loadNamespaces(missingNs)\n }\n\n const resolvedNs = ns\n ? (Array.isArray(ns) ? ns[0] : ns) as string\n : config.defaultNS\n\n return {\n t: i18nInstance.getFixedT(lng, resolvedNs, options.keyPrefix as string | undefined),\n i18n: i18nInstance,\n lng,\n } as any\n}\n\n/**\n * Extract loaded resources from the server i18next instance for passing to I18nProvider.\n *\n * @example\n * ```tsx\n * const { i18n } = await getT()\n * const resources = getResources(i18n, ['common', 'footer'])\n * return <I18nProvider language={i18n.language} resources={resources}>{children}</I18nProvider>\n * ```\n */\nexport function getResources(\n i18n: I18NextClient,\n namespaces?: string[],\n): Resource {\n const resources: Resource = {}\n const store = i18n.store?.data || {}\n const nsFilter = namespaces ? new Set(namespaces) : null\n\n for (const lng of Object.keys(store)) {\n resources[lng] = {}\n for (const ns of Object.keys(store[lng])) {\n if (!nsFilter || nsFilter.has(ns)) {\n resources[lng][ns] = store[lng][ns]\n }\n }\n }\n\n return resources\n}\n\n/**\n * Helper for generateStaticParams — returns params for all supported languages.\n *\n * @example\n * ```tsx\n * import { generateI18nStaticParams } from 'next-i18next/server'\n *\n * export async function generateStaticParams() {\n * return generateI18nStaticParams()\n * }\n * ```\n */\nexport function generateI18nStaticParams(): { lng: string }[] {\n const config = getConfig()\n return config.supportedLngs.map(lng => ({ lng }))\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAMA,SAAgB,gBAAgB,YAA0C;CAExE,MAAM,gBAAgB,WAAW,iBAC/B,WAAW,MAAM,SAAS,QAAQ,MAAc,MAAM,UAAU,IAChE,CAAC,KAAK;CACR,MAAM,cAAc,WAAW,eAC7B,WAAW,MAAM,iBACjB,cAAc;AAEhB,KAAI,CAAC,YACH,OAAM,IAAI,MAAM,gEAAgE;AAElF,KAAI,cAAc,WAAW,EAC3B,OAAM,IAAI,MAAM,mFAAmF;CAGrG,MAAM,YAAY,WAAW,aAAa;AAE1C,QAAO;EACL;EACA;EACA;EACA,IAAI,WAAW,MAAM,CAAC,UAAU;EAChC,cAAc,WAAW,gBAAgB;EACzC,mBAAmB,WAAW,qBAAqB;EACnD,YAAY,WAAW,cAAc;EACrC,iBAAiB,WAAW,mBAAmB;EAC/C,iBAAiB,WAAW,mBAAmB;EAC/C,YAAY,WAAW,cAAc;EACrC,YAAY,WAAW,cAAc;EACrC,cAAc,WAAW,gBAAgB,MAAM,KAAK,KAAK;EACzD,cAAc,WAAW,gBAAgB;GAAC;GAAQ;GAAU;GAAU;EACtE,UAAU,WAAW;EACrB,WAAW,WAAW;EACtB,gBAAgB,WAAW;EAC3B,KAAK,WAAW,OAAO,EAAE;EACzB,gBAAiB,WAAW,kBAAkB,EAAE;EAChD,0BAA0B,WAAW,4BAA4B;EAEjE,MAAM,WAAW;EACjB,iBAAiB,WAAW;EAC5B,mBAAmB,WAAW;EAC/B;;;;ACvCH,IAAI,UAAmC;AAOvC,IAAI,kBAAwC;AAC5C,IAAI,yBAAwD;AAE5D,SAAS,YAA8B;AACrC,KAAI,CAAC,QACH,OAAM,IAAI,MACR,mGACD;AAEH,QAAO;;;;;;AAOT,SAAgB,kBAAkB,YAA8B;AAC9D,WAAU,gBAAgB,WAAW;;AAGvC,SAAS,iBAAiB,SAAyB;AACjD,QAAO,QAAQ,MAAM,MAAc,EAAE,SAAS,UAAU;;AAG1D,SAAS,sBAAsB,QAA0B;AACvD,KAAI,OAAO,eACT,SAAA,GAAA,6BAAA,SAA0B,OAAO,eAAe;AAElD,SAAA,GAAA,6BAAA,SAA0B,OAAO,UAAkB,cAAsB;EACvE,MAAM,WAAW,GAAG,OAAO,WAAW,GAAG,OAAO,gBAC7C,QAAQ,WAAW,SAAS,CAC5B,QAAQ,UAAU,UAAU,CAAC,GAAG,OAAO;AAG1C,MAAI,OAAO,YAAY,eAAe,QAAQ,UAAU,KACtD,KAAI;GACF,MAAM,KAAK,MAAM,OAAO;GAExB,MAAM,YADU,MAAM,OAAO,SACJ,QAAQ,QAAQ,KAAK,EAAE,SAAS,WAAW;GACpE,MAAM,UAAU,MAAM,GAAG,SAAS,UAAU,QAAQ;AACpD,UAAO,KAAK,MAAM,QAAQ;UACpB;AACN,SAAM,IAAI,MACR,mDAAmD,SAAS;;;;EAO7D;;AAKL,QAAM,IAAI,MACR,0CAA0C,SAAS,gKAEpD;GACD;;;;;;;;AASJ,eAAe,kBAAkB,QAAkD;AACjF,KAAI,iBAAiB,cAAe,QAAO;AAG3C,KAAI,uBAAwB,QAAO;AAEnC,2BAA0B,YAAY;EACpC,MAAM,gBAAA,GAAA,QAAA,iBAA+B;EAMrC,MAAM,iBAAiB,OAAO,gBAAgB;AAC9C,OAAK,CAAC,OAAO,aAAa,mBAAmB,CAAC,iBAAiB,OAAO,IAAI,CACxE,cAAa,IAAI,sBAAsB,OAAO,CAAC;AAGjD,SAAO,IAAI,SAAS,WAAgB,aAAa,IAAI,OAAO,CAAC;AAE7D,QAAM,aAAa,KAAK;GAGtB,KAAK,OAAO;GACZ,IAAI,OAAO;GACX,WAAW,OAAO;GAClB,aAAa,OAAO;GACpB,eAAe,OAAO;GACtB,0BAA0B,OAAO;GACjC,YAAY,OAAO;GACnB,SAAS,OAAO;GAChB,eAAe,EAAE,aAAa,OAAO;GACrC,GAAI,OAAO,YAAY,EAAE,WAAW,OAAO,WAAW,GAAG,EAAE;GAC3D,GAAG,OAAO;GACX,CAAC;AAEF,oBAAkB;AAClB,SAAO;KACL;AAEJ,QAAO;;AAQT,MAAM,4BAAA,GAAA,MAAA,OACJ,OAAO,MAAqB,QAA+B;CACzD,MAAM,KAAM,KAAK,QAAQ,MAA+B,EAAE;AAC1D,OAAM,KAAK,gBAAgB,CAAC,IAAI,EAAE,GAAG;EAExC;AAGD,MAAM,kBAAA,GAAA,MAAA,OAAuB,OAAO,WAA8C;CAEhF,MAAM,cADa,OAAA,GAAA,aAAA,UAAe,EACJ,IAAI,OAAO,WAAW;AACpD,KAAI,WAAY,QAAO;CAGvB,MAAM,eADc,OAAA,GAAA,aAAA,UAAe,EACH,IAAI,OAAO,WAAW,EAAE;AACxD,KAAI,aAAa;AACf,MAAI,OAAO,cAAc,SAAS,YAAY,CAC5C,QAAO;AAGT,MAAI,OAAO,0BAA0B;GACnC,MAAM,SAAS,YAAY,aAAa,CAAC,MAAM,IAAI,CAAC;GACpD,MAAM,QAAQ,OAAO,cAAc,MACjC,MAAK,EAAE,aAAa,KAAK,UAAU,EAAE,aAAa,CAAC,MAAM,IAAI,CAAC,OAAO,OACtE;AACD,OAAI,MAAO,QAAO;;;AAItB,QAAO,OAAO;EACd;;;;;;;;;;;;;;;;;;AAmBF,eAAsB,KAIpB,IACA,UAAiD,EAAE,EACjB;CAClC,MAAM,SAAS,WAAW;CAE1B,MAAM,MAAM,QAAQ,OAAO,MAAM,eAAe,OAAO;CACvD,MAAM,eAAe,MAAM,kBAAkB,OAAO;AAEpD,KAAI,OAAO,qBAAqB,QAAQ,IAAI,aAAa,aACvD,OAAM,yBAAyB,cAAc,IAAI;CAOnD,MAAM,aAHoB,KACrB,MAAM,QAAQ,GAAG,GAAG,KAAiB,CAAC,GAAa,GACpD,OAAO,IACe,QAAO,MAAK,CAAC,aAAa,mBAAmB,EAAE,CAAC;AAC1E,KAAI,UAAU,SAAS,EACrB,OAAM,aAAa,eAAe,UAAU;CAG9C,MAAM,aAAa,KACd,MAAM,QAAQ,GAAG,GAAG,GAAG,KAAK,KAC7B,OAAO;AAEX,QAAO;EACL,GAAG,aAAa,UAAU,KAAK,YAAY,QAAQ,UAAgC;EACnF,MAAM;EACN;EACD;;;;;;;;;;;;AAaH,SAAgB,aACd,MACA,YACU;CACV,MAAM,YAAsB,EAAE;CAC9B,MAAM,QAAQ,KAAK,OAAO,QAAQ,EAAE;CACpC,MAAM,WAAW,aAAa,IAAI,IAAI,WAAW,GAAG;AAEpD,MAAK,MAAM,OAAO,OAAO,KAAK,MAAM,EAAE;AACpC,YAAU,OAAO,EAAE;AACnB,OAAK,MAAM,MAAM,OAAO,KAAK,MAAM,KAAK,CACtC,KAAI,CAAC,YAAY,SAAS,IAAI,GAAG,CAC/B,WAAU,KAAK,MAAM,MAAM,KAAK;;AAKtC,QAAO;;;;;;;;;;;;;;AAeT,SAAgB,2BAA8C;AAE5D,QADe,WAAW,CACZ,cAAc,KAAI,SAAQ,EAAE,KAAK,EAAE"}
@@ -55,7 +55,11 @@ interface I18nConfig {
55
55
  };
56
56
  /** @deprecated Use i18nextOptions instead */
57
57
  serializeConfig?: boolean;
58
- /** @deprecated Pages Router only */
58
+ /**
59
+ * Dev-only: when true (and `NODE_ENV !== 'production'`), reload translation
60
+ * resources from the backend before each render so edits to locale files
61
+ * appear without restarting `next dev`. No effect in production builds.
62
+ */
59
63
  reloadOnPrerender?: boolean;
60
64
  /** Support non-explicit language codes like 'en' matching 'en-US' */
61
65
  nonExplicitSupportedLngs?: boolean;
@@ -1 +1 @@
1
- {"version":3,"file":"server.d.cts","names":[],"sources":["../../src/appRouter/types.ts","../../src/appRouter/server.ts"],"mappings":";;;KAEY,cAAA,IAAkB,QAAA,UAAkB,SAAA,aAAsB,OAAA;AAAA,UAErD,UAAA;EAFL;EAIV,aAAA;;EAEA,WAAA;EAN4B;EAQ5B,SAAA;EARoE;EAUpE,EAAA;EAV2E;EAc3E,UAAA;EAZyB;EAczB,eAAA;EAIY;EAFZ,eAAA;EA8BsB;EA5BtB,SAAA,GAAY,QAAA;EA4BS;EA1BrB,cAAA,GAAiB,cAAA;EAlBjB;EAsBA,YAAA;EAlBA;;;EAsBA,iBAAA;EAZA;EAgBA,UAAA;EAdY;EAgBZ,UAAA;EAdiB;EAgBjB,YAAA;EARA;EAUA,YAAA;EAJA;EAMA,QAAA;EAFA;EAMA,GAAA;EAAA;EAEA,cAAA,GAAiB,IAAA,CAAK,WAAA;EAAL;EAIjB,IAAA;IACE,aAAA;IACA,OAAA;IACA,OAAA;MACE,aAAA;MACA,MAAA;MACA,IAAA;MACA,OAAA;IAAA;IAEF,eAAA;EAAA;EAKF;EAFA,eAAA;EAIwB;EAFxB,iBAAA;EA+BU;EA7BV,wBAAA;AAAA;AAAA,KA6BU,UAAA,YAAsB,aAAA,GAAgB,aAAA;EAChD,CAAA,EAAG,SAAA,CAAU,EAAA,EAAI,OAAA;EACjB,IAAA,EAAM,IAAA,ECrEsC;EDuE5C,GAAA;AAAA;;;;AArGF;;;iBC8BgB,iBAAA,CAAkB,UAAA,EAAY,UAAA;;;;;;AD5B9C;;;;;;;;;;;;iBCqKsB,IAAA,YACT,aAAA,GAAgB,aAAA,kBACX,SAAA,CAAU,EAAA,cAAA,CAE1B,EAAA,GAAK,EAAA,GAAK,EAAA,IACV,OAAA;EAAW,SAAA,GAAY,OAAA;EAAS,GAAA;AAAA,IAC/B,OAAA,CAAQ,UAAA,CAAW,EAAA,EAAI,OAAA;;;;;;;;;;;iBAoCV,YAAA,CACd,IAAA,EAAM,IAAA,EACN,UAAA,cACC,QAAA;;;;;;;;;;;;;iBA6Ba,wBAAA,CAAA;EAA8B,GAAA;AAAA"}
1
+ {"version":3,"file":"server.d.cts","names":[],"sources":["../../src/appRouter/types.ts","../../src/appRouter/server.ts"],"mappings":";;;KAEY,cAAA,IAAkB,QAAA,UAAkB,SAAA,aAAsB,OAAA;AAAA,UAErD,UAAA;EAFL;EAIV,aAAA;;EAEA,WAAA;EAN4B;EAQ5B,SAAA;EARoE;EAUpE,EAAA;EAV2E;EAc3E,UAAA;EAZyB;EAczB,eAAA;EAIY;EAFZ,eAAA;EA8BsB;EA5BtB,SAAA,GAAY,QAAA;EA4BS;EA1BrB,cAAA,GAAiB,cAAA;EAlBjB;EAsBA,YAAA;EAlBA;;;EAsBA,iBAAA;EAZA;EAgBA,UAAA;EAdY;EAgBZ,UAAA;EAdiB;EAgBjB,YAAA;EARA;EAUA,YAAA;EAJA;EAMA,QAAA;EAFA;EAMA,GAAA;EAAA;EAEA,cAAA,GAAiB,IAAA,CAAK,WAAA;EAAL;EAIjB,IAAA;IACE,aAAA;IACA,OAAA;IACA,OAAA;MACE,aAAA;MACA,MAAA;MACA,IAAA;MACA,OAAA;IAAA;IAEF,eAAA;EAAA;EASF;EANA,eAAA;EAQwB;;AA6B1B;;;EA/BE,iBAAA;EA+BgD;EA7BhD,wBAAA;AAAA;AAAA,KA6BU,UAAA,YAAsB,aAAA,GAAgB,aAAA;EAChD,CAAA,EAAG,SAAA,CAAU,EAAA,EAAI,OAAA;EACjB,IAAA,EAAM,IAAA,EC4EkB;ED1ExB,GAAA;AAAA;;;;AAzGF;;;iBC8BgB,iBAAA,CAAkB,UAAA,EAAY,UAAA;;;;;;AD5B9C;;;;;;;;;;;;iBCiLsB,IAAA,YACT,aAAA,GAAgB,aAAA,kBACX,SAAA,CAAU,EAAA,cAAA,CAE1B,EAAA,GAAK,EAAA,GAAK,EAAA,IACV,OAAA;EAAW,SAAA,GAAY,OAAA;EAAS,GAAA;AAAA,IAC/B,OAAA,CAAQ,UAAA,CAAW,EAAA,EAAI,OAAA;;;;;;;;;;;iBAwCV,YAAA,CACd,IAAA,EAAM,IAAA,EACN,UAAA,cACC,QAAA;;;;;;;;;;;;;iBA6Ba,wBAAA,CAAA;EAA8B,GAAA;AAAA"}
@@ -55,7 +55,11 @@ interface I18nConfig {
55
55
  };
56
56
  /** @deprecated Use i18nextOptions instead */
57
57
  serializeConfig?: boolean;
58
- /** @deprecated Pages Router only */
58
+ /**
59
+ * Dev-only: when true (and `NODE_ENV !== 'production'`), reload translation
60
+ * resources from the backend before each render so edits to locale files
61
+ * appear without restarting `next dev`. No effect in production builds.
62
+ */
59
63
  reloadOnPrerender?: boolean;
60
64
  /** Support non-explicit language codes like 'en' matching 'en-US' */
61
65
  nonExplicitSupportedLngs?: boolean;
@@ -1 +1 @@
1
- {"version":3,"file":"server.d.mts","names":[],"sources":["../../src/appRouter/types.ts","../../src/appRouter/server.ts"],"mappings":";;;KAEY,cAAA,IAAkB,QAAA,UAAkB,SAAA,aAAsB,OAAA;AAAA,UAErD,UAAA;EAFL;EAIV,aAAA;;EAEA,WAAA;EAN4B;EAQ5B,SAAA;EARoE;EAUpE,EAAA;EAV2E;EAc3E,UAAA;EAZyB;EAczB,eAAA;EAIY;EAFZ,eAAA;EA8BsB;EA5BtB,SAAA,GAAY,QAAA;EA4BS;EA1BrB,cAAA,GAAiB,cAAA;EAlBjB;EAsBA,YAAA;EAlBA;;;EAsBA,iBAAA;EAZA;EAgBA,UAAA;EAdY;EAgBZ,UAAA;EAdiB;EAgBjB,YAAA;EARA;EAUA,YAAA;EAJA;EAMA,QAAA;EAFA;EAMA,GAAA;EAAA;EAEA,cAAA,GAAiB,IAAA,CAAK,WAAA;EAAL;EAIjB,IAAA;IACE,aAAA;IACA,OAAA;IACA,OAAA;MACE,aAAA;MACA,MAAA;MACA,IAAA;MACA,OAAA;IAAA;IAEF,eAAA;EAAA;EAKF;EAFA,eAAA;EAIwB;EAFxB,iBAAA;EA+BU;EA7BV,wBAAA;AAAA;AAAA,KA6BU,UAAA,YAAsB,aAAA,GAAgB,aAAA;EAChD,CAAA,EAAG,SAAA,CAAU,EAAA,EAAI,OAAA;EACjB,IAAA,EAAM,IAAA,ECrEsC;EDuE5C,GAAA;AAAA;;;;AArGF;;;iBC8BgB,iBAAA,CAAkB,UAAA,EAAY,UAAA;;;;;;AD5B9C;;;;;;;;;;;;iBCqKsB,IAAA,YACT,aAAA,GAAgB,aAAA,kBACX,SAAA,CAAU,EAAA,cAAA,CAE1B,EAAA,GAAK,EAAA,GAAK,EAAA,IACV,OAAA;EAAW,SAAA,GAAY,OAAA;EAAS,GAAA;AAAA,IAC/B,OAAA,CAAQ,UAAA,CAAW,EAAA,EAAI,OAAA;;;;;;;;;;;iBAoCV,YAAA,CACd,IAAA,EAAM,IAAA,EACN,UAAA,cACC,QAAA;;;;;;;;;;;;;iBA6Ba,wBAAA,CAAA;EAA8B,GAAA;AAAA"}
1
+ {"version":3,"file":"server.d.mts","names":[],"sources":["../../src/appRouter/types.ts","../../src/appRouter/server.ts"],"mappings":";;;KAEY,cAAA,IAAkB,QAAA,UAAkB,SAAA,aAAsB,OAAA;AAAA,UAErD,UAAA;EAFL;EAIV,aAAA;;EAEA,WAAA;EAN4B;EAQ5B,SAAA;EARoE;EAUpE,EAAA;EAV2E;EAc3E,UAAA;EAZyB;EAczB,eAAA;EAIY;EAFZ,eAAA;EA8BsB;EA5BtB,SAAA,GAAY,QAAA;EA4BS;EA1BrB,cAAA,GAAiB,cAAA;EAlBjB;EAsBA,YAAA;EAlBA;;;EAsBA,iBAAA;EAZA;EAgBA,UAAA;EAdY;EAgBZ,UAAA;EAdiB;EAgBjB,YAAA;EARA;EAUA,YAAA;EAJA;EAMA,QAAA;EAFA;EAMA,GAAA;EAAA;EAEA,cAAA,GAAiB,IAAA,CAAK,WAAA;EAAL;EAIjB,IAAA;IACE,aAAA;IACA,OAAA;IACA,OAAA;MACE,aAAA;MACA,MAAA;MACA,IAAA;MACA,OAAA;IAAA;IAEF,eAAA;EAAA;EASF;EANA,eAAA;EAQwB;;AA6B1B;;;EA/BE,iBAAA;EA+BgD;EA7BhD,wBAAA;AAAA;AAAA,KA6BU,UAAA,YAAsB,aAAA,GAAgB,aAAA;EAChD,CAAA,EAAG,SAAA,CAAU,EAAA,EAAI,OAAA;EACjB,IAAA,EAAM,IAAA,EC4EkB;ED1ExB,GAAA;AAAA;;;;AAzGF;;;iBC8BgB,iBAAA,CAAkB,UAAA,EAAY,UAAA;;;;;;AD5B9C;;;;;;;;;;;;iBCiLsB,IAAA,YACT,aAAA,GAAgB,aAAA,kBACX,SAAA,CAAU,EAAA,cAAA,CAE1B,EAAA,GAAK,EAAA,GAAK,EAAA,IACV,OAAA;EAAW,SAAA,GAAY,OAAA;EAAS,GAAA;AAAA,IAC/B,OAAA,CAAQ,UAAA,CAAW,EAAA,EAAI,OAAA;;;;;;;;;;;iBAwCV,YAAA,CACd,IAAA,EAAM,IAAA,EACN,UAAA,cACC,QAAA;;;;;;;;;;;;;iBA6Ba,wBAAA,CAAA;EAA8B,GAAA;AAAA"}
@@ -108,6 +108,10 @@ async function getSharedInstance(config) {
108
108
  })();
109
109
  return _sharedInstancePromise;
110
110
  }
111
+ const reloadResourcesForRender = cache(async (i18n, lng) => {
112
+ const ns = i18n.options.ns ?? [];
113
+ await i18n.reloadResources([lng], ns);
114
+ });
111
115
  const detectLanguage = cache(async (config) => {
112
116
  const fromHeader = (await headers()).get(config.headerName);
113
117
  if (fromHeader) return fromHeader;
@@ -143,6 +147,7 @@ async function getT(ns, options = {}) {
143
147
  const config = getConfig();
144
148
  const lng = options.lng || await detectLanguage(config);
145
149
  const i18nInstance = await getSharedInstance(config);
150
+ if (config.reloadOnPrerender && process.env.NODE_ENV !== "production") await reloadResourcesForRender(i18nInstance, lng);
146
151
  const missingNs = (ns ? Array.isArray(ns) ? ns : [ns] : config.ns).filter((n) => !i18nInstance.hasLoadedNamespace(n));
147
152
  if (missingNs.length > 0) await i18nInstance.loadNamespaces(missingNs);
148
153
  const resolvedNs = ns ? Array.isArray(ns) ? ns[0] : ns : config.defaultNS;
@@ -1 +1 @@
1
- {"version":3,"file":"server.mjs","names":[],"sources":["../../src/appRouter/config.ts","../../src/appRouter/server.ts"],"sourcesContent":["import type { I18nConfig, NormalizedConfig } from './types'\n\nexport function defineConfig(config: I18nConfig): I18nConfig {\n return config\n}\n\nexport function normalizeConfig(userConfig: I18nConfig): NormalizedConfig {\n // Support legacy format: { i18n: { defaultLocale, locales } }\n const supportedLngs = userConfig.supportedLngs ??\n userConfig.i18n?.locales?.filter((l: string) => l !== 'default') ??\n ['en']\n const fallbackLng = userConfig.fallbackLng ??\n userConfig.i18n?.defaultLocale ??\n supportedLngs[0]\n\n if (!fallbackLng) {\n throw new Error('next-i18next: fallbackLng (or i18n.defaultLocale) is required')\n }\n if (supportedLngs.length === 0) {\n throw new Error('next-i18next: supportedLngs (or i18n.locales) must contain at least one language')\n }\n\n const defaultNS = userConfig.defaultNS ?? 'common'\n\n return {\n supportedLngs,\n fallbackLng,\n defaultNS,\n ns: userConfig.ns ?? [defaultNS],\n localeInPath: userConfig.localeInPath ?? true,\n hideDefaultLocale: userConfig.hideDefaultLocale ?? false,\n localePath: userConfig.localePath ?? '/locales',\n localeStructure: userConfig.localeStructure ?? '{{lng}}/{{ns}}',\n localeExtension: userConfig.localeExtension ?? 'json',\n cookieName: userConfig.cookieName ?? 'i18next',\n headerName: userConfig.headerName ?? 'x-i18next-current-language',\n cookieMaxAge: userConfig.cookieMaxAge ?? 365 * 24 * 60 * 60,\n ignoredPaths: userConfig.ignoredPaths ?? ['/api', '/_next', '/static'],\n basePath: userConfig.basePath,\n resources: userConfig.resources,\n resourceLoader: userConfig.resourceLoader,\n use: userConfig.use ?? [],\n i18nextOptions: (userConfig.i18nextOptions ?? {}) as Record<string, any>,\n nonExplicitSupportedLngs: userConfig.nonExplicitSupportedLngs ?? false,\n // Preserve legacy fields\n i18n: userConfig.i18n,\n serializeConfig: userConfig.serializeConfig,\n reloadOnPrerender: userConfig.reloadOnPrerender,\n }\n}\n","import { createInstance } from 'i18next'\nimport type { i18n as I18NextClient, Resource, Module, FlatNamespace, KeyPrefix } from 'i18next'\nimport resourcesToBackend from 'i18next-resources-to-backend'\nimport { cache } from 'react'\nimport { headers, cookies } from 'next/headers'\n\nimport type { I18nConfig, NormalizedConfig, GetTResult } from './types'\nimport { normalizeConfig } from './config'\n\nlet _config: NormalizedConfig | null = null\n\n// Module-level singleton: persists across requests within the same server process.\n// This is critical for custom backends (i18next-http-backend, i18next-locize-backend)\n// to avoid re-fetching translations on every request.\n// In serverless environments (Lambda, Cloud Functions, etc.), this lives as long as\n// the warm function instance — backends with reloadInterval will refresh automatically.\nlet _sharedInstance: I18NextClient | null = null\nlet _sharedInstancePromise: Promise<I18NextClient> | null = null\n\nfunction getConfig(): NormalizedConfig {\n if (!_config) {\n throw new Error(\n 'next-i18next: Server module not initialized. Call initServerI18next(config) in your root layout.'\n )\n }\n return _config\n}\n\n/**\n * Initialize the server-side i18next configuration.\n * Call this once in your root layout or a shared setup file.\n */\nexport function initServerI18next(userConfig: I18nConfig): void {\n _config = normalizeConfig(userConfig)\n}\n\nfunction hasCustomBackend(plugins: any[]): boolean {\n return plugins.some((b: Module) => b.type === 'backend')\n}\n\nfunction createResourceBackend(config: NormalizedConfig) {\n if (config.resourceLoader) {\n return resourcesToBackend(config.resourceLoader)\n }\n return resourcesToBackend(async (language: string, namespace: string) => {\n const filePath = `${config.localePath}/${config.localeStructure\n .replace('{{lng}}', language)\n .replace('{{ns}}', namespace)}.${config.localeExtension}`\n\n // Node.js runtime: read from filesystem\n if (typeof process !== 'undefined' && process.versions?.node) {\n try {\n const fs = await import('fs/promises')\n const pathMod = await import('path')\n const resolved = pathMod.resolve(process.cwd(), `public${filePath}`)\n const content = await fs.readFile(resolved, 'utf-8')\n return JSON.parse(content)\n } catch {\n throw new Error(\n `next-i18next: Could not read locale file \"public${filePath}\". ` +\n 'On serverless platforms (Vercel, AWS Lambda, etc.), files in public/ are served via CDN ' +\n 'but are NOT available on the filesystem at runtime. Use the `resourceLoader` option with ' +\n 'dynamic imports instead:\\n\\n' +\n ' resourceLoader: (language, namespace) =>\\n' +\n // eslint-disable-next-line no-template-curly-in-string\n ' import(`./public/locales/${language}/${namespace}.json`)\\n'\n )\n }\n }\n\n // Edge runtime: filesystem not available\n throw new Error(\n `next-i18next: Cannot load locale file \"${filePath}\" in Edge Runtime. ` +\n 'Provide pre-bundled `resources`, a custom `resourceLoader`, or use a custom backend (e.g. i18next-http-backend) via the `use` option.'\n )\n })\n}\n\n/**\n * Get or create the shared i18next instance.\n * The instance is created once and reused across all requests.\n * All languages are preloaded so that getFixedT(lng) works for any supported language.\n * Additional namespaces are loaded on demand and cached in the instance store.\n */\nasync function getSharedInstance(config: NormalizedConfig): Promise<I18NextClient> {\n if (_sharedInstance?.isInitialized) return _sharedInstance\n\n // Deduplicate concurrent init calls (multiple requests arriving while first init is in flight)\n if (_sharedInstancePromise) return _sharedInstancePromise\n\n _sharedInstancePromise = (async () => {\n const i18nInstance = createInstance()\n\n // Add a backend when needed:\n // - No resources provided → backend loads everything\n // - Resources provided with partialBundledLanguages → backend loads the rest\n // - Custom backend in config.use → user handles it, skip default backend\n const partialBundled = config.i18nextOptions?.partialBundledLanguages\n if ((!config.resources || partialBundled) && !hasCustomBackend(config.use)) {\n i18nInstance.use(createResourceBackend(config))\n }\n\n config.use.forEach((plugin: any) => i18nInstance.use(plugin))\n\n await i18nInstance.init({\n // No `lng` — the shared instance is language-neutral.\n // We use getFixedT(lng, ns) to get language-specific translators.\n lng: config.fallbackLng,\n ns: config.ns,\n defaultNS: config.defaultNS,\n fallbackLng: config.fallbackLng,\n supportedLngs: config.supportedLngs,\n nonExplicitSupportedLngs: config.nonExplicitSupportedLngs,\n fallbackNS: config.defaultNS,\n preload: config.supportedLngs, // preload ALL languages upfront\n interpolation: { escapeValue: false },\n ...(config.resources ? { resources: config.resources } : {}),\n ...config.i18nextOptions,\n })\n\n _sharedInstance = i18nInstance\n return i18nInstance\n })()\n\n return _sharedInstancePromise\n}\n\n// Per-request language detection, deduplicated within a single React render\nconst detectLanguage = cache(async (config: NormalizedConfig): Promise<string> => {\n const headerList = await headers()\n const fromHeader = headerList.get(config.headerName)\n if (fromHeader) return fromHeader\n\n const cookieStore = await cookies()\n const cookieValue = cookieStore.get(config.cookieName)?.value\n if (cookieValue) {\n if (config.supportedLngs.includes(cookieValue)) {\n return cookieValue\n }\n // nonExplicitSupportedLngs: e.g. cookie 'en' matches supported 'en-US'\n if (config.nonExplicitSupportedLngs) {\n const prefix = cookieValue.toLowerCase().split('-')[0]\n const match = config.supportedLngs.find(\n l => l.toLowerCase() === prefix || l.toLowerCase().split('-')[0] === prefix\n )\n if (match) return match\n }\n }\n\n return config.fallbackLng\n})\n\n/**\n * Get a translation function for use in Server Components, layouts, and generateMetadata.\n *\n * The underlying i18next instance is a **module-level singleton** that persists across\n * requests. This means custom backends (i18next-http-backend, i18next-locize-backend, etc.)\n * only fetch translations once (or according to their own reloadInterval), not on every request.\n *\n * @example\n * ```tsx\n * import { getT } from 'next-i18next/server'\n *\n * export default async function Page() {\n * const { t, i18n } = await getT('home')\n * return <h1>{t('heading')}</h1>\n * }\n * ```\n */\nexport async function getT<\n Ns extends FlatNamespace = FlatNamespace,\n KPrefix extends KeyPrefix<Ns> = undefined,\n>(\n ns?: Ns | Ns[],\n options: { keyPrefix?: KPrefix; lng?: string } = {},\n): Promise<GetTResult<Ns, KPrefix>> {\n const config = getConfig()\n\n const lng = options.lng || await detectLanguage(config)\n const i18nInstance = await getSharedInstance(config)\n\n // Load additional namespaces on demand if not already loaded\n const nsArray: string[] = ns\n ? (Array.isArray(ns) ? ns as string[] : [ns as string])\n : config.ns\n const missingNs = nsArray.filter(n => !i18nInstance.hasLoadedNamespace(n))\n if (missingNs.length > 0) {\n await i18nInstance.loadNamespaces(missingNs)\n }\n\n const resolvedNs = ns\n ? (Array.isArray(ns) ? ns[0] : ns) as string\n : config.defaultNS\n\n return {\n t: i18nInstance.getFixedT(lng, resolvedNs, options.keyPrefix as string | undefined),\n i18n: i18nInstance,\n lng,\n } as any\n}\n\n/**\n * Extract loaded resources from the server i18next instance for passing to I18nProvider.\n *\n * @example\n * ```tsx\n * const { i18n } = await getT()\n * const resources = getResources(i18n, ['common', 'footer'])\n * return <I18nProvider language={i18n.language} resources={resources}>{children}</I18nProvider>\n * ```\n */\nexport function getResources(\n i18n: I18NextClient,\n namespaces?: string[],\n): Resource {\n const resources: Resource = {}\n const store = i18n.store?.data || {}\n const nsFilter = namespaces ? new Set(namespaces) : null\n\n for (const lng of Object.keys(store)) {\n resources[lng] = {}\n for (const ns of Object.keys(store[lng])) {\n if (!nsFilter || nsFilter.has(ns)) {\n resources[lng][ns] = store[lng][ns]\n }\n }\n }\n\n return resources\n}\n\n/**\n * Helper for generateStaticParams — returns params for all supported languages.\n *\n * @example\n * ```tsx\n * import { generateI18nStaticParams } from 'next-i18next/server'\n *\n * export async function generateStaticParams() {\n * return generateI18nStaticParams()\n * }\n * ```\n */\nexport function generateI18nStaticParams(): { lng: string }[] {\n const config = getConfig()\n return config.supportedLngs.map(lng => ({ lng }))\n}\n"],"mappings":";;;;;AAMA,SAAgB,gBAAgB,YAA0C;CAExE,MAAM,gBAAgB,WAAW,iBAC/B,WAAW,MAAM,SAAS,QAAQ,MAAc,MAAM,UAAU,IAChE,CAAC,KAAK;CACR,MAAM,cAAc,WAAW,eAC7B,WAAW,MAAM,iBACjB,cAAc;AAEhB,KAAI,CAAC,YACH,OAAM,IAAI,MAAM,gEAAgE;AAElF,KAAI,cAAc,WAAW,EAC3B,OAAM,IAAI,MAAM,mFAAmF;CAGrG,MAAM,YAAY,WAAW,aAAa;AAE1C,QAAO;EACL;EACA;EACA;EACA,IAAI,WAAW,MAAM,CAAC,UAAU;EAChC,cAAc,WAAW,gBAAgB;EACzC,mBAAmB,WAAW,qBAAqB;EACnD,YAAY,WAAW,cAAc;EACrC,iBAAiB,WAAW,mBAAmB;EAC/C,iBAAiB,WAAW,mBAAmB;EAC/C,YAAY,WAAW,cAAc;EACrC,YAAY,WAAW,cAAc;EACrC,cAAc,WAAW,gBAAgB,MAAM,KAAK,KAAK;EACzD,cAAc,WAAW,gBAAgB;GAAC;GAAQ;GAAU;GAAU;EACtE,UAAU,WAAW;EACrB,WAAW,WAAW;EACtB,gBAAgB,WAAW;EAC3B,KAAK,WAAW,OAAO,EAAE;EACzB,gBAAiB,WAAW,kBAAkB,EAAE;EAChD,0BAA0B,WAAW,4BAA4B;EAEjE,MAAM,WAAW;EACjB,iBAAiB,WAAW;EAC5B,mBAAmB,WAAW;EAC/B;;;;ACvCH,IAAI,UAAmC;AAOvC,IAAI,kBAAwC;AAC5C,IAAI,yBAAwD;AAE5D,SAAS,YAA8B;AACrC,KAAI,CAAC,QACH,OAAM,IAAI,MACR,mGACD;AAEH,QAAO;;;;;;AAOT,SAAgB,kBAAkB,YAA8B;AAC9D,WAAU,gBAAgB,WAAW;;AAGvC,SAAS,iBAAiB,SAAyB;AACjD,QAAO,QAAQ,MAAM,MAAc,EAAE,SAAS,UAAU;;AAG1D,SAAS,sBAAsB,QAA0B;AACvD,KAAI,OAAO,eACT,QAAO,mBAAmB,OAAO,eAAe;AAElD,QAAO,mBAAmB,OAAO,UAAkB,cAAsB;EACvE,MAAM,WAAW,GAAG,OAAO,WAAW,GAAG,OAAO,gBAC7C,QAAQ,WAAW,SAAS,CAC5B,QAAQ,UAAU,UAAU,CAAC,GAAG,OAAO;AAG1C,MAAI,OAAO,YAAY,eAAe,QAAQ,UAAU,KACtD,KAAI;GACF,MAAM,KAAK,MAAM,OAAO;GAExB,MAAM,YADU,MAAM,OAAO,SACJ,QAAQ,QAAQ,KAAK,EAAE,SAAS,WAAW;GACpE,MAAM,UAAU,MAAM,GAAG,SAAS,UAAU,QAAQ;AACpD,UAAO,KAAK,MAAM,QAAQ;UACpB;AACN,SAAM,IAAI,MACR,mDAAmD,SAAS;;;;EAO7D;;AAKL,QAAM,IAAI,MACR,0CAA0C,SAAS,gKAEpD;GACD;;;;;;;;AASJ,eAAe,kBAAkB,QAAkD;AACjF,KAAI,iBAAiB,cAAe,QAAO;AAG3C,KAAI,uBAAwB,QAAO;AAEnC,2BAA0B,YAAY;EACpC,MAAM,eAAe,gBAAgB;EAMrC,MAAM,iBAAiB,OAAO,gBAAgB;AAC9C,OAAK,CAAC,OAAO,aAAa,mBAAmB,CAAC,iBAAiB,OAAO,IAAI,CACxE,cAAa,IAAI,sBAAsB,OAAO,CAAC;AAGjD,SAAO,IAAI,SAAS,WAAgB,aAAa,IAAI,OAAO,CAAC;AAE7D,QAAM,aAAa,KAAK;GAGtB,KAAK,OAAO;GACZ,IAAI,OAAO;GACX,WAAW,OAAO;GAClB,aAAa,OAAO;GACpB,eAAe,OAAO;GACtB,0BAA0B,OAAO;GACjC,YAAY,OAAO;GACnB,SAAS,OAAO;GAChB,eAAe,EAAE,aAAa,OAAO;GACrC,GAAI,OAAO,YAAY,EAAE,WAAW,OAAO,WAAW,GAAG,EAAE;GAC3D,GAAG,OAAO;GACX,CAAC;AAEF,oBAAkB;AAClB,SAAO;KACL;AAEJ,QAAO;;AAIT,MAAM,iBAAiB,MAAM,OAAO,WAA8C;CAEhF,MAAM,cADa,MAAM,SAAS,EACJ,IAAI,OAAO,WAAW;AACpD,KAAI,WAAY,QAAO;CAGvB,MAAM,eADc,MAAM,SAAS,EACH,IAAI,OAAO,WAAW,EAAE;AACxD,KAAI,aAAa;AACf,MAAI,OAAO,cAAc,SAAS,YAAY,CAC5C,QAAO;AAGT,MAAI,OAAO,0BAA0B;GACnC,MAAM,SAAS,YAAY,aAAa,CAAC,MAAM,IAAI,CAAC;GACpD,MAAM,QAAQ,OAAO,cAAc,MACjC,MAAK,EAAE,aAAa,KAAK,UAAU,EAAE,aAAa,CAAC,MAAM,IAAI,CAAC,OAAO,OACtE;AACD,OAAI,MAAO,QAAO;;;AAItB,QAAO,OAAO;EACd;;;;;;;;;;;;;;;;;;AAmBF,eAAsB,KAIpB,IACA,UAAiD,EAAE,EACjB;CAClC,MAAM,SAAS,WAAW;CAE1B,MAAM,MAAM,QAAQ,OAAO,MAAM,eAAe,OAAO;CACvD,MAAM,eAAe,MAAM,kBAAkB,OAAO;CAMpD,MAAM,aAHoB,KACrB,MAAM,QAAQ,GAAG,GAAG,KAAiB,CAAC,GAAa,GACpD,OAAO,IACe,QAAO,MAAK,CAAC,aAAa,mBAAmB,EAAE,CAAC;AAC1E,KAAI,UAAU,SAAS,EACrB,OAAM,aAAa,eAAe,UAAU;CAG9C,MAAM,aAAa,KACd,MAAM,QAAQ,GAAG,GAAG,GAAG,KAAK,KAC7B,OAAO;AAEX,QAAO;EACL,GAAG,aAAa,UAAU,KAAK,YAAY,QAAQ,UAAgC;EACnF,MAAM;EACN;EACD;;;;;;;;;;;;AAaH,SAAgB,aACd,MACA,YACU;CACV,MAAM,YAAsB,EAAE;CAC9B,MAAM,QAAQ,KAAK,OAAO,QAAQ,EAAE;CACpC,MAAM,WAAW,aAAa,IAAI,IAAI,WAAW,GAAG;AAEpD,MAAK,MAAM,OAAO,OAAO,KAAK,MAAM,EAAE;AACpC,YAAU,OAAO,EAAE;AACnB,OAAK,MAAM,MAAM,OAAO,KAAK,MAAM,KAAK,CACtC,KAAI,CAAC,YAAY,SAAS,IAAI,GAAG,CAC/B,WAAU,KAAK,MAAM,MAAM,KAAK;;AAKtC,QAAO;;;;;;;;;;;;;;AAeT,SAAgB,2BAA8C;AAE5D,QADe,WAAW,CACZ,cAAc,KAAI,SAAQ,EAAE,KAAK,EAAE"}
1
+ {"version":3,"file":"server.mjs","names":[],"sources":["../../src/appRouter/config.ts","../../src/appRouter/server.ts"],"sourcesContent":["import type { I18nConfig, NormalizedConfig } from './types'\n\nexport function defineConfig(config: I18nConfig): I18nConfig {\n return config\n}\n\nexport function normalizeConfig(userConfig: I18nConfig): NormalizedConfig {\n // Support legacy format: { i18n: { defaultLocale, locales } }\n const supportedLngs = userConfig.supportedLngs ??\n userConfig.i18n?.locales?.filter((l: string) => l !== 'default') ??\n ['en']\n const fallbackLng = userConfig.fallbackLng ??\n userConfig.i18n?.defaultLocale ??\n supportedLngs[0]\n\n if (!fallbackLng) {\n throw new Error('next-i18next: fallbackLng (or i18n.defaultLocale) is required')\n }\n if (supportedLngs.length === 0) {\n throw new Error('next-i18next: supportedLngs (or i18n.locales) must contain at least one language')\n }\n\n const defaultNS = userConfig.defaultNS ?? 'common'\n\n return {\n supportedLngs,\n fallbackLng,\n defaultNS,\n ns: userConfig.ns ?? [defaultNS],\n localeInPath: userConfig.localeInPath ?? true,\n hideDefaultLocale: userConfig.hideDefaultLocale ?? false,\n localePath: userConfig.localePath ?? '/locales',\n localeStructure: userConfig.localeStructure ?? '{{lng}}/{{ns}}',\n localeExtension: userConfig.localeExtension ?? 'json',\n cookieName: userConfig.cookieName ?? 'i18next',\n headerName: userConfig.headerName ?? 'x-i18next-current-language',\n cookieMaxAge: userConfig.cookieMaxAge ?? 365 * 24 * 60 * 60,\n ignoredPaths: userConfig.ignoredPaths ?? ['/api', '/_next', '/static'],\n basePath: userConfig.basePath,\n resources: userConfig.resources,\n resourceLoader: userConfig.resourceLoader,\n use: userConfig.use ?? [],\n i18nextOptions: (userConfig.i18nextOptions ?? {}) as Record<string, any>,\n nonExplicitSupportedLngs: userConfig.nonExplicitSupportedLngs ?? false,\n // Preserve legacy fields\n i18n: userConfig.i18n,\n serializeConfig: userConfig.serializeConfig,\n reloadOnPrerender: userConfig.reloadOnPrerender,\n }\n}\n","import { createInstance } from 'i18next'\nimport type { i18n as I18NextClient, Resource, Module, FlatNamespace, KeyPrefix } from 'i18next'\nimport resourcesToBackend from 'i18next-resources-to-backend'\nimport { cache } from 'react'\nimport { headers, cookies } from 'next/headers'\n\nimport type { I18nConfig, NormalizedConfig, GetTResult } from './types'\nimport { normalizeConfig } from './config'\n\nlet _config: NormalizedConfig | null = null\n\n// Module-level singleton: persists across requests within the same server process.\n// This is critical for custom backends (i18next-http-backend, i18next-locize-backend)\n// to avoid re-fetching translations on every request.\n// In serverless environments (Lambda, Cloud Functions, etc.), this lives as long as\n// the warm function instance — backends with reloadInterval will refresh automatically.\nlet _sharedInstance: I18NextClient | null = null\nlet _sharedInstancePromise: Promise<I18NextClient> | null = null\n\nfunction getConfig(): NormalizedConfig {\n if (!_config) {\n throw new Error(\n 'next-i18next: Server module not initialized. Call initServerI18next(config) in your root layout.'\n )\n }\n return _config\n}\n\n/**\n * Initialize the server-side i18next configuration.\n * Call this once in your root layout or a shared setup file.\n */\nexport function initServerI18next(userConfig: I18nConfig): void {\n _config = normalizeConfig(userConfig)\n}\n\nfunction hasCustomBackend(plugins: any[]): boolean {\n return plugins.some((b: Module) => b.type === 'backend')\n}\n\nfunction createResourceBackend(config: NormalizedConfig) {\n if (config.resourceLoader) {\n return resourcesToBackend(config.resourceLoader)\n }\n return resourcesToBackend(async (language: string, namespace: string) => {\n const filePath = `${config.localePath}/${config.localeStructure\n .replace('{{lng}}', language)\n .replace('{{ns}}', namespace)}.${config.localeExtension}`\n\n // Node.js runtime: read from filesystem\n if (typeof process !== 'undefined' && process.versions?.node) {\n try {\n const fs = await import('fs/promises')\n const pathMod = await import('path')\n const resolved = pathMod.resolve(process.cwd(), `public${filePath}`)\n const content = await fs.readFile(resolved, 'utf-8')\n return JSON.parse(content)\n } catch {\n throw new Error(\n `next-i18next: Could not read locale file \"public${filePath}\". ` +\n 'On serverless platforms (Vercel, AWS Lambda, etc.), files in public/ are served via CDN ' +\n 'but are NOT available on the filesystem at runtime. Use the `resourceLoader` option with ' +\n 'dynamic imports instead:\\n\\n' +\n ' resourceLoader: (language, namespace) =>\\n' +\n // eslint-disable-next-line no-template-curly-in-string\n ' import(`./public/locales/${language}/${namespace}.json`)\\n'\n )\n }\n }\n\n // Edge runtime: filesystem not available\n throw new Error(\n `next-i18next: Cannot load locale file \"${filePath}\" in Edge Runtime. ` +\n 'Provide pre-bundled `resources`, a custom `resourceLoader`, or use a custom backend (e.g. i18next-http-backend) via the `use` option.'\n )\n })\n}\n\n/**\n * Get or create the shared i18next instance.\n * The instance is created once and reused across all requests.\n * All languages are preloaded so that getFixedT(lng) works for any supported language.\n * Additional namespaces are loaded on demand and cached in the instance store.\n */\nasync function getSharedInstance(config: NormalizedConfig): Promise<I18NextClient> {\n if (_sharedInstance?.isInitialized) return _sharedInstance\n\n // Deduplicate concurrent init calls (multiple requests arriving while first init is in flight)\n if (_sharedInstancePromise) return _sharedInstancePromise\n\n _sharedInstancePromise = (async () => {\n const i18nInstance = createInstance()\n\n // Add a backend when needed:\n // - No resources provided → backend loads everything\n // - Resources provided with partialBundledLanguages → backend loads the rest\n // - Custom backend in config.use → user handles it, skip default backend\n const partialBundled = config.i18nextOptions?.partialBundledLanguages\n if ((!config.resources || partialBundled) && !hasCustomBackend(config.use)) {\n i18nInstance.use(createResourceBackend(config))\n }\n\n config.use.forEach((plugin: any) => i18nInstance.use(plugin))\n\n await i18nInstance.init({\n // No `lng` — the shared instance is language-neutral.\n // We use getFixedT(lng, ns) to get language-specific translators.\n lng: config.fallbackLng,\n ns: config.ns,\n defaultNS: config.defaultNS,\n fallbackLng: config.fallbackLng,\n supportedLngs: config.supportedLngs,\n nonExplicitSupportedLngs: config.nonExplicitSupportedLngs,\n fallbackNS: config.defaultNS,\n preload: config.supportedLngs, // preload ALL languages upfront\n interpolation: { escapeValue: false },\n ...(config.resources ? { resources: config.resources } : {}),\n ...config.i18nextOptions,\n })\n\n _sharedInstance = i18nInstance\n return i18nInstance\n })()\n\n return _sharedInstancePromise\n}\n\n// Dev-only hot-reload: refetch resources for the requested language so edits\n// to locale files appear without restarting `next dev`. Wrapped in `cache()`\n// so multiple `getT` calls within the same render dedupe to a single reload.\n// Gated on `NODE_ENV !== 'production'` at the call site so HTTP/locize/chained\n// backends are never refetched per-request in prod.\nconst reloadResourcesForRender = cache(\n async (i18n: I18NextClient, lng: string): Promise<void> => {\n const ns = (i18n.options.ns as string[] | undefined) ?? []\n await i18n.reloadResources([lng], ns)\n }\n)\n\n// Per-request language detection, deduplicated within a single React render\nconst detectLanguage = cache(async (config: NormalizedConfig): Promise<string> => {\n const headerList = await headers()\n const fromHeader = headerList.get(config.headerName)\n if (fromHeader) return fromHeader\n\n const cookieStore = await cookies()\n const cookieValue = cookieStore.get(config.cookieName)?.value\n if (cookieValue) {\n if (config.supportedLngs.includes(cookieValue)) {\n return cookieValue\n }\n // nonExplicitSupportedLngs: e.g. cookie 'en' matches supported 'en-US'\n if (config.nonExplicitSupportedLngs) {\n const prefix = cookieValue.toLowerCase().split('-')[0]\n const match = config.supportedLngs.find(\n l => l.toLowerCase() === prefix || l.toLowerCase().split('-')[0] === prefix\n )\n if (match) return match\n }\n }\n\n return config.fallbackLng\n})\n\n/**\n * Get a translation function for use in Server Components, layouts, and generateMetadata.\n *\n * The underlying i18next instance is a **module-level singleton** that persists across\n * requests. This means custom backends (i18next-http-backend, i18next-locize-backend, etc.)\n * only fetch translations once (or according to their own reloadInterval), not on every request.\n *\n * @example\n * ```tsx\n * import { getT } from 'next-i18next/server'\n *\n * export default async function Page() {\n * const { t, i18n } = await getT('home')\n * return <h1>{t('heading')}</h1>\n * }\n * ```\n */\nexport async function getT<\n Ns extends FlatNamespace = FlatNamespace,\n KPrefix extends KeyPrefix<Ns> = undefined,\n>(\n ns?: Ns | Ns[],\n options: { keyPrefix?: KPrefix; lng?: string } = {},\n): Promise<GetTResult<Ns, KPrefix>> {\n const config = getConfig()\n\n const lng = options.lng || await detectLanguage(config)\n const i18nInstance = await getSharedInstance(config)\n\n if (config.reloadOnPrerender && process.env.NODE_ENV !== 'production') {\n await reloadResourcesForRender(i18nInstance, lng)\n }\n\n // Load additional namespaces on demand if not already loaded\n const nsArray: string[] = ns\n ? (Array.isArray(ns) ? ns as string[] : [ns as string])\n : config.ns\n const missingNs = nsArray.filter(n => !i18nInstance.hasLoadedNamespace(n))\n if (missingNs.length > 0) {\n await i18nInstance.loadNamespaces(missingNs)\n }\n\n const resolvedNs = ns\n ? (Array.isArray(ns) ? ns[0] : ns) as string\n : config.defaultNS\n\n return {\n t: i18nInstance.getFixedT(lng, resolvedNs, options.keyPrefix as string | undefined),\n i18n: i18nInstance,\n lng,\n } as any\n}\n\n/**\n * Extract loaded resources from the server i18next instance for passing to I18nProvider.\n *\n * @example\n * ```tsx\n * const { i18n } = await getT()\n * const resources = getResources(i18n, ['common', 'footer'])\n * return <I18nProvider language={i18n.language} resources={resources}>{children}</I18nProvider>\n * ```\n */\nexport function getResources(\n i18n: I18NextClient,\n namespaces?: string[],\n): Resource {\n const resources: Resource = {}\n const store = i18n.store?.data || {}\n const nsFilter = namespaces ? new Set(namespaces) : null\n\n for (const lng of Object.keys(store)) {\n resources[lng] = {}\n for (const ns of Object.keys(store[lng])) {\n if (!nsFilter || nsFilter.has(ns)) {\n resources[lng][ns] = store[lng][ns]\n }\n }\n }\n\n return resources\n}\n\n/**\n * Helper for generateStaticParams — returns params for all supported languages.\n *\n * @example\n * ```tsx\n * import { generateI18nStaticParams } from 'next-i18next/server'\n *\n * export async function generateStaticParams() {\n * return generateI18nStaticParams()\n * }\n * ```\n */\nexport function generateI18nStaticParams(): { lng: string }[] {\n const config = getConfig()\n return config.supportedLngs.map(lng => ({ lng }))\n}\n"],"mappings":"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"}
@@ -2,7 +2,6 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
2
  const require_runtime = require("./_virtual/_rolldown/runtime.cjs");
3
3
  const require_utils = require("./utils.cjs");
4
4
  const require_config_createConfig = require("./config/createConfig.cjs");
5
- const require_appWithTranslation = require("./appWithTranslation.cjs");
6
5
  const require_createClient_node = require("./createClient/node.cjs");
7
6
  let fs = require("fs");
8
7
  fs = require_runtime.__toESM(fs);
@@ -29,7 +28,6 @@ const serverSideTranslations = async (initialLocale, namespacesRequired = void 0
29
28
  lng: initialLocale
30
29
  });
31
30
  const { localeExtension, localePath, fallbackLng, reloadOnPrerender } = config;
32
- if (reloadOnPrerender) await require_appWithTranslation.globalI18n?.reloadResources();
33
31
  const { i18n, initPromise } = require_createClient_node({
34
32
  ...config,
35
33
  lng: initialLocale
@@ -45,6 +43,7 @@ const serverSideTranslations = async (initialLocale, namespacesRequired = void 0
45
43
  const getLocaleNamespaces = (path$2) => fs.default.existsSync(path$2) ? fs.default.readdirSync(path$2).map((file) => file.replace(`.${localeExtension}`, "")) : [];
46
44
  namespacesRequired = require_utils.unique(Object.keys(initialI18nStore).map((locale) => getLocaleNamespaces(path.default.resolve(process.cwd(), `${localePath}/${locale}`))).flat());
47
45
  }
46
+ if (reloadOnPrerender && process.env.NODE_ENV !== "production") await i18n.reloadResources(Object.keys(initialI18nStore), namespacesRequired);
48
47
  namespacesRequired.forEach((ns) => {
49
48
  for (const locale in initialI18nStore) initialI18nStore[locale][ns] = (i18n.services.resourceStore.data[locale] || {})[ns] || {};
50
49
  });
@@ -1 +1 @@
1
- {"version":3,"file":"serverSideTranslations.cjs","names":["createConfig","globalI18n","createClient","path","unique"],"sources":["../../src/pagesRouter/serverSideTranslations.ts"],"sourcesContent":["import fs from 'fs'\nimport path from 'path'\nimport { createRequire } from 'module'\n\nimport { createConfig } from './config/createConfig'\nimport createClient from './createClient/node'\n\nimport { globalI18n } from './appWithTranslation'\n\nimport { UserConfig, SSRConfig } from './types'\nimport { getFallbackForLng, unique } from './utils'\nimport { Module, Namespace } from 'i18next'\n\nlet DEFAULT_CONFIG_PATH = './next-i18next.config.js'\n\n/**\n * One line expression like `const { I18NEXT_DEFAULT_CONFIG_PATH: DEFAULT_CONFIG_PATH = './next-i18next.config.js' } = process.env;`\n * is breaking the build, so keep it like this.\n *\n * @see https://github.com/i18next/next-i18next/pull/2084#issuecomment-1420511358\n */\nif (process.env.I18NEXT_DEFAULT_CONFIG_PATH) {\n DEFAULT_CONFIG_PATH = process.env.I18NEXT_DEFAULT_CONFIG_PATH\n}\n\ntype ArrayElementOrSelf<T> = T extends ReadonlyArray<infer U> ? U[] : T[]\n\nexport const serverSideTranslations = async (\n initialLocale: string,\n namespacesRequired:\n | ArrayElementOrSelf<Namespace>\n | string\n | string[]\n | undefined = undefined,\n configOverride: UserConfig | null = null,\n extraLocales: string[] | false = false\n): Promise<SSRConfig> => {\n if (typeof initialLocale !== 'string') {\n throw new Error(\n 'Initial locale argument was not passed into serverSideTranslations'\n )\n }\n\n let userConfig = configOverride\n const configPath = path.resolve(DEFAULT_CONFIG_PATH)\n\n if (!userConfig && fs.existsSync(configPath)) {\n // Use createRequire to prevent Turbopack/webpack from tracing this dynamic require\n const nodeRequire = createRequire(__filename)\n userConfig = nodeRequire(configPath)\n }\n\n if (userConfig === null) {\n throw new Error(\n `next-i18next was unable to find a user config at ${configPath}`\n )\n }\n\n const config = createConfig({\n ...userConfig,\n lng: initialLocale,\n })\n\n const {\n localeExtension,\n localePath,\n fallbackLng,\n reloadOnPrerender,\n } = config\n\n if (reloadOnPrerender) {\n await globalI18n?.reloadResources()\n }\n\n const { i18n, initPromise } = createClient({\n ...config,\n lng: initialLocale,\n })\n\n await initPromise\n\n const hasCustomBackend = userConfig?.use?.filter(Boolean).some(\n (b: Module) => b.type === 'backend'\n )\n if (hasCustomBackend && namespacesRequired) {\n await i18n.loadNamespaces(Array.isArray(namespacesRequired) ? (namespacesRequired as string[]) : (namespacesRequired as string))\n }\n\n const initialI18nStore: Record<string, any> = {\n [initialLocale]: {},\n }\n\n getFallbackForLng(initialLocale, fallbackLng ?? false)\n .concat(extraLocales || [])\n .forEach((lng: string) => {\n initialI18nStore[lng] = {}\n })\n\n if (!Array.isArray(namespacesRequired)) {\n if (typeof localePath === 'function') {\n throw new Error(\n 'Must provide namespacesRequired to serverSideTranslations when using a function as localePath'\n )\n }\n\n const getLocaleNamespaces = (path: string) =>\n fs.existsSync(path)\n ? fs\n .readdirSync(path)\n .map(file => file.replace(`.${localeExtension}`, ''))\n : []\n\n const namespacesByLocale = Object.keys(initialI18nStore)\n .map(locale =>\n getLocaleNamespaces(\n path.resolve(process.cwd(), `${localePath}/${locale}`)\n )\n )\n .flat()\n\n namespacesRequired = unique(namespacesByLocale)\n }\n\n namespacesRequired.forEach(ns => {\n for (const locale in initialI18nStore) {\n initialI18nStore[locale][ns] =\n (i18n.services.resourceStore.data[locale] || {})[ns] || {}\n }\n })\n\n return {\n _nextI18Next: {\n initialI18nStore,\n initialLocale,\n ns: namespacesRequired,\n userConfig: config.serializeConfig ? userConfig : null,\n },\n }\n}\n"],"mappings":";;;;;;;;;;;;AAaA,IAAI,sBAAsB;;;;;;;AAQ1B,IAAI,QAAQ,IAAI,4BACd,uBAAsB,QAAQ,IAAI;AAKpC,MAAa,yBAAyB,OACpC,eACA,qBAIgB,KAAA,GAChB,iBAAoC,MACpC,eAAiC,UACV;AACvB,KAAI,OAAO,kBAAkB,SAC3B,OAAM,IAAI,MACR,qEACD;CAGH,IAAI,aAAa;CACjB,MAAM,aAAa,KAAA,QAAK,QAAQ,oBAAoB;AAEpD,KAAI,CAAC,cAAc,GAAA,QAAG,WAAW,WAAW,CAG1C,eAAA,GAAA,SAAA,eADkC,WAAW,CACpB,WAAW;AAGtC,KAAI,eAAe,KACjB,OAAM,IAAI,MACR,oDAAoD,aACrD;CAGH,MAAM,SAASA,4BAAAA,aAAa;EAC1B,GAAG;EACH,KAAK;EACN,CAAC;CAEF,MAAM,EACJ,iBACA,YACA,aACA,sBACE;AAEJ,KAAI,kBACF,OAAMC,2BAAAA,YAAY,iBAAiB;CAGrC,MAAM,EAAE,MAAM,gBAAgBC,0BAAa;EACzC,GAAG;EACH,KAAK;EACN,CAAC;AAEF,OAAM;AAKN,KAHyB,YAAY,KAAK,OAAO,QAAQ,CAAC,MACvD,MAAc,EAAE,SAAS,UAC3B,IACuB,mBACtB,OAAM,KAAK,eAAe,MAAM,QAAQ,mBAAmB,GAAI,qBAAmC,mBAA8B;CAGlI,MAAM,mBAAwC,GAC3C,gBAAgB,EAAE,EACpB;AAED,eAAA,kBAAkB,eAAe,eAAe,MAAM,CACnD,OAAO,gBAAgB,EAAE,CAAC,CAC1B,SAAS,QAAgB;AACxB,mBAAiB,OAAO,EAAE;GAC1B;AAEJ,KAAI,CAAC,MAAM,QAAQ,mBAAmB,EAAE;AACtC,MAAI,OAAO,eAAe,WACxB,OAAM,IAAI,MACR,gGACD;EAGH,MAAM,uBAAuB,WAC3B,GAAA,QAAG,WAAWC,OAAK,GACf,GAAA,QACC,YAAYA,OAAK,CACjB,KAAI,SAAQ,KAAK,QAAQ,IAAI,mBAAmB,GAAG,CAAC,GACrD,EAAE;AAUR,uBAAqBC,cAAAA,OARM,OAAO,KAAK,iBAAiB,CACrD,KAAI,WACH,oBACE,KAAA,QAAK,QAAQ,QAAQ,KAAK,EAAE,GAAG,WAAW,GAAG,SAAS,CACvD,CACF,CACA,MAAM,CAEsC;;AAGjD,oBAAmB,SAAQ,OAAM;AAC/B,OAAK,MAAM,UAAU,iBACnB,kBAAiB,QAAQ,OACtB,KAAK,SAAS,cAAc,KAAK,WAAW,EAAE,EAAE,OAAO,EAAE;GAE9D;AAEF,QAAO,EACL,cAAc;EACZ;EACA;EACA,IAAI;EACJ,YAAY,OAAO,kBAAkB,aAAa;EACnD,EACF"}
1
+ {"version":3,"file":"serverSideTranslations.cjs","names":["createConfig","createClient","path","unique"],"sources":["../../src/pagesRouter/serverSideTranslations.ts"],"sourcesContent":["import fs from 'fs'\nimport path from 'path'\nimport { createRequire } from 'module'\n\nimport { createConfig } from './config/createConfig'\nimport createClient from './createClient/node'\n\nimport { UserConfig, SSRConfig } from './types'\nimport { getFallbackForLng, unique } from './utils'\nimport { Module, Namespace } from 'i18next'\n\nlet DEFAULT_CONFIG_PATH = './next-i18next.config.js'\n\n/**\n * One line expression like `const { I18NEXT_DEFAULT_CONFIG_PATH: DEFAULT_CONFIG_PATH = './next-i18next.config.js' } = process.env;`\n * is breaking the build, so keep it like this.\n *\n * @see https://github.com/i18next/next-i18next/pull/2084#issuecomment-1420511358\n */\nif (process.env.I18NEXT_DEFAULT_CONFIG_PATH) {\n DEFAULT_CONFIG_PATH = process.env.I18NEXT_DEFAULT_CONFIG_PATH\n}\n\ntype ArrayElementOrSelf<T> = T extends ReadonlyArray<infer U> ? U[] : T[]\n\nexport const serverSideTranslations = async (\n initialLocale: string,\n namespacesRequired:\n | ArrayElementOrSelf<Namespace>\n | string\n | string[]\n | undefined = undefined,\n configOverride: UserConfig | null = null,\n extraLocales: string[] | false = false\n): Promise<SSRConfig> => {\n if (typeof initialLocale !== 'string') {\n throw new Error(\n 'Initial locale argument was not passed into serverSideTranslations'\n )\n }\n\n let userConfig = configOverride\n const configPath = path.resolve(DEFAULT_CONFIG_PATH)\n\n if (!userConfig && fs.existsSync(configPath)) {\n // Use createRequire to prevent Turbopack/webpack from tracing this dynamic require\n const nodeRequire = createRequire(__filename)\n userConfig = nodeRequire(configPath)\n }\n\n if (userConfig === null) {\n throw new Error(\n `next-i18next was unable to find a user config at ${configPath}`\n )\n }\n\n const config = createConfig({\n ...userConfig,\n lng: initialLocale,\n })\n\n const {\n localeExtension,\n localePath,\n fallbackLng,\n reloadOnPrerender,\n } = config\n\n const { i18n, initPromise } = createClient({\n ...config,\n lng: initialLocale,\n })\n\n await initPromise\n\n const hasCustomBackend = userConfig?.use?.filter(Boolean).some(\n (b: Module) => b.type === 'backend'\n )\n if (hasCustomBackend && namespacesRequired) {\n await i18n.loadNamespaces(Array.isArray(namespacesRequired) ? (namespacesRequired as string[]) : (namespacesRequired as string))\n }\n\n const initialI18nStore: Record<string, any> = {\n [initialLocale]: {},\n }\n\n getFallbackForLng(initialLocale, fallbackLng ?? false)\n .concat(extraLocales || [])\n .forEach((lng: string) => {\n initialI18nStore[lng] = {}\n })\n\n if (!Array.isArray(namespacesRequired)) {\n if (typeof localePath === 'function') {\n throw new Error(\n 'Must provide namespacesRequired to serverSideTranslations when using a function as localePath'\n )\n }\n\n const getLocaleNamespaces = (path: string) =>\n fs.existsSync(path)\n ? fs\n .readdirSync(path)\n .map(file => file.replace(`.${localeExtension}`, ''))\n : []\n\n const namespacesByLocale = Object.keys(initialI18nStore)\n .map(locale =>\n getLocaleNamespaces(\n path.resolve(process.cwd(), `${localePath}/${locale}`)\n )\n )\n .flat()\n\n namespacesRequired = unique(namespacesByLocale)\n }\n\n // Dev-only hot-reload: every backend (resources-to-backend, http, locize,\n // chained) refetches unconditionally with no dedup, so doing this in\n // production would hammer the source on every prerender call. Scope to\n // exactly the locales × namespaces this call will ship.\n if (reloadOnPrerender && process.env.NODE_ENV !== 'production') {\n await i18n.reloadResources(\n Object.keys(initialI18nStore),\n namespacesRequired as string[]\n )\n }\n\n namespacesRequired.forEach(ns => {\n for (const locale in initialI18nStore) {\n initialI18nStore[locale][ns] =\n (i18n.services.resourceStore.data[locale] || {})[ns] || {}\n }\n })\n\n return {\n _nextI18Next: {\n initialI18nStore,\n initialLocale,\n ns: namespacesRequired,\n userConfig: config.serializeConfig ? userConfig : null,\n },\n }\n}\n"],"mappings":";;;;;;;;;;;AAWA,IAAI,sBAAsB;;;;;;;AAQ1B,IAAI,QAAQ,IAAI,4BACd,uBAAsB,QAAQ,IAAI;AAKpC,MAAa,yBAAyB,OACpC,eACA,qBAIgB,KAAA,GAChB,iBAAoC,MACpC,eAAiC,UACV;AACvB,KAAI,OAAO,kBAAkB,SAC3B,OAAM,IAAI,MACR,qEACD;CAGH,IAAI,aAAa;CACjB,MAAM,aAAa,KAAA,QAAK,QAAQ,oBAAoB;AAEpD,KAAI,CAAC,cAAc,GAAA,QAAG,WAAW,WAAW,CAG1C,eAAA,GAAA,SAAA,eADkC,WAAW,CACpB,WAAW;AAGtC,KAAI,eAAe,KACjB,OAAM,IAAI,MACR,oDAAoD,aACrD;CAGH,MAAM,SAASA,4BAAAA,aAAa;EAC1B,GAAG;EACH,KAAK;EACN,CAAC;CAEF,MAAM,EACJ,iBACA,YACA,aACA,sBACE;CAEJ,MAAM,EAAE,MAAM,gBAAgBC,0BAAa;EACzC,GAAG;EACH,KAAK;EACN,CAAC;AAEF,OAAM;AAKN,KAHyB,YAAY,KAAK,OAAO,QAAQ,CAAC,MACvD,MAAc,EAAE,SAAS,UAC3B,IACuB,mBACtB,OAAM,KAAK,eAAe,MAAM,QAAQ,mBAAmB,GAAI,qBAAmC,mBAA8B;CAGlI,MAAM,mBAAwC,GAC3C,gBAAgB,EAAE,EACpB;AAED,eAAA,kBAAkB,eAAe,eAAe,MAAM,CACnD,OAAO,gBAAgB,EAAE,CAAC,CAC1B,SAAS,QAAgB;AACxB,mBAAiB,OAAO,EAAE;GAC1B;AAEJ,KAAI,CAAC,MAAM,QAAQ,mBAAmB,EAAE;AACtC,MAAI,OAAO,eAAe,WACxB,OAAM,IAAI,MACR,gGACD;EAGH,MAAM,uBAAuB,WAC3B,GAAA,QAAG,WAAWC,OAAK,GACf,GAAA,QACC,YAAYA,OAAK,CACjB,KAAI,SAAQ,KAAK,QAAQ,IAAI,mBAAmB,GAAG,CAAC,GACrD,EAAE;AAUR,uBAAqBC,cAAAA,OARM,OAAO,KAAK,iBAAiB,CACrD,KAAI,WACH,oBACE,KAAA,QAAK,QAAQ,QAAQ,KAAK,EAAE,GAAG,WAAW,GAAG,SAAS,CACvD,CACF,CACA,MAAM,CAEsC;;AAOjD,KAAI,qBAAqB,QAAQ,IAAI,aAAa,aAChD,OAAM,KAAK,gBACT,OAAO,KAAK,iBAAiB,EAC7B,mBACD;AAGH,oBAAmB,SAAQ,OAAM;AAC/B,OAAK,MAAM,UAAU,iBACnB,kBAAiB,QAAQ,OACtB,KAAK,SAAS,cAAc,KAAK,WAAW,EAAE,EAAE,OAAO,EAAE;GAE9D;AAEF,QAAO,EACL,cAAc;EACZ;EACA;EACA,IAAI;EACJ,YAAY,OAAO,kBAAkB,aAAa;EACnD,EACF"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "next-i18next",
3
- "version": "16.0.5",
3
+ "version": "16.0.6",
4
4
  "repository": "git@github.com:i18next/next-i18next.git",
5
5
  "author": "i18next",
6
6
  "funding": [
@@ -171,7 +171,7 @@
171
171
  "gh-release": "7.0.2",
172
172
  "globals": "17.4.0",
173
173
  "husky": "^9.0.0",
174
- "i18next": "^26.0.1",
174
+ "i18next": "^26.0.10",
175
175
  "jest": "^30.0.0",
176
176
  "jest-environment-jsdom": "^30.0.0",
177
177
  "neostandard": "^0.13.0",
@@ -180,7 +180,7 @@
180
180
  "prettier": "3.8.1",
181
181
  "react": "^19.2.4",
182
182
  "react-dom": "^19.2.4",
183
- "react-i18next": "^17.0.1",
183
+ "react-i18next": "^17.0.7",
184
184
  "rimraf": "^6.1.3",
185
185
  "start-server-and-test": "^2.1.5",
186
186
  "tsdown": "0.21.4",