react-intlayer 9.3.2 → 9.4.0-canary.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (31) hide show
  1. package/README.md +1 -1
  2. package/dist/cjs/analytics/useAnalytics.cjs +4 -4
  3. package/dist/cjs/analytics/useAnalytics.cjs.map +1 -1
  4. package/dist/cjs/client/useDictionaryDynamic.cjs +2 -0
  5. package/dist/cjs/client/useDictionaryDynamic.cjs.map +1 -1
  6. package/dist/cjs/client/useLoadDynamic.cjs +32 -5
  7. package/dist/cjs/client/useLoadDynamic.cjs.map +1 -1
  8. package/dist/cjs/server/IntlayerServerProvider.cjs +28 -0
  9. package/dist/cjs/server/IntlayerServerProvider.cjs.map +1 -1
  10. package/dist/cjs/server/index.cjs +5 -0
  11. package/dist/cjs/server/serverContext.cjs.map +1 -1
  12. package/dist/esm/analytics/useAnalytics.mjs +4 -4
  13. package/dist/esm/analytics/useAnalytics.mjs.map +1 -1
  14. package/dist/esm/client/useDictionaryDynamic.mjs +3 -1
  15. package/dist/esm/client/useDictionaryDynamic.mjs.map +1 -1
  16. package/dist/esm/client/useLoadDynamic.mjs +32 -6
  17. package/dist/esm/client/useLoadDynamic.mjs.map +1 -1
  18. package/dist/esm/server/IntlayerServerProvider.mjs +27 -1
  19. package/dist/esm/server/IntlayerServerProvider.mjs.map +1 -1
  20. package/dist/esm/server/index.mjs +3 -2
  21. package/dist/esm/server/serverContext.mjs.map +1 -1
  22. package/dist/types/analytics/useAnalytics.d.ts +4 -4
  23. package/dist/types/client/useDictionaryDynamic.d.ts.map +1 -1
  24. package/dist/types/client/useLoadDynamic.d.ts +21 -1
  25. package/dist/types/client/useLoadDynamic.d.ts.map +1 -1
  26. package/dist/types/server/IntlayerServerProvider.d.ts +26 -29
  27. package/dist/types/server/IntlayerServerProvider.d.ts.map +1 -1
  28. package/dist/types/server/index.d.ts +3 -2
  29. package/dist/types/server/serverContext.d.ts +1 -1
  30. package/dist/types/server/serverContext.d.ts.map +1 -1
  31. package/package.json +9 -9
package/README.md CHANGED
@@ -327,4 +327,4 @@ Contribute on [GitHub](https://github.com/aymericzip/intlayer), [GitLab](https:/
327
327
 
328
328
  If you like Intlayer, give us a ⭐ on GitHub. It helps others discover the project! [See why GitHub Stars matter](https://github.com/aymericzip/intlayer/blob/main/CONTRIBUTING.md#why-github-stars-matter-).
329
329
 
330
- [![Star History Chart](https://api.star-history.com/svg?repos=aymericzip/intlayer&type=Date)](https://star-history.com/#aymericzip/intlayer&Date)
330
+ [![Star History Chart](https://star-history.dera.page/svg?repos=aymericzip/intlayer&type=Date)](https://star-history.dera.page/#aymericzip/intlayer&Date)
@@ -12,10 +12,10 @@ let _intlayer_analytics_isEnabled = require("@intlayer/analytics/isEnabled");
12
12
  * and keeps it aware of the current locale.
13
13
  *
14
14
  * Mirrors {@link useEditor}: the module is loaded via a dynamic `import()` so it
15
- * ships as its own async chunk, off the critical rendering path. Apps that
16
- * don't opt in (`analytics.enabled !== true`) pay nothing the whole body is
17
- * guarded by `INTLAYER_ANALYTICS_ENABLED` and dead-code-eliminated at build
18
- * time.
15
+ * ships as its own async chunk, off the critical rendering path. Apps that opt
16
+ * out (`analytics.enabled !== true`), or that never install
17
+ * `@intlayer/analytics`, pay nothing the whole body is guarded by
18
+ * `INTLAYER_ANALYTICS_ENABLED` and dead-code-eliminated at build time.
19
19
  */
20
20
  const useAnalytics = () => {
21
21
  const { locale } = (0, react.useContext)(require_client_IntlayerProvider.IntlayerClientContext) ?? {};
@@ -1 +1 @@
1
- {"version":3,"file":"useAnalytics.cjs","names":["useContext","IntlayerClientContext","useRef","isEnabled"],"sources":["../../../src/analytics/useAnalytics.tsx"],"sourcesContent":["'use client';\n\nimport type { AnalyticsClient } from '@intlayer/analytics';\nimport { isEnabled } from '@intlayer/analytics/isEnabled';\nimport { useContext, useEffect, useRef } from 'react';\nimport { IntlayerClientContext } from '../client/IntlayerProvider';\nimport { setExposureSink } from './exposureSink';\n\n/**\n * Initializes the Intlayer analytics client singleton when analytics is enabled\n * and keeps it aware of the current locale.\n *\n * Mirrors {@link useEditor}: the module is loaded via a dynamic `import()` so it\n * ships as its own async chunk, off the critical rendering path. Apps that\n * don't opt in (`analytics.enabled !== true`) pay nothing — the whole body is\n * guarded by `INTLAYER_ANALYTICS_ENABLED` and dead-code-eliminated at build\n * time.\n */\nexport const useAnalytics = () => {\n const { locale } = useContext(IntlayerClientContext) ?? {};\n const clientRef = useRef<AnalyticsClient | null>(null);\n\n useEffect(() => {\n if (process.env.INTLAYER_ANALYTICS_ENABLED === 'false' || !isEnabled) {\n return;\n }\n\n let cancelled = false;\n // Tracks whether initAnalyticsClient actually ran, so cleanup never calls\n // stopAnalyticsClient for an init that was cancelled — that would decrement\n // the shared reference count once too many and could stop a client another\n // provider still uses.\n let initialized = false;\n\n import('@intlayer/analytics')\n .then(({ initAnalyticsClient, buildContentExposure }) => {\n if (cancelled) return;\n\n const client = initAnalyticsClient();\n initialized = true;\n clientRef.current = client;\n\n if (locale) client.setLocale(locale);\n client.trackPageView({ reason: 'initial' });\n\n // Route node-level exposures (from the interpreter plugins) into the\n // client. Serialization happens here, off the hot render path.\n setExposureSink((input) =>\n client.trackContentExposure(buildContentExposure(input))\n );\n })\n .catch(() => {\n /* chunk failed to load — analytics stays a no-op */\n });\n\n return () => {\n cancelled = true;\n clientRef.current = null;\n setExposureSink(null);\n import('@intlayer/analytics')\n .then(({ stopAnalyticsClient }) => {\n if (initialized) stopAnalyticsClient();\n })\n .catch(() => {});\n };\n // Run once on mount; locale updates are handled by the effect below.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, []);\n\n useEffect(() => {\n if (!locale || !clientRef.current) return;\n\n clientRef.current.setLocale(locale);\n clientRef.current.trackPageView({ reason: 'locale_change' });\n }, [locale]);\n};\n"],"mappings":";;;;;;;;;;;;;;;;;;;AAkBA,MAAa,qBAAqB;CAChC,MAAM,EAAE,eAAWA,kBAAWC,qDAAqB,KAAK,CAAC;CACzD,MAAM,gBAAYC,cAA+B,IAAI;CAErD,2BAAgB;EACd,IAAI,QAAQ,IAAI,+BAA+B,WAAW,CAACC,yCACzD;EAGF,IAAI,YAAY;EAKhB,IAAI,cAAc;EAElB,OAAO,sBAAsB,CAC1B,MAAM,EAAE,qBAAqB,2BAA2B;GACvD,IAAI,WAAW;GAEf,MAAM,SAAS,oBAAoB;GACnC,cAAc;GACd,UAAU,UAAU;GAEpB,IAAI,QAAQ,OAAO,UAAU,MAAM;GACnC,OAAO,cAAc,EAAE,QAAQ,UAAU,CAAC;GAI1C,gDAAiB,UACf,OAAO,qBAAqB,qBAAqB,KAAK,CAAC,CACzD;EACF,CAAC,CAAC,CACD,YAAY,CAEb,CAAC;EAEH,aAAa;GACX,YAAY;GACZ,UAAU,UAAU;GACpB,+CAAgB,IAAI;GACpB,OAAO,sBAAsB,CAC1B,MAAM,EAAE,0BAA0B;IACjC,IAAI,aAAa,oBAAoB;GACvC,CAAC,CAAC,CACD,YAAY,CAAC,CAAC;EACnB;CAGF,GAAG,CAAC,CAAC;CAEL,2BAAgB;EACd,IAAI,CAAC,UAAU,CAAC,UAAU,SAAS;EAEnC,UAAU,QAAQ,UAAU,MAAM;EAClC,UAAU,QAAQ,cAAc,EAAE,QAAQ,gBAAgB,CAAC;CAC7D,GAAG,CAAC,MAAM,CAAC;AACb"}
1
+ {"version":3,"file":"useAnalytics.cjs","names":["useContext","IntlayerClientContext","useRef","isEnabled"],"sources":["../../../src/analytics/useAnalytics.tsx"],"sourcesContent":["'use client';\n\nimport type { AnalyticsClient } from '@intlayer/analytics';\nimport { isEnabled } from '@intlayer/analytics/isEnabled';\nimport { useContext, useEffect, useRef } from 'react';\nimport { IntlayerClientContext } from '../client/IntlayerProvider';\nimport { setExposureSink } from './exposureSink';\n\n/**\n * Initializes the Intlayer analytics client singleton when analytics is enabled\n * and keeps it aware of the current locale.\n *\n * Mirrors {@link useEditor}: the module is loaded via a dynamic `import()` so it\n * ships as its own async chunk, off the critical rendering path. Apps that opt\n * out (`analytics.enabled !== true`), or that never install\n * `@intlayer/analytics`, pay nothing — the whole body is guarded by\n * `INTLAYER_ANALYTICS_ENABLED` and dead-code-eliminated at build time.\n */\nexport const useAnalytics = () => {\n const { locale } = useContext(IntlayerClientContext) ?? {};\n const clientRef = useRef<AnalyticsClient | null>(null);\n\n useEffect(() => {\n if (process.env.INTLAYER_ANALYTICS_ENABLED === 'false' || !isEnabled) {\n return;\n }\n\n let cancelled = false;\n // Tracks whether initAnalyticsClient actually ran, so cleanup never calls\n // stopAnalyticsClient for an init that was cancelled — that would decrement\n // the shared reference count once too many and could stop a client another\n // provider still uses.\n let initialized = false;\n\n import('@intlayer/analytics')\n .then(({ initAnalyticsClient, buildContentExposure }) => {\n if (cancelled) return;\n\n const client = initAnalyticsClient();\n initialized = true;\n clientRef.current = client;\n\n if (locale) client.setLocale(locale);\n client.trackPageView({ reason: 'initial' });\n\n // Route node-level exposures (from the interpreter plugins) into the\n // client. Serialization happens here, off the hot render path.\n setExposureSink((input) =>\n client.trackContentExposure(buildContentExposure(input))\n );\n })\n .catch(() => {\n /* chunk failed to load — analytics stays a no-op */\n });\n\n return () => {\n cancelled = true;\n clientRef.current = null;\n setExposureSink(null);\n import('@intlayer/analytics')\n .then(({ stopAnalyticsClient }) => {\n if (initialized) stopAnalyticsClient();\n })\n .catch(() => {});\n };\n // Run once on mount; locale updates are handled by the effect below.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, []);\n\n useEffect(() => {\n if (!locale || !clientRef.current) return;\n\n clientRef.current.setLocale(locale);\n clientRef.current.trackPageView({ reason: 'locale_change' });\n }, [locale]);\n};\n"],"mappings":";;;;;;;;;;;;;;;;;;;AAkBA,MAAa,qBAAqB;CAChC,MAAM,EAAE,eAAWA,kBAAWC,qDAAqB,KAAK,CAAC;CACzD,MAAM,gBAAYC,cAA+B,IAAI;CAErD,2BAAgB;EACd,IAAI,QAAQ,IAAI,+BAA+B,WAAW,CAACC,yCACzD;EAGF,IAAI,YAAY;EAKhB,IAAI,cAAc;EAElB,OAAO,sBAAsB,CAC1B,MAAM,EAAE,qBAAqB,2BAA2B;GACvD,IAAI,WAAW;GAEf,MAAM,SAAS,oBAAoB;GACnC,cAAc;GACd,UAAU,UAAU;GAEpB,IAAI,QAAQ,OAAO,UAAU,MAAM;GACnC,OAAO,cAAc,EAAE,QAAQ,UAAU,CAAC;GAI1C,gDAAiB,UACf,OAAO,qBAAqB,qBAAqB,KAAK,CAAC,CACzD;EACF,CAAC,CAAC,CACD,YAAY,CAEb,CAAC;EAEH,aAAa;GACX,YAAY;GACZ,UAAU,UAAU;GACpB,+CAAgB,IAAI;GACpB,OAAO,sBAAsB,CAC1B,MAAM,EAAE,0BAA0B;IACjC,IAAI,aAAa,oBAAoB;GACvC,CAAC,CAAC,CACD,YAAY,CAAC,CAAC;EACnB;CAGF,GAAG,CAAC,CAAC;CAEL,2BAAgB;EACd,IAAI,CAAC,UAAU,CAAC,UAAU,SAAS;EAEnC,UAAU,QAAQ,UAAU,MAAM;EAClC,UAAU,QAAQ,cAAc,EAAE,QAAQ,gBAAgB,CAAC;CAC7D,GAAG,CAAC,MAAM,CAAC;AACb"}
@@ -40,6 +40,8 @@ const useDictionaryDynamic = (dictionaryPromise, key, localeOrSelector) => {
40
40
  loadChunk: (cacheKey, promise) => require_client_useLoadDynamic.useLoadDynamic(cacheKey, promise),
41
41
  transform: (dictionary) => require_getDictionary.getDictionary(dictionary, localeTarget)
42
42
  });
43
+ const preloadedDictionary = (0, _intlayer_core_dictionaryManipulator.getPreloadedDictionary)(dictionaryPromise, localeTarget);
44
+ if (preloadedDictionary) return require_getDictionary.getDictionary(preloadedDictionary, localeTarget);
43
45
  const plainLoaders = dictionaryPromise;
44
46
  const dictionary = require_client_useLoadDynamic.useLoadDynamic(`${String(key)}.${localeTarget}`, plainLoaders[localeTarget]?.());
45
47
  return require_getDictionary.getDictionary(dictionary, localeTarget);
@@ -1 +1 @@
1
- {"version":3,"file":"useDictionaryDynamic.cjs","names":["useContext","IntlayerClientContext","parseDictionarySelector","resolveDictionaryArgument","internationalization","isQualifiedDynamicLoaderMap","resolveQualifiedDynamicContent","loadDynamicChunk","getDictionary"],"sources":["../../../src/client/useDictionaryDynamic.ts"],"sourcesContent":["'use client';\n\nimport { internationalization } from '@intlayer/config/built';\nimport {\n isQualifiedDynamicLoaderMap,\n parseDictionarySelector,\n type QualifiedDynamicLoaderMap,\n resolveDictionaryArgument,\n resolveQualifiedDynamicContent,\n} from '@intlayer/core/dictionaryManipulator';\nimport type { Dictionary } from '@intlayer/types/dictionary';\nimport type {\n DeclaredLocales,\n DictionaryKeys,\n DictionarySelectorForKey,\n LocalesValues,\n StrictModeLocaleMap,\n} from '@intlayer/types/module_augmentation';\nimport { useContext } from 'react';\nimport { getDictionary } from '../getDictionary';\nimport { IntlayerClientContext } from './IntlayerProvider';\n// `useLoadDynamic` is a suspender cache, not a React hook — aliased to a\n// non-hook name so it can be invoked in loops / conditionally (e.g. when a\n// collection loads several chunks at once).\nimport { useLoadDynamic as loadDynamicChunk } from './useLoadDynamic';\n\n/**\n * Client-side hook that lazily loads a dictionary and returns its content.\n *\n * The dictionary entry is either a plain dynamic loader map\n * (`locale → loader`) or a qualified one (`locale → qualifierId → loader`,\n * tagged with the qualifier dimension). For qualified maps, only the chunk(s)\n * the selector targets are loaded; the resolution mirrors static mode.\n *\n * If the locale is not provided (directly or through the selector), the client\n * context locale is used.\n */\nexport const useDictionaryDynamic = <\n const T extends Dictionary,\n const K extends DictionaryKeys,\n const A extends LocalesValues | DictionarySelectorForKey<K> = DeclaredLocales,\n>(\n dictionaryPromise:\n | StrictModeLocaleMap<() => Promise<T>>\n | QualifiedDynamicLoaderMap,\n key: K,\n localeOrSelector?: A\n) => {\n const { locale: currentLocale, variant: contextVariant } =\n useContext(IntlayerClientContext) ?? {};\n\n const { locale: selectorLocale, selector } =\n process.env.INTLAYER_DICTIONARY_SELECTOR !== 'false'\n ? parseDictionarySelector<LocalesValues>(\n // Layers the provider's ambient variant under the call-site argument\n // before the chunk walk, so only the targeted chunk is loaded.\n resolveDictionaryArgument({\n localeOrSelector,\n contextLocale: currentLocale,\n contextVariant,\n dictionaryKey: String(key),\n })\n )\n : {\n locale: localeOrSelector as LocalesValues | undefined,\n selector: undefined,\n };\n\n const localeTarget =\n selectorLocale ?? currentLocale ?? internationalization.defaultLocale;\n\n if (\n process.env.INTLAYER_DICTIONARY_SELECTOR !== 'false' &&\n isQualifiedDynamicLoaderMap(dictionaryPromise)\n ) {\n return resolveQualifiedDynamicContent({\n loaderMap: dictionaryPromise,\n key: String(key),\n locale: localeTarget,\n selector,\n loadChunk: (cacheKey, promise) => loadDynamicChunk(cacheKey, promise),\n transform: (dictionary) => getDictionary(dictionary, localeTarget),\n });\n }\n\n const plainLoaders = dictionaryPromise as StrictModeLocaleMap<\n () => Promise<T>\n >;\n\n const dictionary = loadDynamicChunk<T>(\n `${String(key)}.${localeTarget}`,\n plainLoaders[localeTarget as keyof typeof plainLoaders]?.() as Promise<T>\n );\n\n return getDictionary(dictionary, localeTarget);\n};\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;AAqCA,MAAa,wBAKX,mBAGA,KACA,qBACG;CACH,MAAM,EAAE,QAAQ,eAAe,SAAS,uBACtCA,kBAAWC,qDAAqB,KAAK,CAAC;CAExC,MAAM,EAAE,QAAQ,gBAAgB,aAC9B,QAAQ,IAAI,iCAAiC,cACzCC,kEAGEC,gEAA0B;EACxB;EACA,eAAe;EACf;EACA,eAAe,OAAO,GAAG;CAC3B,CAAC,CACH,IACA;EACE,QAAQ;EACR,UAAU;CACZ;CAEN,MAAM,eACJ,kBAAkB,iBAAiBC,4CAAqB;CAE1D,IACE,QAAQ,IAAI,iCAAiC,eAC7CC,kEAA4B,iBAAiB,GAE7C,WAAOC,qEAA+B;EACpC,WAAW;EACX,KAAK,OAAO,GAAG;EACf,QAAQ;EACR;EACA,YAAY,UAAU,YAAYC,6CAAiB,UAAU,OAAO;EACpE,YAAY,eAAeC,oCAAc,YAAY,YAAY;CACnE,CAAC;CAGH,MAAM,eAAe;CAIrB,MAAM,aAAaD,6CACjB,GAAG,OAAO,GAAG,EAAE,GAAG,gBAClB,aAAa,aAA0C,GAAG,CAC5D;CAEA,OAAOC,oCAAc,YAAY,YAAY;AAC/C"}
1
+ {"version":3,"file":"useDictionaryDynamic.cjs","names":["useContext","IntlayerClientContext","parseDictionarySelector","resolveDictionaryArgument","internationalization","isQualifiedDynamicLoaderMap","resolveQualifiedDynamicContent","loadDynamicChunk","getDictionary","getPreloadedDictionary"],"sources":["../../../src/client/useDictionaryDynamic.ts"],"sourcesContent":["'use client';\n\nimport { internationalization } from '@intlayer/config/built';\nimport {\n getPreloadedDictionary,\n isQualifiedDynamicLoaderMap,\n parseDictionarySelector,\n type QualifiedDynamicLoaderMap,\n resolveDictionaryArgument,\n resolveQualifiedDynamicContent,\n} from '@intlayer/core/dictionaryManipulator';\nimport type { Dictionary } from '@intlayer/types/dictionary';\nimport type {\n DeclaredLocales,\n DictionaryKeys,\n DictionarySelectorForKey,\n LocalesValues,\n StrictModeLocaleMap,\n} from '@intlayer/types/module_augmentation';\nimport { useContext } from 'react';\nimport { getDictionary } from '../getDictionary';\nimport { IntlayerClientContext } from './IntlayerProvider';\n// `useLoadDynamic` is a suspender cache, not a React hook — aliased to a\n// non-hook name so it can be invoked in loops / conditionally (e.g. when a\n// collection loads several chunks at once).\nimport { useLoadDynamic as loadDynamicChunk } from './useLoadDynamic';\n\n/**\n * Client-side hook that lazily loads a dictionary and returns its content.\n *\n * The dictionary entry is either a plain dynamic loader map\n * (`locale → loader`) or a qualified one (`locale → qualifierId → loader`,\n * tagged with the qualifier dimension). For qualified maps, only the chunk(s)\n * the selector targets are loaded; the resolution mirrors static mode.\n *\n * If the locale is not provided (directly or through the selector), the client\n * context locale is used.\n */\nexport const useDictionaryDynamic = <\n const T extends Dictionary,\n const K extends DictionaryKeys,\n const A extends LocalesValues | DictionarySelectorForKey<K> = DeclaredLocales,\n>(\n dictionaryPromise:\n | StrictModeLocaleMap<() => Promise<T>>\n | QualifiedDynamicLoaderMap,\n key: K,\n localeOrSelector?: A\n) => {\n const { locale: currentLocale, variant: contextVariant } =\n useContext(IntlayerClientContext) ?? {};\n\n const { locale: selectorLocale, selector } =\n process.env.INTLAYER_DICTIONARY_SELECTOR !== 'false'\n ? parseDictionarySelector<LocalesValues>(\n // Layers the provider's ambient variant under the call-site argument\n // before the chunk walk, so only the targeted chunk is loaded.\n resolveDictionaryArgument({\n localeOrSelector,\n contextLocale: currentLocale,\n contextVariant,\n dictionaryKey: String(key),\n })\n )\n : {\n locale: localeOrSelector as LocalesValues | undefined,\n selector: undefined,\n };\n\n const localeTarget =\n selectorLocale ?? currentLocale ?? internationalization.defaultLocale;\n\n if (\n process.env.INTLAYER_DICTIONARY_SELECTOR !== 'false' &&\n isQualifiedDynamicLoaderMap(dictionaryPromise)\n ) {\n return resolveQualifiedDynamicContent({\n loaderMap: dictionaryPromise,\n key: String(key),\n locale: localeTarget,\n selector,\n loadChunk: (cacheKey, promise) => loadDynamicChunk(cacheKey, promise),\n transform: (dictionary) => getDictionary(dictionary, localeTarget),\n });\n }\n\n // A build-tool plugin may have started this locale's chunk while the entry\n // point itself was evaluating, in which case the content is already here and\n // reading it must not go through the suspender — see `getPreloadedDictionary`.\n const preloadedDictionary = getPreloadedDictionary(\n dictionaryPromise,\n localeTarget\n );\n if (preloadedDictionary) {\n return getDictionary(preloadedDictionary as T, localeTarget);\n }\n\n const plainLoaders = dictionaryPromise as StrictModeLocaleMap<\n () => Promise<T>\n >;\n\n const dictionary = loadDynamicChunk<T>(\n `${String(key)}.${localeTarget}`,\n plainLoaders[localeTarget as keyof typeof plainLoaders]?.() as Promise<T>\n );\n\n return getDictionary(dictionary, localeTarget);\n};\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;AAsCA,MAAa,wBAKX,mBAGA,KACA,qBACG;CACH,MAAM,EAAE,QAAQ,eAAe,SAAS,uBACtCA,kBAAWC,qDAAqB,KAAK,CAAC;CAExC,MAAM,EAAE,QAAQ,gBAAgB,aAC9B,QAAQ,IAAI,iCAAiC,cACzCC,kEAGEC,gEAA0B;EACxB;EACA,eAAe;EACf;EACA,eAAe,OAAO,GAAG;CAC3B,CAAC,CACH,IACA;EACE,QAAQ;EACR,UAAU;CACZ;CAEN,MAAM,eACJ,kBAAkB,iBAAiBC,4CAAqB;CAE1D,IACE,QAAQ,IAAI,iCAAiC,eAC7CC,kEAA4B,iBAAiB,GAE7C,WAAOC,qEAA+B;EACpC,WAAW;EACX,KAAK,OAAO,GAAG;EACf,QAAQ;EACR;EACA,YAAY,UAAU,YAAYC,6CAAiB,UAAU,OAAO;EACpE,YAAY,eAAeC,oCAAc,YAAY,YAAY;CACnE,CAAC;CAMH,MAAM,0BAAsBC,6DAC1B,mBACA,YACF;CACA,IAAI,qBACF,OAAOD,oCAAc,qBAA0B,YAAY;CAG7D,MAAM,eAAe;CAIrB,MAAM,aAAaD,6CACjB,GAAG,OAAO,GAAG,EAAE,GAAG,gBAClB,aAAa,aAA0C,GAAG,CAC5D;CAEA,OAAOC,oCAAc,YAAY,YAAY;AAC/C"}
@@ -10,18 +10,45 @@ const createSuspender = (promise) => {
10
10
  status = "error";
11
11
  result = e;
12
12
  });
13
- return { read() {
14
- if (status === "pending") throw suspender;
15
- if (status === "error") throw result;
16
- return result;
17
- } };
13
+ return {
14
+ settled: suspender,
15
+ read() {
16
+ if (status === "pending") throw suspender;
17
+ if (status === "error") throw result;
18
+ return result;
19
+ }
20
+ };
18
21
  };
19
22
  const cache = /* @__PURE__ */ new Map();
20
23
  const useLoadDynamic = (key, promise) => {
21
24
  if (!cache.has(key)) cache.set(key, createSuspender(promise));
22
25
  return cache.get(key).read();
23
26
  };
27
+ /**
28
+ * Fills the same cache {@link useLoadDynamic} reads, ahead of render.
29
+ *
30
+ * A component that reads a dictionary during render suspends whenever the entry
31
+ * is still `pending`, and the nearest boundary shows its fallback. Awaiting this
32
+ * before the render — in a router loader, or during app startup — makes that
33
+ * read synchronous, so no boundary ever falls back.
34
+ *
35
+ * Handing over an already-resolved promise is not enough on its own:
36
+ * {@link createSuspender} only leaves `pending` inside a `.then` callback, so
37
+ * the first read would still suspend for one microtask. Awaiting the returned
38
+ * promise resolves that race, because the callback registered by
39
+ * `createSuspender` runs before this one.
40
+ *
41
+ * @param key - Cache key, identical to the one the later read uses.
42
+ * @param loader - Invoked only when the key is not cached yet, so preloading a
43
+ * dictionary twice never issues a second request.
44
+ * @returns A promise that settles — never rejects — once the entry is readable.
45
+ */
46
+ const preloadDynamic = (key, loader) => {
47
+ if (!cache.has(key)) cache.set(key, createSuspender(loader()));
48
+ return cache.get(key).settled;
49
+ };
24
50
 
25
51
  //#endregion
52
+ exports.preloadDynamic = preloadDynamic;
26
53
  exports.useLoadDynamic = useLoadDynamic;
27
54
  //# sourceMappingURL=useLoadDynamic.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"useLoadDynamic.cjs","names":[],"sources":["../../../src/client/useLoadDynamic.ts"],"sourcesContent":["type Status = 'pending' | 'success' | 'error';\n\nconst createSuspender = <T>(promise: Promise<T>) => {\n let status: Status = 'pending';\n let result: T;\n const suspender = promise.then(\n (r) => {\n status = 'success';\n result = r;\n },\n (e) => {\n status = 'error';\n result = e as any;\n }\n );\n\n return {\n read() {\n if (status === 'pending') throw suspender;\n if (status === 'error') throw result;\n return result!;\n },\n };\n};\n\nconst cache = new Map<string, ReturnType<typeof createSuspender>>();\n\nexport const useLoadDynamic = <T>(key: string, promise: Promise<T>): T => {\n if (!cache.has(key)) {\n cache.set(key, createSuspender(promise));\n }\n\n return (cache.get(key)! as ReturnType<typeof createSuspender>).read() as T;\n};\n"],"mappings":";;AAEA,MAAM,mBAAsB,YAAwB;CAClD,IAAI,SAAiB;CACrB,IAAI;CACJ,MAAM,YAAY,QAAQ,MACvB,MAAM;EACL,SAAS;EACT,SAAS;CACX,IACC,MAAM;EACL,SAAS;EACT,SAAS;CACX,CACF;CAEA,OAAO,EACL,OAAO;EACL,IAAI,WAAW,WAAW,MAAM;EAChC,IAAI,WAAW,SAAS,MAAM;EAC9B,OAAO;CACT,EACF;AACF;AAEA,MAAM,wBAAQ,IAAI,IAAgD;AAElE,MAAa,kBAAqB,KAAa,YAA2B;CACxE,IAAI,CAAC,MAAM,IAAI,GAAG,GAChB,MAAM,IAAI,KAAK,gBAAgB,OAAO,CAAC;CAGzC,OAAQ,MAAM,IAAI,GAAG,CAAC,CAAyC,KAAK;AACtE"}
1
+ {"version":3,"file":"useLoadDynamic.cjs","names":[],"sources":["../../../src/client/useLoadDynamic.ts"],"sourcesContent":["type Status = 'pending' | 'success' | 'error';\n\ntype Suspender<T> = {\n /**\n * Settles once the entry has left `pending`, never rejecting. Awaiting it\n * guarantees a subsequent {@link Suspender.read} returns without suspending.\n */\n settled: Promise<void>;\n read: () => T;\n};\n\nconst createSuspender = <T>(promise: Promise<T>): Suspender<T> => {\n let status: Status = 'pending';\n let result: T;\n const suspender = promise.then(\n (r) => {\n status = 'success';\n result = r;\n },\n (e) => {\n status = 'error';\n result = e as any;\n }\n );\n\n return {\n settled: suspender,\n read() {\n if (status === 'pending') throw suspender;\n if (status === 'error') throw result;\n return result!;\n },\n };\n};\n\nconst cache = new Map<string, Suspender<unknown>>();\n\nexport const useLoadDynamic = <T>(key: string, promise: Promise<T>): T => {\n if (!cache.has(key)) {\n cache.set(key, createSuspender(promise));\n }\n\n return (cache.get(key)! as Suspender<T>).read() as T;\n};\n\n/**\n * Fills the same cache {@link useLoadDynamic} reads, ahead of render.\n *\n * A component that reads a dictionary during render suspends whenever the entry\n * is still `pending`, and the nearest boundary shows its fallback. Awaiting this\n * before the render — in a router loader, or during app startup — makes that\n * read synchronous, so no boundary ever falls back.\n *\n * Handing over an already-resolved promise is not enough on its own:\n * {@link createSuspender} only leaves `pending` inside a `.then` callback, so\n * the first read would still suspend for one microtask. Awaiting the returned\n * promise resolves that race, because the callback registered by\n * `createSuspender` runs before this one.\n *\n * @param key - Cache key, identical to the one the later read uses.\n * @param loader - Invoked only when the key is not cached yet, so preloading a\n * dictionary twice never issues a second request.\n * @returns A promise that settles — never rejects — once the entry is readable.\n */\nexport const preloadDynamic = <T>(\n key: string,\n loader: () => Promise<T>\n): Promise<void> => {\n if (!cache.has(key)) {\n cache.set(key, createSuspender(loader()) as Suspender<unknown>);\n }\n\n return cache.get(key)!.settled;\n};\n"],"mappings":";;AAWA,MAAM,mBAAsB,YAAsC;CAChE,IAAI,SAAiB;CACrB,IAAI;CACJ,MAAM,YAAY,QAAQ,MACvB,MAAM;EACL,SAAS;EACT,SAAS;CACX,IACC,MAAM;EACL,SAAS;EACT,SAAS;CACX,CACF;CAEA,OAAO;EACL,SAAS;EACT,OAAO;GACL,IAAI,WAAW,WAAW,MAAM;GAChC,IAAI,WAAW,SAAS,MAAM;GAC9B,OAAO;EACT;CACF;AACF;AAEA,MAAM,wBAAQ,IAAI,IAAgC;AAElD,MAAa,kBAAqB,KAAa,YAA2B;CACxE,IAAI,CAAC,MAAM,IAAI,GAAG,GAChB,MAAM,IAAI,KAAK,gBAAgB,OAAO,CAAC;CAGzC,OAAQ,MAAM,IAAI,GAAG,CAAC,CAAmB,KAAK;AAChD;;;;;;;;;;;;;;;;;;;;AAqBA,MAAa,kBACX,KACA,WACkB;CAClB,IAAI,CAAC,MAAM,IAAI,GAAG,GAChB,MAAM,IAAI,KAAK,gBAAgB,OAAO,CAAC,CAAuB;CAGhE,OAAO,MAAM,IAAI,GAAG,CAAC,CAAE;AACzB"}
@@ -25,6 +25,32 @@ const useIntlayer = () => require_server_serverContext.getServerContext(Intlayer
25
25
  */
26
26
  const locale = require_server_serverContext.getServerContext(IntlayerServerContext);
27
27
  /**
28
+ * Seeds the request-scoped server context locale imperatively — the equivalent
29
+ * of mounting {@link IntlayerServerProvider} without wrapping the tree.
30
+ *
31
+ * Useful in pages that must stay statically rendered while no ambient
32
+ * request-derived locale source is static-safe (Next.js < 16):
33
+ *
34
+ * ```tsx
35
+ * const Page = async ({ params }) => {
36
+ * const { locale } = await params;
37
+ * setLocale(locale);
38
+ * return <PageContent />;
39
+ * };
40
+ * ```
41
+ */
42
+ const setLocale = (locale) => {
43
+ IntlayerServerContext._storage().value = locale;
44
+ };
45
+ /**
46
+ * Seeds the request-scoped ambient variant imperatively — the equivalent of
47
+ * the `variant` prop of {@link IntlayerServerProvider} without wrapping the
48
+ * tree. See that prop for the accepted shapes.
49
+ */
50
+ const setVariant = (variant) => {
51
+ IntlayerServerVariantContext._storage().value = variant;
52
+ };
53
+ /**
28
54
  * Provider that store the current locale on the server side
29
55
  */
30
56
  const IntlayerServerProvider = ({ children, locale = defaultLocale, variant }) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(IntlayerServerContext.Provider, {
@@ -40,5 +66,7 @@ exports.IntlayerServerContext = IntlayerServerContext;
40
66
  exports.IntlayerServerProvider = IntlayerServerProvider;
41
67
  exports.IntlayerServerVariantContext = IntlayerServerVariantContext;
42
68
  exports.locale = locale;
69
+ exports.setLocale = setLocale;
70
+ exports.setVariant = setVariant;
43
71
  exports.useIntlayer = useIntlayer;
44
72
  //# sourceMappingURL=IntlayerServerProvider.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"IntlayerServerProvider.cjs","names":["internationalization","createServerContext","getServerContext"],"sources":["../../../src/server/IntlayerServerProvider.tsx"],"sourcesContent":["import { internationalization } from '@intlayer/config/built';\nimport type {\n LocalesValues,\n ProviderVariant,\n} from '@intlayer/types/module_augmentation';\n\nimport type { FC, PropsWithChildren } from 'react';\nimport { createServerContext, getServerContext } from './serverContext';\n\nconst { defaultLocale } = internationalization ?? {};\n\n/**\n * Context that store the current locale on the server side\n */\nexport const IntlayerServerContext =\n createServerContext<LocalesValues>(defaultLocale);\n\n/**\n * Context that stores the ambient variant on the server side.\n *\n * Kept separate from {@link IntlayerServerContext} so the locale context keeps\n * its plain `LocalesValues` shape for the packages already reading it.\n */\nexport const IntlayerServerVariantContext =\n createServerContext<ProviderVariant>(undefined);\n\n/**\n * Hook that provides the current locale\n */\nexport const useIntlayer = () => getServerContext(IntlayerServerContext);\n\n/**\n * Get the current locale\n */\nexport const locale = getServerContext(IntlayerServerContext);\n\nexport type IntlayerServerProviderProps = PropsWithChildren & {\n locale?: LocalesValues;\n /**\n * Ambient variant applied to every dictionary read below this provider — for\n * a dimension resolved once per request (tenant, school type, plan tier…).\n *\n * Accepts a name (`'school1'`), an ordered preference chain\n * (`['school1', 'default']`), or a per-key map\n * (`{ key1: 'school1', default: 'base' }`). A call-site selector wins.\n */\n variant?: ProviderVariant;\n};\n\n/**\n * Provider that store the current locale on the server side\n */\nexport const IntlayerServerProvider: FC<IntlayerServerProviderProps> = ({\n children,\n locale = defaultLocale,\n variant,\n}) => (\n <IntlayerServerContext.Provider value={locale}>\n <IntlayerServerVariantContext.Provider value={variant}>\n {children}\n </IntlayerServerVariantContext.Provider>\n </IntlayerServerContext.Provider>\n);\n"],"mappings":";;;;;;AASA,MAAM,EAAE,kBAAkBA,+CAAwB,CAAC;;;;AAKnD,MAAa,wBACXC,iDAAmC,aAAa;;;;;;;AAQlD,MAAa,+BACXA,iDAAqC,MAAS;;;;AAKhD,MAAa,oBAAoBC,8CAAiB,qBAAqB;;;;AAKvE,MAAa,SAASA,8CAAiB,qBAAqB;;;;AAkB5D,MAAa,0BAA2D,EACtE,UACA,SAAS,eACT,cAEA,2CAAC,sBAAsB,UAAvB;CAAgC,OAAO;WACrC,2CAAC,6BAA6B,UAA9B;EAAuC,OAAO;EAC3C;CACoC;AACT"}
1
+ {"version":3,"file":"IntlayerServerProvider.cjs","names":["internationalization","createServerContext","getServerContext"],"sources":["../../../src/server/IntlayerServerProvider.tsx"],"sourcesContent":["import { internationalization } from '@intlayer/config/built';\nimport type {\n LocalesValues,\n ProviderVariant,\n} from '@intlayer/types/module_augmentation';\n\nimport type { FC, PropsWithChildren } from 'react';\nimport { createServerContext, getServerContext } from './serverContext';\n\nconst { defaultLocale } = internationalization ?? {};\n\n/**\n * Context that store the current locale on the server side\n */\nexport const IntlayerServerContext =\n createServerContext<LocalesValues>(defaultLocale);\n\n/**\n * Context that stores the ambient variant on the server side.\n *\n * Kept separate from {@link IntlayerServerContext} so the locale context keeps\n * its plain `LocalesValues` shape for the packages already reading it.\n */\nexport const IntlayerServerVariantContext =\n createServerContext<ProviderVariant>(undefined);\n\n/**\n * Hook that provides the current locale\n */\nexport const useIntlayer = () => getServerContext(IntlayerServerContext);\n\n/**\n * Get the current locale\n */\nexport const locale = getServerContext(IntlayerServerContext);\n\n/**\n * Seeds the request-scoped server context locale imperatively — the equivalent\n * of mounting {@link IntlayerServerProvider} without wrapping the tree.\n *\n * Useful in pages that must stay statically rendered while no ambient\n * request-derived locale source is static-safe (Next.js < 16):\n *\n * ```tsx\n * const Page = async ({ params }) => {\n * const { locale } = await params;\n * setLocale(locale);\n * return <PageContent />;\n * };\n * ```\n */\nexport const setLocale = (locale: LocalesValues): void => {\n IntlayerServerContext._storage().value = locale;\n};\n\n/**\n * Seeds the request-scoped ambient variant imperatively — the equivalent of\n * the `variant` prop of {@link IntlayerServerProvider} without wrapping the\n * tree. See that prop for the accepted shapes.\n */\nexport const setVariant = (variant: ProviderVariant): void => {\n IntlayerServerVariantContext._storage().value = variant;\n};\n\nexport type IntlayerServerProviderProps = PropsWithChildren & {\n locale?: LocalesValues;\n /**\n * Ambient variant applied to every dictionary read below this provider — for\n * a dimension resolved once per request (tenant, school type, plan tier…).\n *\n * Accepts a name (`'school1'`), an ordered preference chain\n * (`['school1', 'default']`), or a per-key map\n * (`{ key1: 'school1', default: 'base' }`). A call-site selector wins.\n */\n variant?: ProviderVariant;\n};\n\n/**\n * Provider that store the current locale on the server side\n */\nexport const IntlayerServerProvider: FC<IntlayerServerProviderProps> = ({\n children,\n locale = defaultLocale,\n variant,\n}) => (\n <IntlayerServerContext.Provider value={locale}>\n <IntlayerServerVariantContext.Provider value={variant}>\n {children}\n </IntlayerServerVariantContext.Provider>\n </IntlayerServerContext.Provider>\n);\n"],"mappings":";;;;;;AASA,MAAM,EAAE,kBAAkBA,+CAAwB,CAAC;;;;AAKnD,MAAa,wBACXC,iDAAmC,aAAa;;;;;;;AAQlD,MAAa,+BACXA,iDAAqC,MAAS;;;;AAKhD,MAAa,oBAAoBC,8CAAiB,qBAAqB;;;;AAKvE,MAAa,SAASA,8CAAiB,qBAAqB;;;;;;;;;;;;;;;;AAiB5D,MAAa,aAAa,WAAgC;CACxD,sBAAsB,SAAS,CAAC,CAAC,QAAQ;AAC3C;;;;;;AAOA,MAAa,cAAc,YAAmC;CAC5D,6BAA6B,SAAS,CAAC,CAAC,QAAQ;AAClD;;;;AAkBA,MAAa,0BAA2D,EACtE,UACA,SAAS,eACT,cAEA,2CAAC,sBAAsB,UAAvB;CAAgC,OAAO;WACrC,2CAAC,6BAA6B,UAA9B;EAAuC,OAAO;EAC3C;CACoC;AACT"}
@@ -1,4 +1,5 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
2
+ const require_server_serverContext = require('./serverContext.cjs');
2
3
  const require_server_IntlayerServerProvider = require('./IntlayerServerProvider.cjs');
3
4
  const require_server_t = require('./t.cjs');
4
5
  const require_server_useI18n = require('./useI18n.cjs');
@@ -12,7 +13,11 @@ const require_server_format_useIntl = require('./format/useIntl.cjs');
12
13
 
13
14
  exports.IntlayerServer = require_server_IntlayerServerProvider.IntlayerServerContext;
14
15
  exports.IntlayerServerProvider = require_server_IntlayerServerProvider.IntlayerServerProvider;
16
+ exports.IntlayerServerVariantContext = require_server_IntlayerServerProvider.IntlayerServerVariantContext;
17
+ exports.getServerContext = require_server_serverContext.getServerContext;
15
18
  exports.locale = require_server_IntlayerServerProvider.locale;
19
+ exports.setLocale = require_server_IntlayerServerProvider.setLocale;
20
+ exports.setVariant = require_server_IntlayerServerProvider.setVariant;
16
21
  exports.t = require_server_t.t;
17
22
  exports.useDictionary = require_server_useDictionary.useDictionary;
18
23
  exports.useDictionaryAsync = require_server_useDictionaryAsync.useDictionaryAsync;
@@ -1 +1 @@
1
- {"version":3,"file":"serverContext.cjs","names":[],"sources":["../../../src/server/serverContext.tsx"],"sourcesContent":["/**\n * Creates a new datastore for a given server context.\n * Attempts to closely mimic the `createContext` API.\n *\n * @example\n * const IntlayerServer = createServerContext<string | null>(null);\n *\n * <IntlayerServer value={locale}>\n * {children}\n * </IntlayerServer>\n */\nimport react, { type FC, type PropsWithChildren, type ReactNode } from 'react';\n\ntype CacheType<T> = () => { value: T | undefined };\n\nconst cacheFallback = () => () => ({ value: undefined });\n\nexport const createServerContext = <T,>(defaultValue?: T): ServerContext<T> => {\n throwInClient();\n\n /** @ts-ignore remove error Property 'cache' does not exist on type 'typeof React'. */\n const cache = react.cache<CacheType<T>> ?? cacheFallback;\n\n const getCache = cache(() => ({\n value: undefined,\n }));\n\n const Provider: FC<PropsWithChildren<{ value?: T }>> = ({\n children,\n value,\n }) => {\n getCache().value = value;\n return children;\n };\n\n const ServerContext = Provider as ServerContext<T>;\n ServerContext.Provider = Provider;\n ServerContext.Consumer = (props) => {\n const store = getCache();\n return props.children(store ? store.value : defaultValue);\n };\n ServerContext._storage = getCache;\n ServerContext._defaultValue = defaultValue;\n\n return ServerContext;\n};\n\n/**\n * Fetches a value present in a given server context.\n * Attempts to closely mimic the `useContext` API.\n *\n * @example\n * getServerContext(IntlayerServer);\n */\nexport const getServerContext = <T,>({\n _storage,\n _defaultValue,\n}: ServerContext<T>) => {\n // throwInClient();\n const store = _storage();\n if (!store) return _defaultValue;\n return store.value;\n};\n\ntype ServerContext<T> = FC<PropsWithChildren<{ value?: T }>> & {\n Provider: FC<PropsWithChildren<{ value?: T }>>;\n Consumer: FC<\n PropsWithChildren<{ children: (context: T | undefined) => ReactNode }>\n >;\n _storage: () => { value: T | undefined };\n _defaultValue: T | undefined;\n};\n\n/**\n * Throws if called within a client component environment.\n * Useful to help prevent mistakes.\n */\nconst throwInClient = (): undefined | never => {\n // If window.document is defined we're in a client component\n if (typeof window !== 'undefined') {\n throw new Error(`createServerContext only works in Server Components`);\n }\n};\n"],"mappings":";;;;;;;;;;;;;;;;;AAeA,MAAM,6BAA6B,EAAE,OAAO,OAAU;AAEtD,MAAa,uBAA2B,iBAAuC;CAC7E,cAAc;CAKd,MAAM,YAFQ,cAAM,SAAuB,cAErB,QAAQ,EAC5B,OAAO,OACT,EAAE;CAEF,MAAM,YAAkD,EACtD,UACA,YACI;EACJ,SAAS,CAAC,CAAC,QAAQ;EACnB,OAAO;CACT;CAEA,MAAM,gBAAgB;CACtB,cAAc,WAAW;CACzB,cAAc,YAAY,UAAU;EAClC,MAAM,QAAQ,SAAS;EACvB,OAAO,MAAM,SAAS,QAAQ,MAAM,QAAQ,YAAY;CAC1D;CACA,cAAc,WAAW;CACzB,cAAc,gBAAgB;CAE9B,OAAO;AACT;;;;;;;;AASA,MAAa,oBAAwB,EACnC,UACA,oBACsB;CAEtB,MAAM,QAAQ,SAAS;CACvB,IAAI,CAAC,OAAO,OAAO;CACnB,OAAO,MAAM;AACf;;;;;AAeA,MAAM,sBAAyC;CAE7C,IAAI,OAAO,WAAW,aACpB,MAAM,IAAI,MAAM,qDAAqD;AAEzE"}
1
+ {"version":3,"file":"serverContext.cjs","names":[],"sources":["../../../src/server/serverContext.tsx"],"sourcesContent":["/**\n * Creates a new datastore for a given server context.\n * Attempts to closely mimic the `createContext` API.\n *\n * @example\n * const IntlayerServer = createServerContext<string | null>(null);\n *\n * <IntlayerServer value={locale}>\n * {children}\n * </IntlayerServer>\n */\nimport react, { type FC, type PropsWithChildren, type ReactNode } from 'react';\n\ntype CacheType<T> = () => { value: T | undefined };\n\nconst cacheFallback = () => () => ({ value: undefined });\n\nexport const createServerContext = <T,>(defaultValue?: T): ServerContext<T> => {\n throwInClient();\n\n /** @ts-ignore remove error Property 'cache' does not exist on type 'typeof React'. */\n const cache = react.cache<CacheType<T>> ?? cacheFallback;\n\n const getCache = cache(() => ({\n value: undefined,\n }));\n\n const Provider: FC<PropsWithChildren<{ value?: T }>> = ({\n children,\n value,\n }) => {\n getCache().value = value;\n return children;\n };\n\n const ServerContext = Provider as ServerContext<T>;\n ServerContext.Provider = Provider;\n ServerContext.Consumer = (props) => {\n const store = getCache();\n return props.children(store ? store.value : defaultValue);\n };\n ServerContext._storage = getCache;\n ServerContext._defaultValue = defaultValue;\n\n return ServerContext;\n};\n\n/**\n * Fetches a value present in a given server context.\n * Attempts to closely mimic the `useContext` API.\n *\n * @example\n * getServerContext(IntlayerServer);\n */\nexport const getServerContext = <T,>({\n _storage,\n _defaultValue,\n}: ServerContext<T>) => {\n // throwInClient();\n const store = _storage();\n if (!store) return _defaultValue;\n return store.value;\n};\n\nexport type ServerContext<T> = FC<PropsWithChildren<{ value?: T }>> & {\n Provider: FC<PropsWithChildren<{ value?: T }>>;\n Consumer: FC<\n PropsWithChildren<{ children: (context: T | undefined) => ReactNode }>\n >;\n _storage: () => { value: T | undefined };\n _defaultValue: T | undefined;\n};\n\n/**\n * Throws if called within a client component environment.\n * Useful to help prevent mistakes.\n */\nconst throwInClient = (): undefined | never => {\n // If window.document is defined we're in a client component\n if (typeof window !== 'undefined') {\n throw new Error(`createServerContext only works in Server Components`);\n }\n};\n"],"mappings":";;;;;;;;;;;;;;;;;AAeA,MAAM,6BAA6B,EAAE,OAAO,OAAU;AAEtD,MAAa,uBAA2B,iBAAuC;CAC7E,cAAc;CAKd,MAAM,YAFQ,cAAM,SAAuB,cAErB,QAAQ,EAC5B,OAAO,OACT,EAAE;CAEF,MAAM,YAAkD,EACtD,UACA,YACI;EACJ,SAAS,CAAC,CAAC,QAAQ;EACnB,OAAO;CACT;CAEA,MAAM,gBAAgB;CACtB,cAAc,WAAW;CACzB,cAAc,YAAY,UAAU;EAClC,MAAM,QAAQ,SAAS;EACvB,OAAO,MAAM,SAAS,QAAQ,MAAM,QAAQ,YAAY;CAC1D;CACA,cAAc,WAAW;CACzB,cAAc,gBAAgB;CAE9B,OAAO;AACT;;;;;;;;AASA,MAAa,oBAAwB,EACnC,UACA,oBACsB;CAEtB,MAAM,QAAQ,SAAS;CACvB,IAAI,CAAC,OAAO,OAAO;CACnB,OAAO,MAAM;AACf;;;;;AAeA,MAAM,sBAAyC;CAE7C,IAAI,OAAO,WAAW,aACpB,MAAM,IAAI,MAAM,qDAAqD;AAEzE"}
@@ -11,10 +11,10 @@ import { isEnabled } from "@intlayer/analytics/isEnabled";
11
11
  * and keeps it aware of the current locale.
12
12
  *
13
13
  * Mirrors {@link useEditor}: the module is loaded via a dynamic `import()` so it
14
- * ships as its own async chunk, off the critical rendering path. Apps that
15
- * don't opt in (`analytics.enabled !== true`) pay nothing the whole body is
16
- * guarded by `INTLAYER_ANALYTICS_ENABLED` and dead-code-eliminated at build
17
- * time.
14
+ * ships as its own async chunk, off the critical rendering path. Apps that opt
15
+ * out (`analytics.enabled !== true`), or that never install
16
+ * `@intlayer/analytics`, pay nothing the whole body is guarded by
17
+ * `INTLAYER_ANALYTICS_ENABLED` and dead-code-eliminated at build time.
18
18
  */
19
19
  const useAnalytics = () => {
20
20
  const { locale } = useContext(IntlayerClientContext) ?? {};
@@ -1 +1 @@
1
- {"version":3,"file":"useAnalytics.mjs","names":[],"sources":["../../../src/analytics/useAnalytics.tsx"],"sourcesContent":["'use client';\n\nimport type { AnalyticsClient } from '@intlayer/analytics';\nimport { isEnabled } from '@intlayer/analytics/isEnabled';\nimport { useContext, useEffect, useRef } from 'react';\nimport { IntlayerClientContext } from '../client/IntlayerProvider';\nimport { setExposureSink } from './exposureSink';\n\n/**\n * Initializes the Intlayer analytics client singleton when analytics is enabled\n * and keeps it aware of the current locale.\n *\n * Mirrors {@link useEditor}: the module is loaded via a dynamic `import()` so it\n * ships as its own async chunk, off the critical rendering path. Apps that\n * don't opt in (`analytics.enabled !== true`) pay nothing — the whole body is\n * guarded by `INTLAYER_ANALYTICS_ENABLED` and dead-code-eliminated at build\n * time.\n */\nexport const useAnalytics = () => {\n const { locale } = useContext(IntlayerClientContext) ?? {};\n const clientRef = useRef<AnalyticsClient | null>(null);\n\n useEffect(() => {\n if (process.env.INTLAYER_ANALYTICS_ENABLED === 'false' || !isEnabled) {\n return;\n }\n\n let cancelled = false;\n // Tracks whether initAnalyticsClient actually ran, so cleanup never calls\n // stopAnalyticsClient for an init that was cancelled — that would decrement\n // the shared reference count once too many and could stop a client another\n // provider still uses.\n let initialized = false;\n\n import('@intlayer/analytics')\n .then(({ initAnalyticsClient, buildContentExposure }) => {\n if (cancelled) return;\n\n const client = initAnalyticsClient();\n initialized = true;\n clientRef.current = client;\n\n if (locale) client.setLocale(locale);\n client.trackPageView({ reason: 'initial' });\n\n // Route node-level exposures (from the interpreter plugins) into the\n // client. Serialization happens here, off the hot render path.\n setExposureSink((input) =>\n client.trackContentExposure(buildContentExposure(input))\n );\n })\n .catch(() => {\n /* chunk failed to load — analytics stays a no-op */\n });\n\n return () => {\n cancelled = true;\n clientRef.current = null;\n setExposureSink(null);\n import('@intlayer/analytics')\n .then(({ stopAnalyticsClient }) => {\n if (initialized) stopAnalyticsClient();\n })\n .catch(() => {});\n };\n // Run once on mount; locale updates are handled by the effect below.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, []);\n\n useEffect(() => {\n if (!locale || !clientRef.current) return;\n\n clientRef.current.setLocale(locale);\n clientRef.current.trackPageView({ reason: 'locale_change' });\n }, [locale]);\n};\n"],"mappings":";;;;;;;;;;;;;;;;;;AAkBA,MAAa,qBAAqB;CAChC,MAAM,EAAE,WAAW,WAAW,qBAAqB,KAAK,CAAC;CACzD,MAAM,YAAY,OAA+B,IAAI;CAErD,gBAAgB;EACd,IAAI,QAAQ,IAAI,+BAA+B,WAAW,CAAC,WACzD;EAGF,IAAI,YAAY;EAKhB,IAAI,cAAc;EAElB,OAAO,sBAAsB,CAC1B,MAAM,EAAE,qBAAqB,2BAA2B;GACvD,IAAI,WAAW;GAEf,MAAM,SAAS,oBAAoB;GACnC,cAAc;GACd,UAAU,UAAU;GAEpB,IAAI,QAAQ,OAAO,UAAU,MAAM;GACnC,OAAO,cAAc,EAAE,QAAQ,UAAU,CAAC;GAI1C,iBAAiB,UACf,OAAO,qBAAqB,qBAAqB,KAAK,CAAC,CACzD;EACF,CAAC,CAAC,CACD,YAAY,CAEb,CAAC;EAEH,aAAa;GACX,YAAY;GACZ,UAAU,UAAU;GACpB,gBAAgB,IAAI;GACpB,OAAO,sBAAsB,CAC1B,MAAM,EAAE,0BAA0B;IACjC,IAAI,aAAa,oBAAoB;GACvC,CAAC,CAAC,CACD,YAAY,CAAC,CAAC;EACnB;CAGF,GAAG,CAAC,CAAC;CAEL,gBAAgB;EACd,IAAI,CAAC,UAAU,CAAC,UAAU,SAAS;EAEnC,UAAU,QAAQ,UAAU,MAAM;EAClC,UAAU,QAAQ,cAAc,EAAE,QAAQ,gBAAgB,CAAC;CAC7D,GAAG,CAAC,MAAM,CAAC;AACb"}
1
+ {"version":3,"file":"useAnalytics.mjs","names":[],"sources":["../../../src/analytics/useAnalytics.tsx"],"sourcesContent":["'use client';\n\nimport type { AnalyticsClient } from '@intlayer/analytics';\nimport { isEnabled } from '@intlayer/analytics/isEnabled';\nimport { useContext, useEffect, useRef } from 'react';\nimport { IntlayerClientContext } from '../client/IntlayerProvider';\nimport { setExposureSink } from './exposureSink';\n\n/**\n * Initializes the Intlayer analytics client singleton when analytics is enabled\n * and keeps it aware of the current locale.\n *\n * Mirrors {@link useEditor}: the module is loaded via a dynamic `import()` so it\n * ships as its own async chunk, off the critical rendering path. Apps that opt\n * out (`analytics.enabled !== true`), or that never install\n * `@intlayer/analytics`, pay nothing — the whole body is guarded by\n * `INTLAYER_ANALYTICS_ENABLED` and dead-code-eliminated at build time.\n */\nexport const useAnalytics = () => {\n const { locale } = useContext(IntlayerClientContext) ?? {};\n const clientRef = useRef<AnalyticsClient | null>(null);\n\n useEffect(() => {\n if (process.env.INTLAYER_ANALYTICS_ENABLED === 'false' || !isEnabled) {\n return;\n }\n\n let cancelled = false;\n // Tracks whether initAnalyticsClient actually ran, so cleanup never calls\n // stopAnalyticsClient for an init that was cancelled — that would decrement\n // the shared reference count once too many and could stop a client another\n // provider still uses.\n let initialized = false;\n\n import('@intlayer/analytics')\n .then(({ initAnalyticsClient, buildContentExposure }) => {\n if (cancelled) return;\n\n const client = initAnalyticsClient();\n initialized = true;\n clientRef.current = client;\n\n if (locale) client.setLocale(locale);\n client.trackPageView({ reason: 'initial' });\n\n // Route node-level exposures (from the interpreter plugins) into the\n // client. Serialization happens here, off the hot render path.\n setExposureSink((input) =>\n client.trackContentExposure(buildContentExposure(input))\n );\n })\n .catch(() => {\n /* chunk failed to load — analytics stays a no-op */\n });\n\n return () => {\n cancelled = true;\n clientRef.current = null;\n setExposureSink(null);\n import('@intlayer/analytics')\n .then(({ stopAnalyticsClient }) => {\n if (initialized) stopAnalyticsClient();\n })\n .catch(() => {});\n };\n // Run once on mount; locale updates are handled by the effect below.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, []);\n\n useEffect(() => {\n if (!locale || !clientRef.current) return;\n\n clientRef.current.setLocale(locale);\n clientRef.current.trackPageView({ reason: 'locale_change' });\n }, [locale]);\n};\n"],"mappings":";;;;;;;;;;;;;;;;;;AAkBA,MAAa,qBAAqB;CAChC,MAAM,EAAE,WAAW,WAAW,qBAAqB,KAAK,CAAC;CACzD,MAAM,YAAY,OAA+B,IAAI;CAErD,gBAAgB;EACd,IAAI,QAAQ,IAAI,+BAA+B,WAAW,CAAC,WACzD;EAGF,IAAI,YAAY;EAKhB,IAAI,cAAc;EAElB,OAAO,sBAAsB,CAC1B,MAAM,EAAE,qBAAqB,2BAA2B;GACvD,IAAI,WAAW;GAEf,MAAM,SAAS,oBAAoB;GACnC,cAAc;GACd,UAAU,UAAU;GAEpB,IAAI,QAAQ,OAAO,UAAU,MAAM;GACnC,OAAO,cAAc,EAAE,QAAQ,UAAU,CAAC;GAI1C,iBAAiB,UACf,OAAO,qBAAqB,qBAAqB,KAAK,CAAC,CACzD;EACF,CAAC,CAAC,CACD,YAAY,CAEb,CAAC;EAEH,aAAa;GACX,YAAY;GACZ,UAAU,UAAU;GACpB,gBAAgB,IAAI;GACpB,OAAO,sBAAsB,CAC1B,MAAM,EAAE,0BAA0B;IACjC,IAAI,aAAa,oBAAoB;GACvC,CAAC,CAAC,CACD,YAAY,CAAC,CAAC;EACnB;CAGF,GAAG,CAAC,CAAC;CAEL,gBAAgB;EACd,IAAI,CAAC,UAAU,CAAC,UAAU,SAAS;EAEnC,UAAU,QAAQ,UAAU,MAAM;EAClC,UAAU,QAAQ,cAAc,EAAE,QAAQ,gBAAgB,CAAC;CAC7D,GAAG,CAAC,MAAM,CAAC;AACb"}
@@ -5,7 +5,7 @@ import { getDictionary } from "../getDictionary.mjs";
5
5
  import { IntlayerClientContext } from "./IntlayerProvider.mjs";
6
6
  import { internationalization } from "@intlayer/config/built";
7
7
  import { useContext } from "react";
8
- import { isQualifiedDynamicLoaderMap, parseDictionarySelector, resolveDictionaryArgument, resolveQualifiedDynamicContent } from "@intlayer/core/dictionaryManipulator";
8
+ import { getPreloadedDictionary, isQualifiedDynamicLoaderMap, parseDictionarySelector, resolveDictionaryArgument, resolveQualifiedDynamicContent } from "@intlayer/core/dictionaryManipulator";
9
9
 
10
10
  //#region src/client/useDictionaryDynamic.ts
11
11
  /**
@@ -39,6 +39,8 @@ const useDictionaryDynamic = (dictionaryPromise, key, localeOrSelector) => {
39
39
  loadChunk: (cacheKey, promise) => useLoadDynamic(cacheKey, promise),
40
40
  transform: (dictionary) => getDictionary(dictionary, localeTarget)
41
41
  });
42
+ const preloadedDictionary = getPreloadedDictionary(dictionaryPromise, localeTarget);
43
+ if (preloadedDictionary) return getDictionary(preloadedDictionary, localeTarget);
42
44
  const plainLoaders = dictionaryPromise;
43
45
  const dictionary = useLoadDynamic(`${String(key)}.${localeTarget}`, plainLoaders[localeTarget]?.());
44
46
  return getDictionary(dictionary, localeTarget);
@@ -1 +1 @@
1
- {"version":3,"file":"useDictionaryDynamic.mjs","names":["loadDynamicChunk"],"sources":["../../../src/client/useDictionaryDynamic.ts"],"sourcesContent":["'use client';\n\nimport { internationalization } from '@intlayer/config/built';\nimport {\n isQualifiedDynamicLoaderMap,\n parseDictionarySelector,\n type QualifiedDynamicLoaderMap,\n resolveDictionaryArgument,\n resolveQualifiedDynamicContent,\n} from '@intlayer/core/dictionaryManipulator';\nimport type { Dictionary } from '@intlayer/types/dictionary';\nimport type {\n DeclaredLocales,\n DictionaryKeys,\n DictionarySelectorForKey,\n LocalesValues,\n StrictModeLocaleMap,\n} from '@intlayer/types/module_augmentation';\nimport { useContext } from 'react';\nimport { getDictionary } from '../getDictionary';\nimport { IntlayerClientContext } from './IntlayerProvider';\n// `useLoadDynamic` is a suspender cache, not a React hook — aliased to a\n// non-hook name so it can be invoked in loops / conditionally (e.g. when a\n// collection loads several chunks at once).\nimport { useLoadDynamic as loadDynamicChunk } from './useLoadDynamic';\n\n/**\n * Client-side hook that lazily loads a dictionary and returns its content.\n *\n * The dictionary entry is either a plain dynamic loader map\n * (`locale → loader`) or a qualified one (`locale → qualifierId → loader`,\n * tagged with the qualifier dimension). For qualified maps, only the chunk(s)\n * the selector targets are loaded; the resolution mirrors static mode.\n *\n * If the locale is not provided (directly or through the selector), the client\n * context locale is used.\n */\nexport const useDictionaryDynamic = <\n const T extends Dictionary,\n const K extends DictionaryKeys,\n const A extends LocalesValues | DictionarySelectorForKey<K> = DeclaredLocales,\n>(\n dictionaryPromise:\n | StrictModeLocaleMap<() => Promise<T>>\n | QualifiedDynamicLoaderMap,\n key: K,\n localeOrSelector?: A\n) => {\n const { locale: currentLocale, variant: contextVariant } =\n useContext(IntlayerClientContext) ?? {};\n\n const { locale: selectorLocale, selector } =\n process.env.INTLAYER_DICTIONARY_SELECTOR !== 'false'\n ? parseDictionarySelector<LocalesValues>(\n // Layers the provider's ambient variant under the call-site argument\n // before the chunk walk, so only the targeted chunk is loaded.\n resolveDictionaryArgument({\n localeOrSelector,\n contextLocale: currentLocale,\n contextVariant,\n dictionaryKey: String(key),\n })\n )\n : {\n locale: localeOrSelector as LocalesValues | undefined,\n selector: undefined,\n };\n\n const localeTarget =\n selectorLocale ?? currentLocale ?? internationalization.defaultLocale;\n\n if (\n process.env.INTLAYER_DICTIONARY_SELECTOR !== 'false' &&\n isQualifiedDynamicLoaderMap(dictionaryPromise)\n ) {\n return resolveQualifiedDynamicContent({\n loaderMap: dictionaryPromise,\n key: String(key),\n locale: localeTarget,\n selector,\n loadChunk: (cacheKey, promise) => loadDynamicChunk(cacheKey, promise),\n transform: (dictionary) => getDictionary(dictionary, localeTarget),\n });\n }\n\n const plainLoaders = dictionaryPromise as StrictModeLocaleMap<\n () => Promise<T>\n >;\n\n const dictionary = loadDynamicChunk<T>(\n `${String(key)}.${localeTarget}`,\n plainLoaders[localeTarget as keyof typeof plainLoaders]?.() as Promise<T>\n );\n\n return getDictionary(dictionary, localeTarget);\n};\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;AAqCA,MAAa,wBAKX,mBAGA,KACA,qBACG;CACH,MAAM,EAAE,QAAQ,eAAe,SAAS,mBACtC,WAAW,qBAAqB,KAAK,CAAC;CAExC,MAAM,EAAE,QAAQ,gBAAgB,aAC9B,QAAQ,IAAI,iCAAiC,UACzC,wBAGE,0BAA0B;EACxB;EACA,eAAe;EACf;EACA,eAAe,OAAO,GAAG;CAC3B,CAAC,CACH,IACA;EACE,QAAQ;EACR,UAAU;CACZ;CAEN,MAAM,eACJ,kBAAkB,iBAAiB,qBAAqB;CAE1D,IACE,QAAQ,IAAI,iCAAiC,WAC7C,4BAA4B,iBAAiB,GAE7C,OAAO,+BAA+B;EACpC,WAAW;EACX,KAAK,OAAO,GAAG;EACf,QAAQ;EACR;EACA,YAAY,UAAU,YAAYA,eAAiB,UAAU,OAAO;EACpE,YAAY,eAAe,cAAc,YAAY,YAAY;CACnE,CAAC;CAGH,MAAM,eAAe;CAIrB,MAAM,aAAaA,eACjB,GAAG,OAAO,GAAG,EAAE,GAAG,gBAClB,aAAa,aAA0C,GAAG,CAC5D;CAEA,OAAO,cAAc,YAAY,YAAY;AAC/C"}
1
+ {"version":3,"file":"useDictionaryDynamic.mjs","names":["loadDynamicChunk"],"sources":["../../../src/client/useDictionaryDynamic.ts"],"sourcesContent":["'use client';\n\nimport { internationalization } from '@intlayer/config/built';\nimport {\n getPreloadedDictionary,\n isQualifiedDynamicLoaderMap,\n parseDictionarySelector,\n type QualifiedDynamicLoaderMap,\n resolveDictionaryArgument,\n resolveQualifiedDynamicContent,\n} from '@intlayer/core/dictionaryManipulator';\nimport type { Dictionary } from '@intlayer/types/dictionary';\nimport type {\n DeclaredLocales,\n DictionaryKeys,\n DictionarySelectorForKey,\n LocalesValues,\n StrictModeLocaleMap,\n} from '@intlayer/types/module_augmentation';\nimport { useContext } from 'react';\nimport { getDictionary } from '../getDictionary';\nimport { IntlayerClientContext } from './IntlayerProvider';\n// `useLoadDynamic` is a suspender cache, not a React hook — aliased to a\n// non-hook name so it can be invoked in loops / conditionally (e.g. when a\n// collection loads several chunks at once).\nimport { useLoadDynamic as loadDynamicChunk } from './useLoadDynamic';\n\n/**\n * Client-side hook that lazily loads a dictionary and returns its content.\n *\n * The dictionary entry is either a plain dynamic loader map\n * (`locale → loader`) or a qualified one (`locale → qualifierId → loader`,\n * tagged with the qualifier dimension). For qualified maps, only the chunk(s)\n * the selector targets are loaded; the resolution mirrors static mode.\n *\n * If the locale is not provided (directly or through the selector), the client\n * context locale is used.\n */\nexport const useDictionaryDynamic = <\n const T extends Dictionary,\n const K extends DictionaryKeys,\n const A extends LocalesValues | DictionarySelectorForKey<K> = DeclaredLocales,\n>(\n dictionaryPromise:\n | StrictModeLocaleMap<() => Promise<T>>\n | QualifiedDynamicLoaderMap,\n key: K,\n localeOrSelector?: A\n) => {\n const { locale: currentLocale, variant: contextVariant } =\n useContext(IntlayerClientContext) ?? {};\n\n const { locale: selectorLocale, selector } =\n process.env.INTLAYER_DICTIONARY_SELECTOR !== 'false'\n ? parseDictionarySelector<LocalesValues>(\n // Layers the provider's ambient variant under the call-site argument\n // before the chunk walk, so only the targeted chunk is loaded.\n resolveDictionaryArgument({\n localeOrSelector,\n contextLocale: currentLocale,\n contextVariant,\n dictionaryKey: String(key),\n })\n )\n : {\n locale: localeOrSelector as LocalesValues | undefined,\n selector: undefined,\n };\n\n const localeTarget =\n selectorLocale ?? currentLocale ?? internationalization.defaultLocale;\n\n if (\n process.env.INTLAYER_DICTIONARY_SELECTOR !== 'false' &&\n isQualifiedDynamicLoaderMap(dictionaryPromise)\n ) {\n return resolveQualifiedDynamicContent({\n loaderMap: dictionaryPromise,\n key: String(key),\n locale: localeTarget,\n selector,\n loadChunk: (cacheKey, promise) => loadDynamicChunk(cacheKey, promise),\n transform: (dictionary) => getDictionary(dictionary, localeTarget),\n });\n }\n\n // A build-tool plugin may have started this locale's chunk while the entry\n // point itself was evaluating, in which case the content is already here and\n // reading it must not go through the suspender — see `getPreloadedDictionary`.\n const preloadedDictionary = getPreloadedDictionary(\n dictionaryPromise,\n localeTarget\n );\n if (preloadedDictionary) {\n return getDictionary(preloadedDictionary as T, localeTarget);\n }\n\n const plainLoaders = dictionaryPromise as StrictModeLocaleMap<\n () => Promise<T>\n >;\n\n const dictionary = loadDynamicChunk<T>(\n `${String(key)}.${localeTarget}`,\n plainLoaders[localeTarget as keyof typeof plainLoaders]?.() as Promise<T>\n );\n\n return getDictionary(dictionary, localeTarget);\n};\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;AAsCA,MAAa,wBAKX,mBAGA,KACA,qBACG;CACH,MAAM,EAAE,QAAQ,eAAe,SAAS,mBACtC,WAAW,qBAAqB,KAAK,CAAC;CAExC,MAAM,EAAE,QAAQ,gBAAgB,aAC9B,QAAQ,IAAI,iCAAiC,UACzC,wBAGE,0BAA0B;EACxB;EACA,eAAe;EACf;EACA,eAAe,OAAO,GAAG;CAC3B,CAAC,CACH,IACA;EACE,QAAQ;EACR,UAAU;CACZ;CAEN,MAAM,eACJ,kBAAkB,iBAAiB,qBAAqB;CAE1D,IACE,QAAQ,IAAI,iCAAiC,WAC7C,4BAA4B,iBAAiB,GAE7C,OAAO,+BAA+B;EACpC,WAAW;EACX,KAAK,OAAO,GAAG;EACf,QAAQ;EACR;EACA,YAAY,UAAU,YAAYA,eAAiB,UAAU,OAAO;EACpE,YAAY,eAAe,cAAc,YAAY,YAAY;CACnE,CAAC;CAMH,MAAM,sBAAsB,uBAC1B,mBACA,YACF;CACA,IAAI,qBACF,OAAO,cAAc,qBAA0B,YAAY;CAG7D,MAAM,eAAe;CAIrB,MAAM,aAAaA,eACjB,GAAG,OAAO,GAAG,EAAE,GAAG,gBAClB,aAAa,aAA0C,GAAG,CAC5D;CAEA,OAAO,cAAc,YAAY,YAAY;AAC/C"}
@@ -9,18 +9,44 @@ const createSuspender = (promise) => {
9
9
  status = "error";
10
10
  result = e;
11
11
  });
12
- return { read() {
13
- if (status === "pending") throw suspender;
14
- if (status === "error") throw result;
15
- return result;
16
- } };
12
+ return {
13
+ settled: suspender,
14
+ read() {
15
+ if (status === "pending") throw suspender;
16
+ if (status === "error") throw result;
17
+ return result;
18
+ }
19
+ };
17
20
  };
18
21
  const cache = /* @__PURE__ */ new Map();
19
22
  const useLoadDynamic = (key, promise) => {
20
23
  if (!cache.has(key)) cache.set(key, createSuspender(promise));
21
24
  return cache.get(key).read();
22
25
  };
26
+ /**
27
+ * Fills the same cache {@link useLoadDynamic} reads, ahead of render.
28
+ *
29
+ * A component that reads a dictionary during render suspends whenever the entry
30
+ * is still `pending`, and the nearest boundary shows its fallback. Awaiting this
31
+ * before the render — in a router loader, or during app startup — makes that
32
+ * read synchronous, so no boundary ever falls back.
33
+ *
34
+ * Handing over an already-resolved promise is not enough on its own:
35
+ * {@link createSuspender} only leaves `pending` inside a `.then` callback, so
36
+ * the first read would still suspend for one microtask. Awaiting the returned
37
+ * promise resolves that race, because the callback registered by
38
+ * `createSuspender` runs before this one.
39
+ *
40
+ * @param key - Cache key, identical to the one the later read uses.
41
+ * @param loader - Invoked only when the key is not cached yet, so preloading a
42
+ * dictionary twice never issues a second request.
43
+ * @returns A promise that settles — never rejects — once the entry is readable.
44
+ */
45
+ const preloadDynamic = (key, loader) => {
46
+ if (!cache.has(key)) cache.set(key, createSuspender(loader()));
47
+ return cache.get(key).settled;
48
+ };
23
49
 
24
50
  //#endregion
25
- export { useLoadDynamic };
51
+ export { preloadDynamic, useLoadDynamic };
26
52
  //# sourceMappingURL=useLoadDynamic.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"useLoadDynamic.mjs","names":[],"sources":["../../../src/client/useLoadDynamic.ts"],"sourcesContent":["type Status = 'pending' | 'success' | 'error';\n\nconst createSuspender = <T>(promise: Promise<T>) => {\n let status: Status = 'pending';\n let result: T;\n const suspender = promise.then(\n (r) => {\n status = 'success';\n result = r;\n },\n (e) => {\n status = 'error';\n result = e as any;\n }\n );\n\n return {\n read() {\n if (status === 'pending') throw suspender;\n if (status === 'error') throw result;\n return result!;\n },\n };\n};\n\nconst cache = new Map<string, ReturnType<typeof createSuspender>>();\n\nexport const useLoadDynamic = <T>(key: string, promise: Promise<T>): T => {\n if (!cache.has(key)) {\n cache.set(key, createSuspender(promise));\n }\n\n return (cache.get(key)! as ReturnType<typeof createSuspender>).read() as T;\n};\n"],"mappings":";AAEA,MAAM,mBAAsB,YAAwB;CAClD,IAAI,SAAiB;CACrB,IAAI;CACJ,MAAM,YAAY,QAAQ,MACvB,MAAM;EACL,SAAS;EACT,SAAS;CACX,IACC,MAAM;EACL,SAAS;EACT,SAAS;CACX,CACF;CAEA,OAAO,EACL,OAAO;EACL,IAAI,WAAW,WAAW,MAAM;EAChC,IAAI,WAAW,SAAS,MAAM;EAC9B,OAAO;CACT,EACF;AACF;AAEA,MAAM,wBAAQ,IAAI,IAAgD;AAElE,MAAa,kBAAqB,KAAa,YAA2B;CACxE,IAAI,CAAC,MAAM,IAAI,GAAG,GAChB,MAAM,IAAI,KAAK,gBAAgB,OAAO,CAAC;CAGzC,OAAQ,MAAM,IAAI,GAAG,CAAC,CAAyC,KAAK;AACtE"}
1
+ {"version":3,"file":"useLoadDynamic.mjs","names":[],"sources":["../../../src/client/useLoadDynamic.ts"],"sourcesContent":["type Status = 'pending' | 'success' | 'error';\n\ntype Suspender<T> = {\n /**\n * Settles once the entry has left `pending`, never rejecting. Awaiting it\n * guarantees a subsequent {@link Suspender.read} returns without suspending.\n */\n settled: Promise<void>;\n read: () => T;\n};\n\nconst createSuspender = <T>(promise: Promise<T>): Suspender<T> => {\n let status: Status = 'pending';\n let result: T;\n const suspender = promise.then(\n (r) => {\n status = 'success';\n result = r;\n },\n (e) => {\n status = 'error';\n result = e as any;\n }\n );\n\n return {\n settled: suspender,\n read() {\n if (status === 'pending') throw suspender;\n if (status === 'error') throw result;\n return result!;\n },\n };\n};\n\nconst cache = new Map<string, Suspender<unknown>>();\n\nexport const useLoadDynamic = <T>(key: string, promise: Promise<T>): T => {\n if (!cache.has(key)) {\n cache.set(key, createSuspender(promise));\n }\n\n return (cache.get(key)! as Suspender<T>).read() as T;\n};\n\n/**\n * Fills the same cache {@link useLoadDynamic} reads, ahead of render.\n *\n * A component that reads a dictionary during render suspends whenever the entry\n * is still `pending`, and the nearest boundary shows its fallback. Awaiting this\n * before the render — in a router loader, or during app startup — makes that\n * read synchronous, so no boundary ever falls back.\n *\n * Handing over an already-resolved promise is not enough on its own:\n * {@link createSuspender} only leaves `pending` inside a `.then` callback, so\n * the first read would still suspend for one microtask. Awaiting the returned\n * promise resolves that race, because the callback registered by\n * `createSuspender` runs before this one.\n *\n * @param key - Cache key, identical to the one the later read uses.\n * @param loader - Invoked only when the key is not cached yet, so preloading a\n * dictionary twice never issues a second request.\n * @returns A promise that settles — never rejects — once the entry is readable.\n */\nexport const preloadDynamic = <T>(\n key: string,\n loader: () => Promise<T>\n): Promise<void> => {\n if (!cache.has(key)) {\n cache.set(key, createSuspender(loader()) as Suspender<unknown>);\n }\n\n return cache.get(key)!.settled;\n};\n"],"mappings":";AAWA,MAAM,mBAAsB,YAAsC;CAChE,IAAI,SAAiB;CACrB,IAAI;CACJ,MAAM,YAAY,QAAQ,MACvB,MAAM;EACL,SAAS;EACT,SAAS;CACX,IACC,MAAM;EACL,SAAS;EACT,SAAS;CACX,CACF;CAEA,OAAO;EACL,SAAS;EACT,OAAO;GACL,IAAI,WAAW,WAAW,MAAM;GAChC,IAAI,WAAW,SAAS,MAAM;GAC9B,OAAO;EACT;CACF;AACF;AAEA,MAAM,wBAAQ,IAAI,IAAgC;AAElD,MAAa,kBAAqB,KAAa,YAA2B;CACxE,IAAI,CAAC,MAAM,IAAI,GAAG,GAChB,MAAM,IAAI,KAAK,gBAAgB,OAAO,CAAC;CAGzC,OAAQ,MAAM,IAAI,GAAG,CAAC,CAAmB,KAAK;AAChD;;;;;;;;;;;;;;;;;;;;AAqBA,MAAa,kBACX,KACA,WACkB;CAClB,IAAI,CAAC,MAAM,IAAI,GAAG,GAChB,MAAM,IAAI,KAAK,gBAAgB,OAAO,CAAC,CAAuB;CAGhE,OAAO,MAAM,IAAI,GAAG,CAAC,CAAE;AACzB"}
@@ -24,6 +24,32 @@ const useIntlayer = () => getServerContext(IntlayerServerContext);
24
24
  */
25
25
  const locale = getServerContext(IntlayerServerContext);
26
26
  /**
27
+ * Seeds the request-scoped server context locale imperatively — the equivalent
28
+ * of mounting {@link IntlayerServerProvider} without wrapping the tree.
29
+ *
30
+ * Useful in pages that must stay statically rendered while no ambient
31
+ * request-derived locale source is static-safe (Next.js < 16):
32
+ *
33
+ * ```tsx
34
+ * const Page = async ({ params }) => {
35
+ * const { locale } = await params;
36
+ * setLocale(locale);
37
+ * return <PageContent />;
38
+ * };
39
+ * ```
40
+ */
41
+ const setLocale = (locale) => {
42
+ IntlayerServerContext._storage().value = locale;
43
+ };
44
+ /**
45
+ * Seeds the request-scoped ambient variant imperatively — the equivalent of
46
+ * the `variant` prop of {@link IntlayerServerProvider} without wrapping the
47
+ * tree. See that prop for the accepted shapes.
48
+ */
49
+ const setVariant = (variant) => {
50
+ IntlayerServerVariantContext._storage().value = variant;
51
+ };
52
+ /**
27
53
  * Provider that store the current locale on the server side
28
54
  */
29
55
  const IntlayerServerProvider = ({ children, locale = defaultLocale, variant }) => /* @__PURE__ */ jsx(IntlayerServerContext.Provider, {
@@ -35,5 +61,5 @@ const IntlayerServerProvider = ({ children, locale = defaultLocale, variant }) =
35
61
  });
36
62
 
37
63
  //#endregion
38
- export { IntlayerServerContext, IntlayerServerProvider, IntlayerServerVariantContext, locale, useIntlayer };
64
+ export { IntlayerServerContext, IntlayerServerProvider, IntlayerServerVariantContext, locale, setLocale, setVariant, useIntlayer };
39
65
  //# sourceMappingURL=IntlayerServerProvider.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"IntlayerServerProvider.mjs","names":[],"sources":["../../../src/server/IntlayerServerProvider.tsx"],"sourcesContent":["import { internationalization } from '@intlayer/config/built';\nimport type {\n LocalesValues,\n ProviderVariant,\n} from '@intlayer/types/module_augmentation';\n\nimport type { FC, PropsWithChildren } from 'react';\nimport { createServerContext, getServerContext } from './serverContext';\n\nconst { defaultLocale } = internationalization ?? {};\n\n/**\n * Context that store the current locale on the server side\n */\nexport const IntlayerServerContext =\n createServerContext<LocalesValues>(defaultLocale);\n\n/**\n * Context that stores the ambient variant on the server side.\n *\n * Kept separate from {@link IntlayerServerContext} so the locale context keeps\n * its plain `LocalesValues` shape for the packages already reading it.\n */\nexport const IntlayerServerVariantContext =\n createServerContext<ProviderVariant>(undefined);\n\n/**\n * Hook that provides the current locale\n */\nexport const useIntlayer = () => getServerContext(IntlayerServerContext);\n\n/**\n * Get the current locale\n */\nexport const locale = getServerContext(IntlayerServerContext);\n\nexport type IntlayerServerProviderProps = PropsWithChildren & {\n locale?: LocalesValues;\n /**\n * Ambient variant applied to every dictionary read below this provider — for\n * a dimension resolved once per request (tenant, school type, plan tier…).\n *\n * Accepts a name (`'school1'`), an ordered preference chain\n * (`['school1', 'default']`), or a per-key map\n * (`{ key1: 'school1', default: 'base' }`). A call-site selector wins.\n */\n variant?: ProviderVariant;\n};\n\n/**\n * Provider that store the current locale on the server side\n */\nexport const IntlayerServerProvider: FC<IntlayerServerProviderProps> = ({\n children,\n locale = defaultLocale,\n variant,\n}) => (\n <IntlayerServerContext.Provider value={locale}>\n <IntlayerServerVariantContext.Provider value={variant}>\n {children}\n </IntlayerServerVariantContext.Provider>\n </IntlayerServerContext.Provider>\n);\n"],"mappings":";;;;;AASA,MAAM,EAAE,kBAAkB,wBAAwB,CAAC;;;;AAKnD,MAAa,wBACX,oBAAmC,aAAa;;;;;;;AAQlD,MAAa,+BACX,oBAAqC,MAAS;;;;AAKhD,MAAa,oBAAoB,iBAAiB,qBAAqB;;;;AAKvE,MAAa,SAAS,iBAAiB,qBAAqB;;;;AAkB5D,MAAa,0BAA2D,EACtE,UACA,SAAS,eACT,cAEA,oBAAC,sBAAsB,UAAvB;CAAgC,OAAO;WACrC,oBAAC,6BAA6B,UAA9B;EAAuC,OAAO;EAC3C;CACoC;AACT"}
1
+ {"version":3,"file":"IntlayerServerProvider.mjs","names":[],"sources":["../../../src/server/IntlayerServerProvider.tsx"],"sourcesContent":["import { internationalization } from '@intlayer/config/built';\nimport type {\n LocalesValues,\n ProviderVariant,\n} from '@intlayer/types/module_augmentation';\n\nimport type { FC, PropsWithChildren } from 'react';\nimport { createServerContext, getServerContext } from './serverContext';\n\nconst { defaultLocale } = internationalization ?? {};\n\n/**\n * Context that store the current locale on the server side\n */\nexport const IntlayerServerContext =\n createServerContext<LocalesValues>(defaultLocale);\n\n/**\n * Context that stores the ambient variant on the server side.\n *\n * Kept separate from {@link IntlayerServerContext} so the locale context keeps\n * its plain `LocalesValues` shape for the packages already reading it.\n */\nexport const IntlayerServerVariantContext =\n createServerContext<ProviderVariant>(undefined);\n\n/**\n * Hook that provides the current locale\n */\nexport const useIntlayer = () => getServerContext(IntlayerServerContext);\n\n/**\n * Get the current locale\n */\nexport const locale = getServerContext(IntlayerServerContext);\n\n/**\n * Seeds the request-scoped server context locale imperatively — the equivalent\n * of mounting {@link IntlayerServerProvider} without wrapping the tree.\n *\n * Useful in pages that must stay statically rendered while no ambient\n * request-derived locale source is static-safe (Next.js < 16):\n *\n * ```tsx\n * const Page = async ({ params }) => {\n * const { locale } = await params;\n * setLocale(locale);\n * return <PageContent />;\n * };\n * ```\n */\nexport const setLocale = (locale: LocalesValues): void => {\n IntlayerServerContext._storage().value = locale;\n};\n\n/**\n * Seeds the request-scoped ambient variant imperatively — the equivalent of\n * the `variant` prop of {@link IntlayerServerProvider} without wrapping the\n * tree. See that prop for the accepted shapes.\n */\nexport const setVariant = (variant: ProviderVariant): void => {\n IntlayerServerVariantContext._storage().value = variant;\n};\n\nexport type IntlayerServerProviderProps = PropsWithChildren & {\n locale?: LocalesValues;\n /**\n * Ambient variant applied to every dictionary read below this provider — for\n * a dimension resolved once per request (tenant, school type, plan tier…).\n *\n * Accepts a name (`'school1'`), an ordered preference chain\n * (`['school1', 'default']`), or a per-key map\n * (`{ key1: 'school1', default: 'base' }`). A call-site selector wins.\n */\n variant?: ProviderVariant;\n};\n\n/**\n * Provider that store the current locale on the server side\n */\nexport const IntlayerServerProvider: FC<IntlayerServerProviderProps> = ({\n children,\n locale = defaultLocale,\n variant,\n}) => (\n <IntlayerServerContext.Provider value={locale}>\n <IntlayerServerVariantContext.Provider value={variant}>\n {children}\n </IntlayerServerVariantContext.Provider>\n </IntlayerServerContext.Provider>\n);\n"],"mappings":";;;;;AASA,MAAM,EAAE,kBAAkB,wBAAwB,CAAC;;;;AAKnD,MAAa,wBACX,oBAAmC,aAAa;;;;;;;AAQlD,MAAa,+BACX,oBAAqC,MAAS;;;;AAKhD,MAAa,oBAAoB,iBAAiB,qBAAqB;;;;AAKvE,MAAa,SAAS,iBAAiB,qBAAqB;;;;;;;;;;;;;;;;AAiB5D,MAAa,aAAa,WAAgC;CACxD,sBAAsB,SAAS,CAAC,CAAC,QAAQ;AAC3C;;;;;;AAOA,MAAa,cAAc,YAAmC;CAC5D,6BAA6B,SAAS,CAAC,CAAC,QAAQ;AAClD;;;;AAkBA,MAAa,0BAA2D,EACtE,UACA,SAAS,eACT,cAEA,oBAAC,sBAAsB,UAAvB;CAAgC,OAAO;WACrC,oBAAC,6BAA6B,UAA9B;EAAuC,OAAO;EAC3C;CACoC;AACT"}
@@ -1,4 +1,5 @@
1
- import { IntlayerServerContext, IntlayerServerProvider, locale } from "./IntlayerServerProvider.mjs";
1
+ import { getServerContext } from "./serverContext.mjs";
2
+ import { IntlayerServerContext, IntlayerServerProvider, IntlayerServerVariantContext, locale, setLocale, setVariant } from "./IntlayerServerProvider.mjs";
2
3
  import { t } from "./t.mjs";
3
4
  import { useI18n } from "./useI18n.mjs";
4
5
  import { useIntlayer } from "./useIntlayer.mjs";
@@ -9,4 +10,4 @@ import { useLoadDynamic } from "./useLoadDynamic.mjs";
9
10
  import { useDictionaryDynamic } from "./useDictionaryDynamic.mjs";
10
11
  import { useIntl } from "./format/useIntl.mjs";
11
12
 
12
- export { IntlayerServerContext as IntlayerServer, IntlayerServerProvider, locale, t, useDictionary, useDictionaryAsync, useDictionaryDynamic, useI18n, useIntl, useIntlayer, useLoadDynamic, useLocale };
13
+ export { IntlayerServerContext as IntlayerServer, IntlayerServerProvider, IntlayerServerVariantContext, getServerContext, locale, setLocale, setVariant, t, useDictionary, useDictionaryAsync, useDictionaryDynamic, useI18n, useIntl, useIntlayer, useLoadDynamic, useLocale };
@@ -1 +1 @@
1
- {"version":3,"file":"serverContext.mjs","names":[],"sources":["../../../src/server/serverContext.tsx"],"sourcesContent":["/**\n * Creates a new datastore for a given server context.\n * Attempts to closely mimic the `createContext` API.\n *\n * @example\n * const IntlayerServer = createServerContext<string | null>(null);\n *\n * <IntlayerServer value={locale}>\n * {children}\n * </IntlayerServer>\n */\nimport react, { type FC, type PropsWithChildren, type ReactNode } from 'react';\n\ntype CacheType<T> = () => { value: T | undefined };\n\nconst cacheFallback = () => () => ({ value: undefined });\n\nexport const createServerContext = <T,>(defaultValue?: T): ServerContext<T> => {\n throwInClient();\n\n /** @ts-ignore remove error Property 'cache' does not exist on type 'typeof React'. */\n const cache = react.cache<CacheType<T>> ?? cacheFallback;\n\n const getCache = cache(() => ({\n value: undefined,\n }));\n\n const Provider: FC<PropsWithChildren<{ value?: T }>> = ({\n children,\n value,\n }) => {\n getCache().value = value;\n return children;\n };\n\n const ServerContext = Provider as ServerContext<T>;\n ServerContext.Provider = Provider;\n ServerContext.Consumer = (props) => {\n const store = getCache();\n return props.children(store ? store.value : defaultValue);\n };\n ServerContext._storage = getCache;\n ServerContext._defaultValue = defaultValue;\n\n return ServerContext;\n};\n\n/**\n * Fetches a value present in a given server context.\n * Attempts to closely mimic the `useContext` API.\n *\n * @example\n * getServerContext(IntlayerServer);\n */\nexport const getServerContext = <T,>({\n _storage,\n _defaultValue,\n}: ServerContext<T>) => {\n // throwInClient();\n const store = _storage();\n if (!store) return _defaultValue;\n return store.value;\n};\n\ntype ServerContext<T> = FC<PropsWithChildren<{ value?: T }>> & {\n Provider: FC<PropsWithChildren<{ value?: T }>>;\n Consumer: FC<\n PropsWithChildren<{ children: (context: T | undefined) => ReactNode }>\n >;\n _storage: () => { value: T | undefined };\n _defaultValue: T | undefined;\n};\n\n/**\n * Throws if called within a client component environment.\n * Useful to help prevent mistakes.\n */\nconst throwInClient = (): undefined | never => {\n // If window.document is defined we're in a client component\n if (typeof window !== 'undefined') {\n throw new Error(`createServerContext only works in Server Components`);\n }\n};\n"],"mappings":";;;;;;;;;;;;;;AAeA,MAAM,6BAA6B,EAAE,OAAO,OAAU;AAEtD,MAAa,uBAA2B,iBAAuC;CAC7E,cAAc;CAKd,MAAM,YAFQ,MAAM,SAAuB,cAErB,QAAQ,EAC5B,OAAO,OACT,EAAE;CAEF,MAAM,YAAkD,EACtD,UACA,YACI;EACJ,SAAS,CAAC,CAAC,QAAQ;EACnB,OAAO;CACT;CAEA,MAAM,gBAAgB;CACtB,cAAc,WAAW;CACzB,cAAc,YAAY,UAAU;EAClC,MAAM,QAAQ,SAAS;EACvB,OAAO,MAAM,SAAS,QAAQ,MAAM,QAAQ,YAAY;CAC1D;CACA,cAAc,WAAW;CACzB,cAAc,gBAAgB;CAE9B,OAAO;AACT;;;;;;;;AASA,MAAa,oBAAwB,EACnC,UACA,oBACsB;CAEtB,MAAM,QAAQ,SAAS;CACvB,IAAI,CAAC,OAAO,OAAO;CACnB,OAAO,MAAM;AACf;;;;;AAeA,MAAM,sBAAyC;CAE7C,IAAI,OAAO,WAAW,aACpB,MAAM,IAAI,MAAM,qDAAqD;AAEzE"}
1
+ {"version":3,"file":"serverContext.mjs","names":[],"sources":["../../../src/server/serverContext.tsx"],"sourcesContent":["/**\n * Creates a new datastore for a given server context.\n * Attempts to closely mimic the `createContext` API.\n *\n * @example\n * const IntlayerServer = createServerContext<string | null>(null);\n *\n * <IntlayerServer value={locale}>\n * {children}\n * </IntlayerServer>\n */\nimport react, { type FC, type PropsWithChildren, type ReactNode } from 'react';\n\ntype CacheType<T> = () => { value: T | undefined };\n\nconst cacheFallback = () => () => ({ value: undefined });\n\nexport const createServerContext = <T,>(defaultValue?: T): ServerContext<T> => {\n throwInClient();\n\n /** @ts-ignore remove error Property 'cache' does not exist on type 'typeof React'. */\n const cache = react.cache<CacheType<T>> ?? cacheFallback;\n\n const getCache = cache(() => ({\n value: undefined,\n }));\n\n const Provider: FC<PropsWithChildren<{ value?: T }>> = ({\n children,\n value,\n }) => {\n getCache().value = value;\n return children;\n };\n\n const ServerContext = Provider as ServerContext<T>;\n ServerContext.Provider = Provider;\n ServerContext.Consumer = (props) => {\n const store = getCache();\n return props.children(store ? store.value : defaultValue);\n };\n ServerContext._storage = getCache;\n ServerContext._defaultValue = defaultValue;\n\n return ServerContext;\n};\n\n/**\n * Fetches a value present in a given server context.\n * Attempts to closely mimic the `useContext` API.\n *\n * @example\n * getServerContext(IntlayerServer);\n */\nexport const getServerContext = <T,>({\n _storage,\n _defaultValue,\n}: ServerContext<T>) => {\n // throwInClient();\n const store = _storage();\n if (!store) return _defaultValue;\n return store.value;\n};\n\nexport type ServerContext<T> = FC<PropsWithChildren<{ value?: T }>> & {\n Provider: FC<PropsWithChildren<{ value?: T }>>;\n Consumer: FC<\n PropsWithChildren<{ children: (context: T | undefined) => ReactNode }>\n >;\n _storage: () => { value: T | undefined };\n _defaultValue: T | undefined;\n};\n\n/**\n * Throws if called within a client component environment.\n * Useful to help prevent mistakes.\n */\nconst throwInClient = (): undefined | never => {\n // If window.document is defined we're in a client component\n if (typeof window !== 'undefined') {\n throw new Error(`createServerContext only works in Server Components`);\n }\n};\n"],"mappings":";;;;;;;;;;;;;;AAeA,MAAM,6BAA6B,EAAE,OAAO,OAAU;AAEtD,MAAa,uBAA2B,iBAAuC;CAC7E,cAAc;CAKd,MAAM,YAFQ,MAAM,SAAuB,cAErB,QAAQ,EAC5B,OAAO,OACT,EAAE;CAEF,MAAM,YAAkD,EACtD,UACA,YACI;EACJ,SAAS,CAAC,CAAC,QAAQ;EACnB,OAAO;CACT;CAEA,MAAM,gBAAgB;CACtB,cAAc,WAAW;CACzB,cAAc,YAAY,UAAU;EAClC,MAAM,QAAQ,SAAS;EACvB,OAAO,MAAM,SAAS,QAAQ,MAAM,QAAQ,YAAY;CAC1D;CACA,cAAc,WAAW;CACzB,cAAc,gBAAgB;CAE9B,OAAO;AACT;;;;;;;;AASA,MAAa,oBAAwB,EACnC,UACA,oBACsB;CAEtB,MAAM,QAAQ,SAAS;CACvB,IAAI,CAAC,OAAO,OAAO;CACnB,OAAO,MAAM;AACf;;;;;AAeA,MAAM,sBAAyC;CAE7C,IAAI,OAAO,WAAW,aACpB,MAAM,IAAI,MAAM,qDAAqD;AAEzE"}
@@ -4,10 +4,10 @@
4
4
  * and keeps it aware of the current locale.
5
5
  *
6
6
  * Mirrors {@link useEditor}: the module is loaded via a dynamic `import()` so it
7
- * ships as its own async chunk, off the critical rendering path. Apps that
8
- * don't opt in (`analytics.enabled !== true`) pay nothing the whole body is
9
- * guarded by `INTLAYER_ANALYTICS_ENABLED` and dead-code-eliminated at build
10
- * time.
7
+ * ships as its own async chunk, off the critical rendering path. Apps that opt
8
+ * out (`analytics.enabled !== true`), or that never install
9
+ * `@intlayer/analytics`, pay nothing the whole body is guarded by
10
+ * `INTLAYER_ANALYTICS_ENABLED` and dead-code-eliminated at build time.
11
11
  */
12
12
  declare const useAnalytics: () => void;
13
13
  //#endregion
@@ -1 +1 @@
1
- {"version":3,"file":"useDictionaryDynamic.d.ts","names":[],"sources":["../../../src/client/useDictionaryDynamic.ts"],"mappings":";;;;;;;;;;;;;;;cAqCa,6BACL,UAAU,kBACV,UAAU,sBACV,UAAU,gBAAgB,yBAAyB,KAAK,iBAAe,mBAGzE,0BAA0B,QAAQ,MAClC,2BAAyB,KACxB,GAAC,mBACa"}
1
+ {"version":3,"file":"useDictionaryDynamic.d.ts","names":[],"sources":["../../../src/client/useDictionaryDynamic.ts"],"mappings":";;;;;;;;;;;;;;;cAsCa,6BACL,UAAU,kBACV,UAAU,sBACV,UAAU,gBAAgB,yBAAyB,KAAK,iBAAe,mBAGzE,0BAA0B,QAAQ,MAClC,2BAAyB,KACxB,GAAC,mBACa"}
@@ -1,5 +1,25 @@
1
1
  //#region src/client/useLoadDynamic.d.ts
2
2
  declare const useLoadDynamic: <T>(key: string, promise: Promise<T>) => T;
3
+ /**
4
+ * Fills the same cache {@link useLoadDynamic} reads, ahead of render.
5
+ *
6
+ * A component that reads a dictionary during render suspends whenever the entry
7
+ * is still `pending`, and the nearest boundary shows its fallback. Awaiting this
8
+ * before the render — in a router loader, or during app startup — makes that
9
+ * read synchronous, so no boundary ever falls back.
10
+ *
11
+ * Handing over an already-resolved promise is not enough on its own:
12
+ * {@link createSuspender} only leaves `pending` inside a `.then` callback, so
13
+ * the first read would still suspend for one microtask. Awaiting the returned
14
+ * promise resolves that race, because the callback registered by
15
+ * `createSuspender` runs before this one.
16
+ *
17
+ * @param key - Cache key, identical to the one the later read uses.
18
+ * @param loader - Invoked only when the key is not cached yet, so preloading a
19
+ * dictionary twice never issues a second request.
20
+ * @returns A promise that settles — never rejects — once the entry is readable.
21
+ */
22
+ declare const preloadDynamic: <T>(key: string, loader: () => Promise<T>) => Promise<void>;
3
23
  //#endregion
4
- export { useLoadDynamic };
24
+ export { preloadDynamic, useLoadDynamic };
5
25
  //# sourceMappingURL=useLoadDynamic.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"useLoadDynamic.d.ts","names":[],"sources":["../../../src/client/useLoadDynamic.ts"],"mappings":";cA2Ba,iBAAkB,GAAC,aAAa,SAAW,QAAQ,OAAK"}
1
+ {"version":3,"file":"useLoadDynamic.d.ts","names":[],"sources":["../../../src/client/useLoadDynamic.ts"],"mappings":";cAqCa,iBAAkB,GAAC,aAAa,SAAW,QAAQ,OAAK;;;;;;;;;;;;;;;;;;;;cA2BxD,iBAAkB,GAAC,aACnB,cACG,QAAQ,OACrB"}
@@ -1,43 +1,18 @@
1
+ import { ServerContext } from "./serverContext.js";
1
2
  import { LocalesValues, ProviderVariant } from "@intlayer/types/module_augmentation";
2
3
  import { FC, PropsWithChildren } from "react";
3
4
  //#region src/server/IntlayerServerProvider.d.ts
4
5
  /**
5
6
  * Context that store the current locale on the server side
6
7
  */
7
- declare const IntlayerServerContext: FC<PropsWithChildren<{
8
- value?: LocalesValues;
9
- }>> & {
10
- Provider: FC<PropsWithChildren<{
11
- value?: LocalesValues;
12
- }>>;
13
- Consumer: FC<PropsWithChildren<{
14
- children: (context: LocalesValues) => import("react").ReactNode;
15
- }>>;
16
- _storage: () => {
17
- value: LocalesValues;
18
- };
19
- _defaultValue: LocalesValues;
20
- };
8
+ declare const IntlayerServerContext: ServerContext<LocalesValues>;
21
9
  /**
22
10
  * Context that stores the ambient variant on the server side.
23
11
  *
24
12
  * Kept separate from {@link IntlayerServerContext} so the locale context keeps
25
13
  * its plain `LocalesValues` shape for the packages already reading it.
26
14
  */
27
- declare const IntlayerServerVariantContext: FC<PropsWithChildren<{
28
- value?: ProviderVariant;
29
- }>> & {
30
- Provider: FC<PropsWithChildren<{
31
- value?: ProviderVariant;
32
- }>>;
33
- Consumer: FC<PropsWithChildren<{
34
- children: (context: ProviderVariant) => import("react").ReactNode;
35
- }>>;
36
- _storage: () => {
37
- value: ProviderVariant;
38
- };
39
- _defaultValue: ProviderVariant;
40
- };
15
+ declare const IntlayerServerVariantContext: ServerContext<ProviderVariant>;
41
16
  /**
42
17
  * Hook that provides the current locale
43
18
  */
@@ -46,6 +21,28 @@ declare const useIntlayer: () => LocalesValues;
46
21
  * Get the current locale
47
22
  */
48
23
  declare const locale: LocalesValues;
24
+ /**
25
+ * Seeds the request-scoped server context locale imperatively — the equivalent
26
+ * of mounting {@link IntlayerServerProvider} without wrapping the tree.
27
+ *
28
+ * Useful in pages that must stay statically rendered while no ambient
29
+ * request-derived locale source is static-safe (Next.js < 16):
30
+ *
31
+ * ```tsx
32
+ * const Page = async ({ params }) => {
33
+ * const { locale } = await params;
34
+ * setLocale(locale);
35
+ * return <PageContent />;
36
+ * };
37
+ * ```
38
+ */
39
+ declare const setLocale: (locale: LocalesValues) => void;
40
+ /**
41
+ * Seeds the request-scoped ambient variant imperatively — the equivalent of
42
+ * the `variant` prop of {@link IntlayerServerProvider} without wrapping the
43
+ * tree. See that prop for the accepted shapes.
44
+ */
45
+ declare const setVariant: (variant: ProviderVariant) => void;
49
46
  type IntlayerServerProviderProps = PropsWithChildren & {
50
47
  locale?: LocalesValues;
51
48
  /**
@@ -63,5 +60,5 @@ type IntlayerServerProviderProps = PropsWithChildren & {
63
60
  */
64
61
  declare const IntlayerServerProvider: FC<IntlayerServerProviderProps>;
65
62
  //#endregion
66
- export { IntlayerServerContext, IntlayerServerProvider, IntlayerServerProviderProps, IntlayerServerVariantContext, locale, useIntlayer };
63
+ export { IntlayerServerContext, IntlayerServerProvider, IntlayerServerProviderProps, IntlayerServerVariantContext, locale, setLocale, setVariant, useIntlayer };
67
64
  //# sourceMappingURL=IntlayerServerProvider.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"IntlayerServerProvider.d.ts","names":[],"sources":["../../../src/server/IntlayerServerProvider.tsx"],"mappings":";;;;;;cAca,uBAAqB,GAAA;;;;;;;;;;;;;;;;;;;;cASrB,8BAA4B,GAAA;;;;;;;;;;;;;;;;;cAM5B,mBAAW;;;;cAKX,QAAM;KAEP,8BAA8B;EACxC,SAAS;;;;;;;;;EAST,UAAU;;;;;cAMC,wBAAwB,GAAG"}
1
+ {"version":3,"file":"IntlayerServerProvider.d.ts","names":[],"sources":["../../../src/server/IntlayerServerProvider.tsx"],"mappings":";;;;;;;cAca,uBAAqB,cAAA;;;;;;;cASrB,8BAA4B,cAAA;;;;cAM5B,mBAAW;;;;cAKX,QAAM;;;;;;;;;;;;;;;;cAiBN,YAAS,QAAY;;;;;;cASrB,aAAU,SAAa;KAIxB,8BAA8B;EACxC,SAAS;;;;;;;;;EAST,UAAU;;;;;cAMC,wBAAwB,GAAG"}
@@ -1,4 +1,5 @@
1
- import { IntlayerServerContext, IntlayerServerProvider, IntlayerServerProviderProps, locale } from "./IntlayerServerProvider.js";
1
+ import { ServerContext, getServerContext } from "./serverContext.js";
2
+ import { IntlayerServerContext, IntlayerServerProvider, IntlayerServerProviderProps, IntlayerServerVariantContext, locale, setLocale, setVariant } from "./IntlayerServerProvider.js";
2
3
  import { useIntl } from "./format/useIntl.js";
3
4
  import { t } from "./t.js";
4
5
  import { useDictionary } from "./useDictionary.js";
@@ -8,4 +9,4 @@ import { useI18n } from "./useI18n.js";
8
9
  import { useIntlayer } from "./useIntlayer.js";
9
10
  import { useLoadDynamic } from "./useLoadDynamic.js";
10
11
  import { useLocale } from "./useLocale.js";
11
- export { IntlayerServerContext as IntlayerServer, IntlayerServerProvider, type IntlayerServerProviderProps, locale, t, useDictionary, useDictionaryAsync, useDictionaryDynamic, useI18n, useIntl, useIntlayer, useLoadDynamic, useLocale };
12
+ export { IntlayerServerContext as IntlayerServer, IntlayerServerProvider, type IntlayerServerProviderProps, IntlayerServerVariantContext, type ServerContext, getServerContext, locale, setLocale, setVariant, t, useDictionary, useDictionaryAsync, useDictionaryDynamic, useI18n, useIntl, useIntlayer, useLoadDynamic, useLocale };
@@ -24,5 +24,5 @@ type ServerContext<T> = FC<PropsWithChildren<{
24
24
  _defaultValue: T | undefined;
25
25
  };
26
26
  //#endregion
27
- export { createServerContext, getServerContext };
27
+ export { ServerContext, createServerContext, getServerContext };
28
28
  //# sourceMappingURL=serverContext.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"serverContext.d.ts","names":[],"sources":["../../../src/server/serverContext.tsx"],"mappings":";;cAiBa,sBAAuB,GAAC,eAAkB,MAAI,cAAc;;;;;;;;cAqC5D,mBAAoB,KAAC,UAAA,iBAG/B,cAAc,OAAE;KAOd,cAAc,KAAK,GAAG;EAAoB,QAAQ;;EACrD,UAAU,GAAG;IAAoB,QAAQ;;EACzC,UAAU,GACR;IAAoB,WAAW,SAAS,kBAAkB;;EAE5D;IAAkB,OAAO;;EACzB,eAAe"}
1
+ {"version":3,"file":"serverContext.d.ts","names":[],"sources":["../../../src/server/serverContext.tsx"],"mappings":";;cAiBa,sBAAuB,GAAC,eAAkB,MAAI,cAAc;;;;;;;;cAqC5D,mBAAoB,KAAC,UAAA,iBAG/B,cAAc,OAAE;KAOP,cAAc,KAAK,GAAG;EAAoB,QAAQ;;EAC5D,UAAU,GAAG;IAAoB,QAAQ;;EACzC,UAAU,GACR;IAAoB,WAAW,SAAS,kBAAkB;;EAE5D;IAAkB,OAAO;;EACzB,eAAe"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-intlayer",
3
- "version": "9.3.2",
3
+ "version": "9.4.0-canary.0",
4
4
  "private": false,
5
5
  "description": "Easily internationalize i18n your React applications with type-safe multilingual content management.",
6
6
  "keywords": [
@@ -132,12 +132,12 @@
132
132
  "typecheck": "tsc --noEmit --project tsconfig.types.json"
133
133
  },
134
134
  "dependencies": {
135
- "@intlayer/api": "9.3.2",
136
- "@intlayer/config": "9.3.2",
137
- "@intlayer/core": "9.3.2",
138
- "@intlayer/dictionaries-entry": "9.3.2",
139
- "@intlayer/editor": "9.3.2",
140
- "@intlayer/types": "9.3.2"
135
+ "@intlayer/api": "9.4.0-canary.0",
136
+ "@intlayer/config": "9.4.0-canary.0",
137
+ "@intlayer/core": "9.4.0-canary.0",
138
+ "@intlayer/dictionaries-entry": "9.4.0-canary.0",
139
+ "@intlayer/editor": "9.4.0-canary.0",
140
+ "@intlayer/types": "9.4.0-canary.0"
141
141
  },
142
142
  "devDependencies": {
143
143
  "@craco/types": "7.1.0",
@@ -151,14 +151,14 @@
151
151
  "rimraf": "6.1.3",
152
152
  "tsdown": "0.22.14",
153
153
  "typescript": "7.0.2",
154
- "vitest": "4.1.10"
154
+ "vitest": "4.1.11"
155
155
  },
156
156
  "peerDependencies": {
157
157
  "react": ">=16.0.0",
158
158
  "react-dom": ">=16.0.0"
159
159
  },
160
160
  "optionalDependencies": {
161
- "@intlayer/analytics": "9.3.2"
161
+ "@intlayer/analytics": "9.4.0-canary.0"
162
162
  },
163
163
  "engines": {
164
164
  "node": ">=14.18"