elysia-intlayer 9.5.11 → 9.5.12

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.
@@ -19,6 +19,7 @@ const intlayerStorage = new node_async_hooks.AsyncLocalStorage();
19
19
  * Returns the context of the request currently being handled, if any.
20
20
  */
21
21
  const getRequestContext = () => intlayerStorage.getStore()?.current;
22
+ (0, _intlayer_core_interpreter.registerAmbientLocaleResolver)(() => getRequestContext()?.locale);
22
23
  let debug = () => {};
23
24
  /**
24
25
  * Builds the translation function bound to a resolved request locale.
@@ -70,8 +71,8 @@ const releaseContext = () => {
70
71
  const intlayer = () => {
71
72
  const configuration = (0, _intlayer_config_node.getConfiguration)();
72
73
  const { internationalization } = configuration;
73
- if (process.env["NODE_ENV"] === "development") debug = (message) => console.debug(message);
74
- (0, _intlayer_engine_build.prepareIntlayer)(configuration);
74
+ if (process.env.NODE_ENV === "development") debug = (message) => console.debug(message);
75
+ (0, _intlayer_engine_build.prepareIntlayerServer)(configuration, { label: "elysia-intlayer" });
75
76
  return new elysia.Elysia({ name: "elysia-intlayer" }).derive({ as: "global" }, ({ request, cookie }) => {
76
77
  /**
77
78
  * Retrieves the locale from storage (cookies, headers).
@@ -1 +1 @@
1
- {"version":3,"file":"index.cjs","names":["AsyncLocalStorage","getTranslation","getConfiguration","Elysia","getLocaleFromStorageServer","localeDetector","getIntlayerFunction","getDictionaryFunction"],"sources":["../../src/index.ts"],"sourcesContent":["import { AsyncLocalStorage } from 'node:async_hooks';\nimport { getConfiguration } from '@intlayer/config/node';\nimport {\n getDictionary as getDictionaryFunction,\n getIntlayer as getIntlayerFunction,\n getTranslation,\n} from '@intlayer/core/interpreter';\nimport { localeDetector } from '@intlayer/core/localization';\nimport { getLocaleFromStorageServer } from '@intlayer/core/utils';\nimport { prepareIntlayer } from '@intlayer/engine/build';\nimport type { Locale } from '@intlayer/types/allLocales';\nimport type { StrictModeLocaleMap } from '@intlayer/types/module_augmentation';\nimport { Elysia } from 'elysia';\n\n/**\n * Translates a locale map into the content matching the current request locale.\n */\nexport type TranslateFunction = <Content extends string>(\n content: StrictModeLocaleMap<Content> | string,\n locale?: Locale\n) => Content;\n\n/**\n * Intlayer state injected into every Elysia route context by the `intlayer` plugin.\n */\nexport type IntlayerContext = {\n /** Locale explicitly requested by the client through a cookie or a header. */\n locale_storage?: Locale;\n /** Locale negotiated from the request headers (`Accept-Language`). */\n locale_detected: Locale;\n /** Locale to use for this request, `locale_storage` taking precedence. */\n locale: Locale;\n /** Locale configured as fallback in `intlayer.config.ts`. */\n defaultLocale: Locale;\n /** Translates an inline locale map. */\n t: TranslateFunction;\n /** Reads a dictionary by key, defaulting to the request locale. */\n getIntlayer: typeof getIntlayerFunction;\n /** Reads an imported dictionary, defaulting to the request locale. */\n getDictionary: typeof getDictionaryFunction;\n};\n\n/**\n * Mutable holder for the context of the request being handled.\n *\n * The context is held behind a reference because `AsyncLocalStorage.enterWith(undefined)`\n * is a no-op in Bun: clearing the reference is the only reliable way to release it.\n */\ntype IntlayerContextRef = { current?: IntlayerContext };\n\n/**\n * Per-request storage backing the standalone `t`, `getIntlayer` and `getDictionary` exports.\n *\n * `cls-hooked` (used by the Node-based Intlayer plugins) relies on `async_hooks.createHook`,\n * which Bun does not implement. `AsyncLocalStorage` is supported by both runtimes.\n */\nconst intlayerStorage = new AsyncLocalStorage<IntlayerContextRef>();\n\n/**\n * Returns the context of the request currently being handled, if any.\n */\nconst getRequestContext = (): IntlayerContext | undefined =>\n intlayerStorage.getStore()?.current;\n\n// Zero-cost fallback, will be updated with console logger in dev mode\nlet debug: (message: string) => void = () => {};\n\n/**\n * Builds the translation function bound to a resolved request locale.\n */\nconst createTranslateFunction =\n (locale: Locale, defaultLocale: Locale): TranslateFunction =>\n <Content extends string>(\n content: StrictModeLocaleMap<Content> | string,\n localeArg?: Locale\n ): Content => {\n const targetLocale = localeArg ?? locale;\n\n if (typeof content === 'undefined') {\n return '' as unknown as Content;\n }\n\n if (typeof content === 'string') {\n return content as unknown as Content;\n }\n\n if (\n typeof content?.[\n targetLocale as unknown as keyof StrictModeLocaleMap<Content>\n ] === 'undefined'\n ) {\n if (\n typeof content?.[\n defaultLocale as unknown as keyof StrictModeLocaleMap<Content>\n ] === 'undefined'\n ) {\n return content as unknown as Content;\n }\n\n return getTranslation(content, defaultLocale);\n }\n\n return getTranslation(content, targetLocale);\n };\n\n/**\n * Releases the request context once the response is mapped, so the standalone helpers\n * never resolve against an already terminated request.\n *\n * Returns `undefined` so Elysia keeps running the remaining `mapResponse` handlers.\n */\nconst releaseContext = (): undefined => {\n const contextRef = intlayerStorage.getStore();\n\n if (contextRef) {\n contextRef.current = undefined;\n }\n\n return undefined;\n};\n\n/**\n * Elysia plugin that integrates Intlayer into your Elysia application.\n *\n * It handles:\n * 1. Locale detection from storage (cookies, headers) then from `Accept-Language`.\n * 2. Decorating the route context with an `intlayer` object exposing `t`, `getIntlayer` and `getDictionary`.\n * 3. Exposing the same helpers to the standalone `t`, `getIntlayer` and `getDictionary` exports\n * for the duration of the request, through `AsyncLocalStorage`.\n *\n * @example\n * ```ts\n * import { Elysia } from 'elysia';\n * import { intlayer } from 'elysia-intlayer';\n *\n * const app = new Elysia()\n * .use(intlayer())\n * .get('/', ({ intlayer }) =>\n * intlayer.t({\n * en: 'Hello',\n * fr: 'Bonjour',\n * })\n * );\n * ```\n */\nexport const intlayer = () => {\n const configuration = getConfiguration();\n const { internationalization } = configuration;\n\n if (process.env['NODE_ENV'] === 'development') {\n debug = (message: string) => console.debug(message);\n }\n\n prepareIntlayer(configuration);\n\n return new Elysia({ name: 'elysia-intlayer' })\n .derive({ as: 'global' }, ({ request, cookie }) => {\n /**\n * Retrieves the locale from storage (cookies, headers).\n */\n const localeFromStorage = getLocaleFromStorageServer({\n getCookie: (name: string) =>\n cookie?.[name]?.value as string | undefined,\n getHeader: (name: string) => request.headers.get(name) ?? undefined,\n });\n\n const negotiatorHeaders: Record<string, string> = {};\n request.headers.forEach((value, key) => {\n negotiatorHeaders[key] = value;\n });\n\n const localeDetected = localeDetector(\n negotiatorHeaders,\n internationalization.locales,\n internationalization.defaultLocale\n );\n\n const locale = localeFromStorage ?? localeDetected;\n const defaultLocale = internationalization.defaultLocale;\n\n const getIntlayer: typeof getIntlayerFunction = (\n key: Parameters<typeof getIntlayerFunction>[0],\n localeArg = locale as Parameters<typeof getIntlayerFunction>[1],\n ...props: any[]\n ) => getIntlayerFunction(key, localeArg, ...props);\n\n const getDictionary: typeof getDictionaryFunction = (\n key: Parameters<typeof getDictionaryFunction>[0],\n localeArg = locale as Parameters<typeof getDictionaryFunction>[1],\n ...props: any[]\n ) => getDictionaryFunction(key, localeArg, ...props);\n\n const context: IntlayerContext = {\n locale_storage: localeFromStorage,\n locale_detected: localeDetected,\n locale,\n defaultLocale,\n t: createTranslateFunction(locale, defaultLocale),\n getIntlayer,\n getDictionary,\n };\n\n // Elysia awaits every lifecycle hook of a request on the same async chain,\n // so entering the store here keeps it available to the route handler.\n intlayerStorage.enterWith({ current: context });\n\n return { intlayer: context };\n })\n .mapResponse({ as: 'global' }, releaseContext)\n .onError({ as: 'global' }, releaseContext);\n};\n\n/**\n * Translation function that retrieves content for the locale of the current request.\n *\n * Falls back to the configured default locale when called outside of a request\n * handled by the `intlayer` plugin.\n *\n * @example\n * ```ts\n * import { t } from 'elysia-intlayer';\n *\n * app.get('/', () => t({ en: 'Hello', fr: 'Bonjour' }));\n * ```\n */\nexport const t = <Content extends string>(\n content: StrictModeLocaleMap<Content> | string,\n locale?: Locale\n): Content => {\n const context = getRequestContext();\n\n if (context) {\n return context.t(content, locale);\n }\n\n debug(\n 'Intlayer context not found. Add `.use(intlayer())` to your Elysia app, or use `context.intlayer.t` instead.'\n );\n\n const { internationalization } = getConfiguration();\n\n return getTranslation(\n content as StrictModeLocaleMap<Content>,\n locale ?? internationalization.defaultLocale\n );\n};\n\n/**\n * Retrieves a dictionary by key, using the locale of the current request by default.\n */\nexport const getIntlayer: typeof getIntlayerFunction = (\n ...args: Parameters<typeof getIntlayerFunction>\n) => {\n const context = getRequestContext();\n\n if (context) {\n return context.getIntlayer(...args);\n }\n\n debug(\n 'Intlayer context not found. Add `.use(intlayer())` to your Elysia app, or use `context.intlayer.getIntlayer` instead.'\n );\n\n return getIntlayerFunction(...args);\n};\n\n/**\n * Retrieves an imported dictionary, using the locale of the current request by default.\n */\nexport const getDictionary: typeof getDictionaryFunction = (\n ...args: Parameters<typeof getDictionaryFunction>\n) => {\n const context = getRequestContext();\n\n if (context) {\n return context.getDictionary(...args);\n }\n\n debug(\n 'Intlayer context not found. Add `.use(intlayer())` to your Elysia app, or use `context.intlayer.getDictionary` instead.'\n );\n\n return getDictionaryFunction(...args);\n};\n"],"mappings":";;;;;;;;;;;;;;;;AAwDA,MAAM,kBAAkB,IAAIA,mCAAsC;;;;AAKlE,MAAM,0BACJ,gBAAgB,SAAS,CAAC,EAAE;AAG9B,IAAI,cAAyC,CAAC;;;;AAK9C,MAAM,2BACH,QAAgB,mBAEf,SACA,cACY;CACZ,MAAM,eAAe,aAAa;CAElC,IAAI,OAAO,YAAY,aACrB,OAAO;CAGT,IAAI,OAAO,YAAY,UACrB,OAAO;CAGT,IACE,OAAO,UACL,kBACI,aACN;EACA,IACE,OAAO,UACL,mBACI,aAEN,OAAO;EAGT,WAAOC,2CAAe,SAAS,aAAa;CAC9C;CAEA,WAAOA,2CAAe,SAAS,YAAY;AAC7C;;;;;;;AAQF,MAAM,uBAAkC;CACtC,MAAM,aAAa,gBAAgB,SAAS;CAE5C,IAAI,YACF,WAAW,UAAU;AAIzB;;;;;;;;;;;;;;;;;;;;;;;;;AA0BA,MAAa,iBAAiB;CAC5B,MAAM,oBAAgBC,wCAAiB;CACvC,MAAM,EAAE,yBAAyB;CAEjC,IAAI,QAAQ,IAAI,gBAAgB,eAC9B,SAAS,YAAoB,QAAQ,MAAM,OAAO;CAGpD,4CAAgB,aAAa;CAE7B,OAAO,IAAIC,cAAO,EAAE,MAAM,kBAAkB,CAAC,CAAC,CAC3C,OAAO,EAAE,IAAI,SAAS,IAAI,EAAE,SAAS,aAAa;;;;EAIjD,MAAM,wBAAoBC,iDAA2B;GACnD,YAAY,SACV,SAAS,KAAK,EAAE;GAClB,YAAY,SAAiB,QAAQ,QAAQ,IAAI,IAAI,KAAK;EAC5D,CAAC;EAED,MAAM,oBAA4C,CAAC;EACnD,QAAQ,QAAQ,SAAS,OAAO,QAAQ;GACtC,kBAAkB,OAAO;EAC3B,CAAC;EAED,MAAM,qBAAiBC,4CACrB,mBACA,qBAAqB,SACrB,qBAAqB,aACvB;EAEA,MAAM,SAAS,qBAAqB;EACpC,MAAM,gBAAgB,qBAAqB;EAE3C,MAAM,eACJ,KACA,YAAY,QACZ,GAAG,cACAC,wCAAoB,KAAK,WAAW,GAAG,KAAK;EAEjD,MAAM,iBACJ,KACA,YAAY,QACZ,GAAG,cACAC,0CAAsB,KAAK,WAAW,GAAG,KAAK;EAEnD,MAAM,UAA2B;GAC/B,gBAAgB;GAChB,iBAAiB;GACjB;GACA;GACA,GAAG,wBAAwB,QAAQ,aAAa;GAChD;GACA;EACF;EAIA,gBAAgB,UAAU,EAAE,SAAS,QAAQ,CAAC;EAE9C,OAAO,EAAE,UAAU,QAAQ;CAC7B,CAAC,CAAC,CACD,YAAY,EAAE,IAAI,SAAS,GAAG,cAAc,CAAC,CAC7C,QAAQ,EAAE,IAAI,SAAS,GAAG,cAAc;AAC7C;;;;;;;;;;;;;;AAeA,MAAa,KACX,SACA,WACY;CACZ,MAAM,UAAU,kBAAkB;CAElC,IAAI,SACF,OAAO,QAAQ,EAAE,SAAS,MAAM;CAGlC,MACE,6GACF;CAEA,MAAM,EAAE,6BAAyBL,wCAAiB;CAElD,WAAOD,2CACL,SACA,UAAU,qBAAqB,aACjC;AACF;;;;AAKA,MAAa,eACX,GAAG,SACA;CACH,MAAM,UAAU,kBAAkB;CAElC,IAAI,SACF,OAAO,QAAQ,YAAY,GAAG,IAAI;CAGpC,MACE,uHACF;CAEA,WAAOK,wCAAoB,GAAG,IAAI;AACpC;;;;AAKA,MAAa,iBACX,GAAG,SACA;CACH,MAAM,UAAU,kBAAkB;CAElC,IAAI,SACF,OAAO,QAAQ,cAAc,GAAG,IAAI;CAGtC,MACE,yHACF;CAEA,WAAOC,0CAAsB,GAAG,IAAI;AACtC"}
1
+ {"version":3,"file":"index.cjs","names":["AsyncLocalStorage","registerAmbientLocaleResolver","getTranslation","getConfiguration","Elysia","getLocaleFromStorageServer","localeDetector","getIntlayerFunction","getDictionaryFunction"],"sources":["../../src/index.ts"],"sourcesContent":["import { AsyncLocalStorage } from 'node:async_hooks';\nimport { getConfiguration } from '@intlayer/config/node';\nimport {\n getDictionary as getDictionaryFunction,\n getIntlayer as getIntlayerFunction,\n getTranslation,\n registerAmbientLocaleResolver,\n} from '@intlayer/core/interpreter';\nimport { localeDetector } from '@intlayer/core/localization';\nimport { getLocaleFromStorageServer } from '@intlayer/core/utils';\nimport { prepareIntlayerServer } from '@intlayer/engine/build';\nimport type { Locale } from '@intlayer/types/allLocales';\nimport type { StrictModeLocaleMap } from '@intlayer/types/module_augmentation';\nimport { Elysia } from 'elysia';\n\n/**\n * Translates a locale map into the content matching the current request locale.\n */\nexport type TranslateFunction = <Content extends string>(\n content: StrictModeLocaleMap<Content> | string,\n locale?: Locale\n) => Content;\n\n/**\n * Intlayer state injected into every Elysia route context by the `intlayer` plugin.\n */\nexport type IntlayerContext = {\n /** Locale explicitly requested by the client through a cookie or a header. */\n locale_storage?: Locale;\n /** Locale negotiated from the request headers (`Accept-Language`). */\n locale_detected: Locale;\n /** Locale to use for this request, `locale_storage` taking precedence. */\n locale: Locale;\n /** Locale configured as fallback in `intlayer.config.ts`. */\n defaultLocale: Locale;\n /** Translates an inline locale map. */\n t: TranslateFunction;\n /** Reads a dictionary by key, defaulting to the request locale. */\n getIntlayer: typeof getIntlayerFunction;\n /** Reads an imported dictionary, defaulting to the request locale. */\n getDictionary: typeof getDictionaryFunction;\n};\n\n/**\n * Mutable holder for the context of the request being handled.\n *\n * The context is held behind a reference because `AsyncLocalStorage.enterWith(undefined)`\n * is a no-op in Bun: clearing the reference is the only reliable way to release it.\n */\ntype IntlayerContextRef = { current?: IntlayerContext };\n\n/**\n * Per-request storage backing the standalone `t`, `getIntlayer` and `getDictionary` exports.\n *\n * `cls-hooked` (used by the Node-based Intlayer plugins) relies on `async_hooks.createHook`,\n * which Bun does not implement. `AsyncLocalStorage` is supported by both runtimes.\n */\nconst intlayerStorage = new AsyncLocalStorage<IntlayerContextRef>();\n\n/**\n * Returns the context of the request currently being handled, if any.\n */\nconst getRequestContext = (): IntlayerContext | undefined =>\n intlayerStorage.getStore()?.current;\n\n// Lets a bare `getIntlayer` / `getDictionary` from any Intlayer package resolve\n// to the locale of the request being handled.\nregisterAmbientLocaleResolver(() => getRequestContext()?.locale);\n\n// Zero-cost fallback, will be updated with console logger in dev mode\nlet debug: (message: string) => void = () => {};\n\n/**\n * Builds the translation function bound to a resolved request locale.\n */\nconst createTranslateFunction =\n (locale: Locale, defaultLocale: Locale): TranslateFunction =>\n <Content extends string>(\n content: StrictModeLocaleMap<Content> | string,\n localeArg?: Locale\n ): Content => {\n const targetLocale = localeArg ?? locale;\n\n if (typeof content === 'undefined') {\n return '' as unknown as Content;\n }\n\n if (typeof content === 'string') {\n return content as unknown as Content;\n }\n\n if (\n typeof content?.[\n targetLocale as unknown as keyof StrictModeLocaleMap<Content>\n ] === 'undefined'\n ) {\n if (\n typeof content?.[\n defaultLocale as unknown as keyof StrictModeLocaleMap<Content>\n ] === 'undefined'\n ) {\n return content as unknown as Content;\n }\n\n return getTranslation(content, defaultLocale);\n }\n\n return getTranslation(content, targetLocale);\n };\n\n/**\n * Releases the request context once the response is mapped, so the standalone helpers\n * never resolve against an already terminated request.\n *\n * Returns `undefined` so Elysia keeps running the remaining `mapResponse` handlers.\n */\nconst releaseContext = (): undefined => {\n const contextRef = intlayerStorage.getStore();\n\n if (contextRef) {\n contextRef.current = undefined;\n }\n\n return undefined;\n};\n\n/**\n * Elysia plugin that integrates Intlayer into your Elysia application.\n *\n * It handles:\n * 1. Locale detection from storage (cookies, headers) then from `Accept-Language`.\n * 2. Decorating the route context with an `intlayer` object exposing `t`, `getIntlayer` and `getDictionary`.\n * 3. Exposing the same helpers to the standalone `t`, `getIntlayer` and `getDictionary` exports\n * for the duration of the request, through `AsyncLocalStorage`.\n *\n * @example\n * ```ts\n * import { Elysia } from 'elysia';\n * import { intlayer } from 'elysia-intlayer';\n *\n * const app = new Elysia()\n * .use(intlayer())\n * .get('/', ({ intlayer }) =>\n * intlayer.t({\n * en: 'Hello',\n * fr: 'Bonjour',\n * })\n * );\n * ```\n */\nexport const intlayer = () => {\n const configuration = getConfiguration();\n const { internationalization } = configuration;\n\n if (process.env['NODE_ENV'] === 'development') {\n debug = (message: string) => console.debug(message);\n }\n\n prepareIntlayerServer(configuration, { label: 'elysia-intlayer' });\n\n return new Elysia({ name: 'elysia-intlayer' })\n .derive({ as: 'global' }, ({ request, cookie }) => {\n /**\n * Retrieves the locale from storage (cookies, headers).\n */\n const localeFromStorage = getLocaleFromStorageServer({\n getCookie: (name: string) =>\n cookie?.[name]?.value as string | undefined,\n getHeader: (name: string) => request.headers.get(name) ?? undefined,\n });\n\n const negotiatorHeaders: Record<string, string> = {};\n request.headers.forEach((value, key) => {\n negotiatorHeaders[key] = value;\n });\n\n const localeDetected = localeDetector(\n negotiatorHeaders,\n internationalization.locales,\n internationalization.defaultLocale\n );\n\n const locale = localeFromStorage ?? localeDetected;\n const defaultLocale = internationalization.defaultLocale;\n\n const getIntlayer: typeof getIntlayerFunction = (\n key: Parameters<typeof getIntlayerFunction>[0],\n localeArg = locale as Parameters<typeof getIntlayerFunction>[1],\n ...props: any[]\n ) => getIntlayerFunction(key, localeArg, ...props);\n\n const getDictionary: typeof getDictionaryFunction = (\n key: Parameters<typeof getDictionaryFunction>[0],\n localeArg = locale as Parameters<typeof getDictionaryFunction>[1],\n ...props: any[]\n ) => getDictionaryFunction(key, localeArg, ...props);\n\n const context: IntlayerContext = {\n locale_storage: localeFromStorage,\n locale_detected: localeDetected,\n locale,\n defaultLocale,\n t: createTranslateFunction(locale, defaultLocale),\n getIntlayer,\n getDictionary,\n };\n\n // Elysia awaits every lifecycle hook of a request on the same async chain,\n // so entering the store here keeps it available to the route handler.\n intlayerStorage.enterWith({ current: context });\n\n return { intlayer: context };\n })\n .mapResponse({ as: 'global' }, releaseContext)\n .onError({ as: 'global' }, releaseContext);\n};\n\n/**\n * Translation function that retrieves content for the locale of the current request.\n *\n * Falls back to the configured default locale when called outside of a request\n * handled by the `intlayer` plugin.\n *\n * @example\n * ```ts\n * import { t } from 'elysia-intlayer';\n *\n * app.get('/', () => t({ en: 'Hello', fr: 'Bonjour' }));\n * ```\n */\nexport const t = <Content extends string>(\n content: StrictModeLocaleMap<Content> | string,\n locale?: Locale\n): Content => {\n const context = getRequestContext();\n\n if (context) {\n return context.t(content, locale);\n }\n\n debug(\n 'Intlayer context not found. Add `.use(intlayer())` to your Elysia app, or use `context.intlayer.t` instead.'\n );\n\n const { internationalization } = getConfiguration();\n\n return getTranslation(\n content as StrictModeLocaleMap<Content>,\n locale ?? internationalization.defaultLocale\n );\n};\n\n/**\n * Retrieves a dictionary by key, using the locale of the current request by default.\n */\nexport const getIntlayer: typeof getIntlayerFunction = (\n ...args: Parameters<typeof getIntlayerFunction>\n) => {\n const context = getRequestContext();\n\n if (context) {\n return context.getIntlayer(...args);\n }\n\n debug(\n 'Intlayer context not found. Add `.use(intlayer())` to your Elysia app, or use `context.intlayer.getIntlayer` instead.'\n );\n\n return getIntlayerFunction(...args);\n};\n\n/**\n * Retrieves an imported dictionary, using the locale of the current request by default.\n */\nexport const getDictionary: typeof getDictionaryFunction = (\n ...args: Parameters<typeof getDictionaryFunction>\n) => {\n const context = getRequestContext();\n\n if (context) {\n return context.getDictionary(...args);\n }\n\n debug(\n 'Intlayer context not found. Add `.use(intlayer())` to your Elysia app, or use `context.intlayer.getDictionary` instead.'\n );\n\n return getDictionaryFunction(...args);\n};\n"],"mappings":";;;;;;;;;;;;;;;;AAyDA,MAAM,kBAAkB,IAAIA,mCAAsC;;;;AAKlE,MAAM,0BACJ,gBAAgB,SAAS,CAAC,EAAE;IAI9BC,gEAAoC,kBAAkB,CAAC,EAAE,MAAM;AAG/D,IAAI,cAAyC,CAAC;;;;AAK9C,MAAM,2BACH,QAAgB,mBAEf,SACA,cACY;CACZ,MAAM,eAAe,aAAa;CAElC,IAAI,OAAO,YAAY,aACrB,OAAO;CAGT,IAAI,OAAO,YAAY,UACrB,OAAO;CAGT,IACE,OAAO,UACL,kBACI,aACN;EACA,IACE,OAAO,UACL,mBACI,aAEN,OAAO;EAGT,WAAOC,2CAAe,SAAS,aAAa;CAC9C;CAEA,WAAOA,2CAAe,SAAS,YAAY;AAC7C;;;;;;;AAQF,MAAM,uBAAkC;CACtC,MAAM,aAAa,gBAAgB,SAAS;CAE5C,IAAI,YACF,WAAW,UAAU;AAIzB;;;;;;;;;;;;;;;;;;;;;;;;;AA0BA,MAAa,iBAAiB;CAC5B,MAAM,oBAAgBC,wCAAiB;CACvC,MAAM,EAAE,yBAAyB;CAEjC,6BAAgC,eAC9B,SAAS,YAAoB,QAAQ,MAAM,OAAO;CAGpD,kDAAsB,eAAe,EAAE,OAAO,kBAAkB,CAAC;CAEjE,OAAO,IAAIC,cAAO,EAAE,MAAM,kBAAkB,CAAC,CAAC,CAC3C,OAAO,EAAE,IAAI,SAAS,IAAI,EAAE,SAAS,aAAa;;;;EAIjD,MAAM,wBAAoBC,iDAA2B;GACnD,YAAY,SACV,SAAS,KAAK,EAAE;GAClB,YAAY,SAAiB,QAAQ,QAAQ,IAAI,IAAI,KAAK;EAC5D,CAAC;EAED,MAAM,oBAA4C,CAAC;EACnD,QAAQ,QAAQ,SAAS,OAAO,QAAQ;GACtC,kBAAkB,OAAO;EAC3B,CAAC;EAED,MAAM,qBAAiBC,4CACrB,mBACA,qBAAqB,SACrB,qBAAqB,aACvB;EAEA,MAAM,SAAS,qBAAqB;EACpC,MAAM,gBAAgB,qBAAqB;EAE3C,MAAM,eACJ,KACA,YAAY,QACZ,GAAG,cACAC,wCAAoB,KAAK,WAAW,GAAG,KAAK;EAEjD,MAAM,iBACJ,KACA,YAAY,QACZ,GAAG,cACAC,0CAAsB,KAAK,WAAW,GAAG,KAAK;EAEnD,MAAM,UAA2B;GAC/B,gBAAgB;GAChB,iBAAiB;GACjB;GACA;GACA,GAAG,wBAAwB,QAAQ,aAAa;GAChD;GACA;EACF;EAIA,gBAAgB,UAAU,EAAE,SAAS,QAAQ,CAAC;EAE9C,OAAO,EAAE,UAAU,QAAQ;CAC7B,CAAC,CAAC,CACD,YAAY,EAAE,IAAI,SAAS,GAAG,cAAc,CAAC,CAC7C,QAAQ,EAAE,IAAI,SAAS,GAAG,cAAc;AAC7C;;;;;;;;;;;;;;AAeA,MAAa,KACX,SACA,WACY;CACZ,MAAM,UAAU,kBAAkB;CAElC,IAAI,SACF,OAAO,QAAQ,EAAE,SAAS,MAAM;CAGlC,MACE,6GACF;CAEA,MAAM,EAAE,6BAAyBL,wCAAiB;CAElD,WAAOD,2CACL,SACA,UAAU,qBAAqB,aACjC;AACF;;;;AAKA,MAAa,eACX,GAAG,SACA;CACH,MAAM,UAAU,kBAAkB;CAElC,IAAI,SACF,OAAO,QAAQ,YAAY,GAAG,IAAI;CAGpC,MACE,uHACF;CAEA,WAAOK,wCAAoB,GAAG,IAAI;AACpC;;;;AAKA,MAAa,iBACX,GAAG,SACA;CACH,MAAM,UAAU,kBAAkB;CAElC,IAAI,SACF,OAAO,QAAQ,cAAc,GAAG,IAAI;CAGtC,MACE,yHACF;CAEA,WAAOC,0CAAsB,GAAG,IAAI;AACtC"}
@@ -1,9 +1,9 @@
1
1
  import { AsyncLocalStorage } from "node:async_hooks";
2
2
  import { getConfiguration } from "@intlayer/config/node";
3
- import { getDictionary as getDictionary$1, getIntlayer as getIntlayer$1, getTranslation } from "@intlayer/core/interpreter";
3
+ import { getDictionary as getDictionary$1, getIntlayer as getIntlayer$1, getTranslation, registerAmbientLocaleResolver } from "@intlayer/core/interpreter";
4
4
  import { localeDetector } from "@intlayer/core/localization";
5
5
  import { getLocaleFromStorageServer } from "@intlayer/core/utils";
6
- import { prepareIntlayer } from "@intlayer/engine/build";
6
+ import { prepareIntlayerServer } from "@intlayer/engine/build";
7
7
  import { Elysia } from "elysia";
8
8
 
9
9
  //#region src/index.ts
@@ -18,6 +18,7 @@ const intlayerStorage = new AsyncLocalStorage();
18
18
  * Returns the context of the request currently being handled, if any.
19
19
  */
20
20
  const getRequestContext = () => intlayerStorage.getStore()?.current;
21
+ registerAmbientLocaleResolver(() => getRequestContext()?.locale);
21
22
  let debug = () => {};
22
23
  /**
23
24
  * Builds the translation function bound to a resolved request locale.
@@ -69,8 +70,8 @@ const releaseContext = () => {
69
70
  const intlayer = () => {
70
71
  const configuration = getConfiguration();
71
72
  const { internationalization } = configuration;
72
- debug = (message) => console.debug(message);
73
- prepareIntlayer(configuration);
73
+ if (process.env.NODE_ENV === "development") debug = (message) => console.debug(message);
74
+ prepareIntlayerServer(configuration, { label: "elysia-intlayer" });
74
75
  return new Elysia({ name: "elysia-intlayer" }).derive({ as: "global" }, ({ request, cookie }) => {
75
76
  /**
76
77
  * Retrieves the locale from storage (cookies, headers).
@@ -1 +1 @@
1
- {"version":3,"file":"index.mjs","names":["getIntlayerFunction","getDictionaryFunction"],"sources":["../../src/index.ts"],"sourcesContent":["import { AsyncLocalStorage } from 'node:async_hooks';\nimport { getConfiguration } from '@intlayer/config/node';\nimport {\n getDictionary as getDictionaryFunction,\n getIntlayer as getIntlayerFunction,\n getTranslation,\n} from '@intlayer/core/interpreter';\nimport { localeDetector } from '@intlayer/core/localization';\nimport { getLocaleFromStorageServer } from '@intlayer/core/utils';\nimport { prepareIntlayer } from '@intlayer/engine/build';\nimport type { Locale } from '@intlayer/types/allLocales';\nimport type { StrictModeLocaleMap } from '@intlayer/types/module_augmentation';\nimport { Elysia } from 'elysia';\n\n/**\n * Translates a locale map into the content matching the current request locale.\n */\nexport type TranslateFunction = <Content extends string>(\n content: StrictModeLocaleMap<Content> | string,\n locale?: Locale\n) => Content;\n\n/**\n * Intlayer state injected into every Elysia route context by the `intlayer` plugin.\n */\nexport type IntlayerContext = {\n /** Locale explicitly requested by the client through a cookie or a header. */\n locale_storage?: Locale;\n /** Locale negotiated from the request headers (`Accept-Language`). */\n locale_detected: Locale;\n /** Locale to use for this request, `locale_storage` taking precedence. */\n locale: Locale;\n /** Locale configured as fallback in `intlayer.config.ts`. */\n defaultLocale: Locale;\n /** Translates an inline locale map. */\n t: TranslateFunction;\n /** Reads a dictionary by key, defaulting to the request locale. */\n getIntlayer: typeof getIntlayerFunction;\n /** Reads an imported dictionary, defaulting to the request locale. */\n getDictionary: typeof getDictionaryFunction;\n};\n\n/**\n * Mutable holder for the context of the request being handled.\n *\n * The context is held behind a reference because `AsyncLocalStorage.enterWith(undefined)`\n * is a no-op in Bun: clearing the reference is the only reliable way to release it.\n */\ntype IntlayerContextRef = { current?: IntlayerContext };\n\n/**\n * Per-request storage backing the standalone `t`, `getIntlayer` and `getDictionary` exports.\n *\n * `cls-hooked` (used by the Node-based Intlayer plugins) relies on `async_hooks.createHook`,\n * which Bun does not implement. `AsyncLocalStorage` is supported by both runtimes.\n */\nconst intlayerStorage = new AsyncLocalStorage<IntlayerContextRef>();\n\n/**\n * Returns the context of the request currently being handled, if any.\n */\nconst getRequestContext = (): IntlayerContext | undefined =>\n intlayerStorage.getStore()?.current;\n\n// Zero-cost fallback, will be updated with console logger in dev mode\nlet debug: (message: string) => void = () => {};\n\n/**\n * Builds the translation function bound to a resolved request locale.\n */\nconst createTranslateFunction =\n (locale: Locale, defaultLocale: Locale): TranslateFunction =>\n <Content extends string>(\n content: StrictModeLocaleMap<Content> | string,\n localeArg?: Locale\n ): Content => {\n const targetLocale = localeArg ?? locale;\n\n if (typeof content === 'undefined') {\n return '' as unknown as Content;\n }\n\n if (typeof content === 'string') {\n return content as unknown as Content;\n }\n\n if (\n typeof content?.[\n targetLocale as unknown as keyof StrictModeLocaleMap<Content>\n ] === 'undefined'\n ) {\n if (\n typeof content?.[\n defaultLocale as unknown as keyof StrictModeLocaleMap<Content>\n ] === 'undefined'\n ) {\n return content as unknown as Content;\n }\n\n return getTranslation(content, defaultLocale);\n }\n\n return getTranslation(content, targetLocale);\n };\n\n/**\n * Releases the request context once the response is mapped, so the standalone helpers\n * never resolve against an already terminated request.\n *\n * Returns `undefined` so Elysia keeps running the remaining `mapResponse` handlers.\n */\nconst releaseContext = (): undefined => {\n const contextRef = intlayerStorage.getStore();\n\n if (contextRef) {\n contextRef.current = undefined;\n }\n\n return undefined;\n};\n\n/**\n * Elysia plugin that integrates Intlayer into your Elysia application.\n *\n * It handles:\n * 1. Locale detection from storage (cookies, headers) then from `Accept-Language`.\n * 2. Decorating the route context with an `intlayer` object exposing `t`, `getIntlayer` and `getDictionary`.\n * 3. Exposing the same helpers to the standalone `t`, `getIntlayer` and `getDictionary` exports\n * for the duration of the request, through `AsyncLocalStorage`.\n *\n * @example\n * ```ts\n * import { Elysia } from 'elysia';\n * import { intlayer } from 'elysia-intlayer';\n *\n * const app = new Elysia()\n * .use(intlayer())\n * .get('/', ({ intlayer }) =>\n * intlayer.t({\n * en: 'Hello',\n * fr: 'Bonjour',\n * })\n * );\n * ```\n */\nexport const intlayer = () => {\n const configuration = getConfiguration();\n const { internationalization } = configuration;\n\n if (process.env['NODE_ENV'] === 'development') {\n debug = (message: string) => console.debug(message);\n }\n\n prepareIntlayer(configuration);\n\n return new Elysia({ name: 'elysia-intlayer' })\n .derive({ as: 'global' }, ({ request, cookie }) => {\n /**\n * Retrieves the locale from storage (cookies, headers).\n */\n const localeFromStorage = getLocaleFromStorageServer({\n getCookie: (name: string) =>\n cookie?.[name]?.value as string | undefined,\n getHeader: (name: string) => request.headers.get(name) ?? undefined,\n });\n\n const negotiatorHeaders: Record<string, string> = {};\n request.headers.forEach((value, key) => {\n negotiatorHeaders[key] = value;\n });\n\n const localeDetected = localeDetector(\n negotiatorHeaders,\n internationalization.locales,\n internationalization.defaultLocale\n );\n\n const locale = localeFromStorage ?? localeDetected;\n const defaultLocale = internationalization.defaultLocale;\n\n const getIntlayer: typeof getIntlayerFunction = (\n key: Parameters<typeof getIntlayerFunction>[0],\n localeArg = locale as Parameters<typeof getIntlayerFunction>[1],\n ...props: any[]\n ) => getIntlayerFunction(key, localeArg, ...props);\n\n const getDictionary: typeof getDictionaryFunction = (\n key: Parameters<typeof getDictionaryFunction>[0],\n localeArg = locale as Parameters<typeof getDictionaryFunction>[1],\n ...props: any[]\n ) => getDictionaryFunction(key, localeArg, ...props);\n\n const context: IntlayerContext = {\n locale_storage: localeFromStorage,\n locale_detected: localeDetected,\n locale,\n defaultLocale,\n t: createTranslateFunction(locale, defaultLocale),\n getIntlayer,\n getDictionary,\n };\n\n // Elysia awaits every lifecycle hook of a request on the same async chain,\n // so entering the store here keeps it available to the route handler.\n intlayerStorage.enterWith({ current: context });\n\n return { intlayer: context };\n })\n .mapResponse({ as: 'global' }, releaseContext)\n .onError({ as: 'global' }, releaseContext);\n};\n\n/**\n * Translation function that retrieves content for the locale of the current request.\n *\n * Falls back to the configured default locale when called outside of a request\n * handled by the `intlayer` plugin.\n *\n * @example\n * ```ts\n * import { t } from 'elysia-intlayer';\n *\n * app.get('/', () => t({ en: 'Hello', fr: 'Bonjour' }));\n * ```\n */\nexport const t = <Content extends string>(\n content: StrictModeLocaleMap<Content> | string,\n locale?: Locale\n): Content => {\n const context = getRequestContext();\n\n if (context) {\n return context.t(content, locale);\n }\n\n debug(\n 'Intlayer context not found. Add `.use(intlayer())` to your Elysia app, or use `context.intlayer.t` instead.'\n );\n\n const { internationalization } = getConfiguration();\n\n return getTranslation(\n content as StrictModeLocaleMap<Content>,\n locale ?? internationalization.defaultLocale\n );\n};\n\n/**\n * Retrieves a dictionary by key, using the locale of the current request by default.\n */\nexport const getIntlayer: typeof getIntlayerFunction = (\n ...args: Parameters<typeof getIntlayerFunction>\n) => {\n const context = getRequestContext();\n\n if (context) {\n return context.getIntlayer(...args);\n }\n\n debug(\n 'Intlayer context not found. Add `.use(intlayer())` to your Elysia app, or use `context.intlayer.getIntlayer` instead.'\n );\n\n return getIntlayerFunction(...args);\n};\n\n/**\n * Retrieves an imported dictionary, using the locale of the current request by default.\n */\nexport const getDictionary: typeof getDictionaryFunction = (\n ...args: Parameters<typeof getDictionaryFunction>\n) => {\n const context = getRequestContext();\n\n if (context) {\n return context.getDictionary(...args);\n }\n\n debug(\n 'Intlayer context not found. Add `.use(intlayer())` to your Elysia app, or use `context.intlayer.getDictionary` instead.'\n );\n\n return getDictionaryFunction(...args);\n};\n"],"mappings":";;;;;;;;;;;;;;;AAwDA,MAAM,kBAAkB,IAAI,kBAAsC;;;;AAKlE,MAAM,0BACJ,gBAAgB,SAAS,CAAC,EAAE;AAG9B,IAAI,cAAyC,CAAC;;;;AAK9C,MAAM,2BACH,QAAgB,mBAEf,SACA,cACY;CACZ,MAAM,eAAe,aAAa;CAElC,IAAI,OAAO,YAAY,aACrB,OAAO;CAGT,IAAI,OAAO,YAAY,UACrB,OAAO;CAGT,IACE,OAAO,UACL,kBACI,aACN;EACA,IACE,OAAO,UACL,mBACI,aAEN,OAAO;EAGT,OAAO,eAAe,SAAS,aAAa;CAC9C;CAEA,OAAO,eAAe,SAAS,YAAY;AAC7C;;;;;;;AAQF,MAAM,uBAAkC;CACtC,MAAM,aAAa,gBAAgB,SAAS;CAE5C,IAAI,YACF,WAAW,UAAU;AAIzB;;;;;;;;;;;;;;;;;;;;;;;;;AA0BA,MAAa,iBAAiB;CAC5B,MAAM,gBAAgB,iBAAiB;CACvC,MAAM,EAAE,yBAAyB;CAG/B,SAAS,YAAoB,QAAQ,MAAM,OAAO;CAGpD,gBAAgB,aAAa;CAE7B,OAAO,IAAI,OAAO,EAAE,MAAM,kBAAkB,CAAC,CAAC,CAC3C,OAAO,EAAE,IAAI,SAAS,IAAI,EAAE,SAAS,aAAa;;;;EAIjD,MAAM,oBAAoB,2BAA2B;GACnD,YAAY,SACV,SAAS,KAAK,EAAE;GAClB,YAAY,SAAiB,QAAQ,QAAQ,IAAI,IAAI,KAAK;EAC5D,CAAC;EAED,MAAM,oBAA4C,CAAC;EACnD,QAAQ,QAAQ,SAAS,OAAO,QAAQ;GACtC,kBAAkB,OAAO;EAC3B,CAAC;EAED,MAAM,iBAAiB,eACrB,mBACA,qBAAqB,SACrB,qBAAqB,aACvB;EAEA,MAAM,SAAS,qBAAqB;EACpC,MAAM,gBAAgB,qBAAqB;EAE3C,MAAM,eACJ,KACA,YAAY,QACZ,GAAG,UACAA,cAAoB,KAAK,WAAW,GAAG,KAAK;EAEjD,MAAM,iBACJ,KACA,YAAY,QACZ,GAAG,UACAC,gBAAsB,KAAK,WAAW,GAAG,KAAK;EAEnD,MAAM,UAA2B;GAC/B,gBAAgB;GAChB,iBAAiB;GACjB;GACA;GACA,GAAG,wBAAwB,QAAQ,aAAa;GAChD;GACA;EACF;EAIA,gBAAgB,UAAU,EAAE,SAAS,QAAQ,CAAC;EAE9C,OAAO,EAAE,UAAU,QAAQ;CAC7B,CAAC,CAAC,CACD,YAAY,EAAE,IAAI,SAAS,GAAG,cAAc,CAAC,CAC7C,QAAQ,EAAE,IAAI,SAAS,GAAG,cAAc;AAC7C;;;;;;;;;;;;;;AAeA,MAAa,KACX,SACA,WACY;CACZ,MAAM,UAAU,kBAAkB;CAElC,IAAI,SACF,OAAO,QAAQ,EAAE,SAAS,MAAM;CAGlC,MACE,6GACF;CAEA,MAAM,EAAE,yBAAyB,iBAAiB;CAElD,OAAO,eACL,SACA,UAAU,qBAAqB,aACjC;AACF;;;;AAKA,MAAa,eACX,GAAG,SACA;CACH,MAAM,UAAU,kBAAkB;CAElC,IAAI,SACF,OAAO,QAAQ,YAAY,GAAG,IAAI;CAGpC,MACE,uHACF;CAEA,OAAOD,cAAoB,GAAG,IAAI;AACpC;;;;AAKA,MAAa,iBACX,GAAG,SACA;CACH,MAAM,UAAU,kBAAkB;CAElC,IAAI,SACF,OAAO,QAAQ,cAAc,GAAG,IAAI;CAGtC,MACE,yHACF;CAEA,OAAOC,gBAAsB,GAAG,IAAI;AACtC"}
1
+ {"version":3,"file":"index.mjs","names":["getIntlayerFunction","getDictionaryFunction"],"sources":["../../src/index.ts"],"sourcesContent":["import { AsyncLocalStorage } from 'node:async_hooks';\nimport { getConfiguration } from '@intlayer/config/node';\nimport {\n getDictionary as getDictionaryFunction,\n getIntlayer as getIntlayerFunction,\n getTranslation,\n registerAmbientLocaleResolver,\n} from '@intlayer/core/interpreter';\nimport { localeDetector } from '@intlayer/core/localization';\nimport { getLocaleFromStorageServer } from '@intlayer/core/utils';\nimport { prepareIntlayerServer } from '@intlayer/engine/build';\nimport type { Locale } from '@intlayer/types/allLocales';\nimport type { StrictModeLocaleMap } from '@intlayer/types/module_augmentation';\nimport { Elysia } from 'elysia';\n\n/**\n * Translates a locale map into the content matching the current request locale.\n */\nexport type TranslateFunction = <Content extends string>(\n content: StrictModeLocaleMap<Content> | string,\n locale?: Locale\n) => Content;\n\n/**\n * Intlayer state injected into every Elysia route context by the `intlayer` plugin.\n */\nexport type IntlayerContext = {\n /** Locale explicitly requested by the client through a cookie or a header. */\n locale_storage?: Locale;\n /** Locale negotiated from the request headers (`Accept-Language`). */\n locale_detected: Locale;\n /** Locale to use for this request, `locale_storage` taking precedence. */\n locale: Locale;\n /** Locale configured as fallback in `intlayer.config.ts`. */\n defaultLocale: Locale;\n /** Translates an inline locale map. */\n t: TranslateFunction;\n /** Reads a dictionary by key, defaulting to the request locale. */\n getIntlayer: typeof getIntlayerFunction;\n /** Reads an imported dictionary, defaulting to the request locale. */\n getDictionary: typeof getDictionaryFunction;\n};\n\n/**\n * Mutable holder for the context of the request being handled.\n *\n * The context is held behind a reference because `AsyncLocalStorage.enterWith(undefined)`\n * is a no-op in Bun: clearing the reference is the only reliable way to release it.\n */\ntype IntlayerContextRef = { current?: IntlayerContext };\n\n/**\n * Per-request storage backing the standalone `t`, `getIntlayer` and `getDictionary` exports.\n *\n * `cls-hooked` (used by the Node-based Intlayer plugins) relies on `async_hooks.createHook`,\n * which Bun does not implement. `AsyncLocalStorage` is supported by both runtimes.\n */\nconst intlayerStorage = new AsyncLocalStorage<IntlayerContextRef>();\n\n/**\n * Returns the context of the request currently being handled, if any.\n */\nconst getRequestContext = (): IntlayerContext | undefined =>\n intlayerStorage.getStore()?.current;\n\n// Lets a bare `getIntlayer` / `getDictionary` from any Intlayer package resolve\n// to the locale of the request being handled.\nregisterAmbientLocaleResolver(() => getRequestContext()?.locale);\n\n// Zero-cost fallback, will be updated with console logger in dev mode\nlet debug: (message: string) => void = () => {};\n\n/**\n * Builds the translation function bound to a resolved request locale.\n */\nconst createTranslateFunction =\n (locale: Locale, defaultLocale: Locale): TranslateFunction =>\n <Content extends string>(\n content: StrictModeLocaleMap<Content> | string,\n localeArg?: Locale\n ): Content => {\n const targetLocale = localeArg ?? locale;\n\n if (typeof content === 'undefined') {\n return '' as unknown as Content;\n }\n\n if (typeof content === 'string') {\n return content as unknown as Content;\n }\n\n if (\n typeof content?.[\n targetLocale as unknown as keyof StrictModeLocaleMap<Content>\n ] === 'undefined'\n ) {\n if (\n typeof content?.[\n defaultLocale as unknown as keyof StrictModeLocaleMap<Content>\n ] === 'undefined'\n ) {\n return content as unknown as Content;\n }\n\n return getTranslation(content, defaultLocale);\n }\n\n return getTranslation(content, targetLocale);\n };\n\n/**\n * Releases the request context once the response is mapped, so the standalone helpers\n * never resolve against an already terminated request.\n *\n * Returns `undefined` so Elysia keeps running the remaining `mapResponse` handlers.\n */\nconst releaseContext = (): undefined => {\n const contextRef = intlayerStorage.getStore();\n\n if (contextRef) {\n contextRef.current = undefined;\n }\n\n return undefined;\n};\n\n/**\n * Elysia plugin that integrates Intlayer into your Elysia application.\n *\n * It handles:\n * 1. Locale detection from storage (cookies, headers) then from `Accept-Language`.\n * 2. Decorating the route context with an `intlayer` object exposing `t`, `getIntlayer` and `getDictionary`.\n * 3. Exposing the same helpers to the standalone `t`, `getIntlayer` and `getDictionary` exports\n * for the duration of the request, through `AsyncLocalStorage`.\n *\n * @example\n * ```ts\n * import { Elysia } from 'elysia';\n * import { intlayer } from 'elysia-intlayer';\n *\n * const app = new Elysia()\n * .use(intlayer())\n * .get('/', ({ intlayer }) =>\n * intlayer.t({\n * en: 'Hello',\n * fr: 'Bonjour',\n * })\n * );\n * ```\n */\nexport const intlayer = () => {\n const configuration = getConfiguration();\n const { internationalization } = configuration;\n\n if (process.env['NODE_ENV'] === 'development') {\n debug = (message: string) => console.debug(message);\n }\n\n prepareIntlayerServer(configuration, { label: 'elysia-intlayer' });\n\n return new Elysia({ name: 'elysia-intlayer' })\n .derive({ as: 'global' }, ({ request, cookie }) => {\n /**\n * Retrieves the locale from storage (cookies, headers).\n */\n const localeFromStorage = getLocaleFromStorageServer({\n getCookie: (name: string) =>\n cookie?.[name]?.value as string | undefined,\n getHeader: (name: string) => request.headers.get(name) ?? undefined,\n });\n\n const negotiatorHeaders: Record<string, string> = {};\n request.headers.forEach((value, key) => {\n negotiatorHeaders[key] = value;\n });\n\n const localeDetected = localeDetector(\n negotiatorHeaders,\n internationalization.locales,\n internationalization.defaultLocale\n );\n\n const locale = localeFromStorage ?? localeDetected;\n const defaultLocale = internationalization.defaultLocale;\n\n const getIntlayer: typeof getIntlayerFunction = (\n key: Parameters<typeof getIntlayerFunction>[0],\n localeArg = locale as Parameters<typeof getIntlayerFunction>[1],\n ...props: any[]\n ) => getIntlayerFunction(key, localeArg, ...props);\n\n const getDictionary: typeof getDictionaryFunction = (\n key: Parameters<typeof getDictionaryFunction>[0],\n localeArg = locale as Parameters<typeof getDictionaryFunction>[1],\n ...props: any[]\n ) => getDictionaryFunction(key, localeArg, ...props);\n\n const context: IntlayerContext = {\n locale_storage: localeFromStorage,\n locale_detected: localeDetected,\n locale,\n defaultLocale,\n t: createTranslateFunction(locale, defaultLocale),\n getIntlayer,\n getDictionary,\n };\n\n // Elysia awaits every lifecycle hook of a request on the same async chain,\n // so entering the store here keeps it available to the route handler.\n intlayerStorage.enterWith({ current: context });\n\n return { intlayer: context };\n })\n .mapResponse({ as: 'global' }, releaseContext)\n .onError({ as: 'global' }, releaseContext);\n};\n\n/**\n * Translation function that retrieves content for the locale of the current request.\n *\n * Falls back to the configured default locale when called outside of a request\n * handled by the `intlayer` plugin.\n *\n * @example\n * ```ts\n * import { t } from 'elysia-intlayer';\n *\n * app.get('/', () => t({ en: 'Hello', fr: 'Bonjour' }));\n * ```\n */\nexport const t = <Content extends string>(\n content: StrictModeLocaleMap<Content> | string,\n locale?: Locale\n): Content => {\n const context = getRequestContext();\n\n if (context) {\n return context.t(content, locale);\n }\n\n debug(\n 'Intlayer context not found. Add `.use(intlayer())` to your Elysia app, or use `context.intlayer.t` instead.'\n );\n\n const { internationalization } = getConfiguration();\n\n return getTranslation(\n content as StrictModeLocaleMap<Content>,\n locale ?? internationalization.defaultLocale\n );\n};\n\n/**\n * Retrieves a dictionary by key, using the locale of the current request by default.\n */\nexport const getIntlayer: typeof getIntlayerFunction = (\n ...args: Parameters<typeof getIntlayerFunction>\n) => {\n const context = getRequestContext();\n\n if (context) {\n return context.getIntlayer(...args);\n }\n\n debug(\n 'Intlayer context not found. Add `.use(intlayer())` to your Elysia app, or use `context.intlayer.getIntlayer` instead.'\n );\n\n return getIntlayerFunction(...args);\n};\n\n/**\n * Retrieves an imported dictionary, using the locale of the current request by default.\n */\nexport const getDictionary: typeof getDictionaryFunction = (\n ...args: Parameters<typeof getDictionaryFunction>\n) => {\n const context = getRequestContext();\n\n if (context) {\n return context.getDictionary(...args);\n }\n\n debug(\n 'Intlayer context not found. Add `.use(intlayer())` to your Elysia app, or use `context.intlayer.getDictionary` instead.'\n );\n\n return getDictionaryFunction(...args);\n};\n"],"mappings":";;;;;;;;;;;;;;;AAyDA,MAAM,kBAAkB,IAAI,kBAAsC;;;;AAKlE,MAAM,0BACJ,gBAAgB,SAAS,CAAC,EAAE;AAI9B,oCAAoC,kBAAkB,CAAC,EAAE,MAAM;AAG/D,IAAI,cAAyC,CAAC;;;;AAK9C,MAAM,2BACH,QAAgB,mBAEf,SACA,cACY;CACZ,MAAM,eAAe,aAAa;CAElC,IAAI,OAAO,YAAY,aACrB,OAAO;CAGT,IAAI,OAAO,YAAY,UACrB,OAAO;CAGT,IACE,OAAO,UACL,kBACI,aACN;EACA,IACE,OAAO,UACL,mBACI,aAEN,OAAO;EAGT,OAAO,eAAe,SAAS,aAAa;CAC9C;CAEA,OAAO,eAAe,SAAS,YAAY;AAC7C;;;;;;;AAQF,MAAM,uBAAkC;CACtC,MAAM,aAAa,gBAAgB,SAAS;CAE5C,IAAI,YACF,WAAW,UAAU;AAIzB;;;;;;;;;;;;;;;;;;;;;;;;;AA0BA,MAAa,iBAAiB;CAC5B,MAAM,gBAAgB,iBAAiB;CACvC,MAAM,EAAE,yBAAyB;CAEjC,6BAAgC,eAC9B,SAAS,YAAoB,QAAQ,MAAM,OAAO;CAGpD,sBAAsB,eAAe,EAAE,OAAO,kBAAkB,CAAC;CAEjE,OAAO,IAAI,OAAO,EAAE,MAAM,kBAAkB,CAAC,CAAC,CAC3C,OAAO,EAAE,IAAI,SAAS,IAAI,EAAE,SAAS,aAAa;;;;EAIjD,MAAM,oBAAoB,2BAA2B;GACnD,YAAY,SACV,SAAS,KAAK,EAAE;GAClB,YAAY,SAAiB,QAAQ,QAAQ,IAAI,IAAI,KAAK;EAC5D,CAAC;EAED,MAAM,oBAA4C,CAAC;EACnD,QAAQ,QAAQ,SAAS,OAAO,QAAQ;GACtC,kBAAkB,OAAO;EAC3B,CAAC;EAED,MAAM,iBAAiB,eACrB,mBACA,qBAAqB,SACrB,qBAAqB,aACvB;EAEA,MAAM,SAAS,qBAAqB;EACpC,MAAM,gBAAgB,qBAAqB;EAE3C,MAAM,eACJ,KACA,YAAY,QACZ,GAAG,UACAA,cAAoB,KAAK,WAAW,GAAG,KAAK;EAEjD,MAAM,iBACJ,KACA,YAAY,QACZ,GAAG,UACAC,gBAAsB,KAAK,WAAW,GAAG,KAAK;EAEnD,MAAM,UAA2B;GAC/B,gBAAgB;GAChB,iBAAiB;GACjB;GACA;GACA,GAAG,wBAAwB,QAAQ,aAAa;GAChD;GACA;EACF;EAIA,gBAAgB,UAAU,EAAE,SAAS,QAAQ,CAAC;EAE9C,OAAO,EAAE,UAAU,QAAQ;CAC7B,CAAC,CAAC,CACD,YAAY,EAAE,IAAI,SAAS,GAAG,cAAc,CAAC,CAC7C,QAAQ,EAAE,IAAI,SAAS,GAAG,cAAc;AAC7C;;;;;;;;;;;;;;AAeA,MAAa,KACX,SACA,WACY;CACZ,MAAM,UAAU,kBAAkB;CAElC,IAAI,SACF,OAAO,QAAQ,EAAE,SAAS,MAAM;CAGlC,MACE,6GACF;CAEA,MAAM,EAAE,yBAAyB,iBAAiB;CAElD,OAAO,eACL,SACA,UAAU,qBAAqB,aACjC;AACF;;;;AAKA,MAAa,eACX,GAAG,SACA;CACH,MAAM,UAAU,kBAAkB;CAElC,IAAI,SACF,OAAO,QAAQ,YAAY,GAAG,IAAI;CAGpC,MACE,uHACF;CAEA,OAAOD,cAAoB,GAAG,IAAI;AACpC;;;;AAKA,MAAa,iBACX,GAAG,SACA;CACH,MAAM,UAAU,kBAAkB;CAElC,IAAI,SACF,OAAO,QAAQ,cAAc,GAAG,IAAI;CAGtC,MACE,yHACF;CAEA,OAAOC,gBAAsB,GAAG,IAAI;AACtC"}
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","names":[],"sources":["../../src/index.ts"],"mappings":";;;;;;;;YAiBY,qBAAqB,wBAC/B,SAAS,oBAAoB,mBAC7B,SAAS,WACN;;;;YAKO;;EAEV,iBAAiB;;EAEjB,iBAAiB;;EAEjB,QAAQ;;EAER,eAAe;;EAEf,GAAG;;EAEH,oBAAoB;;EAEpB,sBAAsB;;;;;;;;;;;;;;;;;;;;;;;;;;qBA0GX,gBAAQ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;qBAgFR,IAAK,wBAAsB,SAC7B,oBAAoB,mBAAiB,SACrC,WACR;;;;qBAsBU,oBAAoB;;;;qBAmBpB,sBAAsB"}
1
+ {"version":3,"file":"index.d.ts","names":[],"sources":["../../src/index.ts"],"mappings":";;;;;;;;YAkBY,qBAAqB,wBAC/B,SAAS,oBAAoB,mBAC7B,SAAS,WACN;;;;YAKO;;EAEV,iBAAiB;;EAEjB,iBAAiB;;EAEjB,QAAQ;;EAER,eAAe;;EAEf,GAAG;;EAEH,oBAAoB;;EAEpB,sBAAsB;;;;;;;;;;;;;;;;;;;;;;;;;;qBA8GX,gBAAQ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;qBAgFR,IAAK,wBAAsB,SAC7B,oBAAoB,mBAAiB,SACrC,WACR;;;;qBAsBU,oBAAoB;;;;qBAmBpB,sBAAsB"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "elysia-intlayer",
3
- "version": "9.5.11",
3
+ "version": "9.5.12",
4
4
  "private": false,
5
5
  "description": "Manage internationalization i18n in a simple way for Elysia applications.",
6
6
  "keywords": [
@@ -76,10 +76,10 @@
76
76
  "typecheck": "tsc --noEmit --project tsconfig.types.json"
77
77
  },
78
78
  "dependencies": {
79
- "@intlayer/config": "9.5.11",
80
- "@intlayer/core": "9.5.11",
81
- "@intlayer/engine": "9.5.11",
82
- "@intlayer/types": "9.5.11"
79
+ "@intlayer/config": "9.5.12",
80
+ "@intlayer/core": "9.5.12",
81
+ "@intlayer/engine": "9.5.12",
82
+ "@intlayer/types": "9.5.12"
83
83
  },
84
84
  "devDependencies": {
85
85
  "@types/node": "^22",