@intlayer/react-intl 9.0.0-canary.8 → 9.0.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 (40) hide show
  1. package/dist/esm/createIntlObject.mjs +9 -14
  2. package/dist/esm/createIntlObject.mjs.map +1 -1
  3. package/dist/esm/dictionaryIntlShape.mjs +0 -0
  4. package/dist/esm/index.mjs +3 -1
  5. package/dist/esm/plugin/index.mjs +3 -36
  6. package/dist/esm/plugin/index.mjs.map +1 -1
  7. package/dist/esm/typedMessageIds.mjs +0 -0
  8. package/dist/esm/useDictionary.mjs +45 -0
  9. package/dist/esm/useDictionary.mjs.map +1 -0
  10. package/dist/esm/useDictionaryDynamic.mjs +27 -0
  11. package/dist/esm/useDictionaryDynamic.mjs.map +1 -0
  12. package/dist/types/FormattedComponents.d.ts +0 -1
  13. package/dist/types/FormattedComponents.d.ts.map +1 -1
  14. package/dist/types/FormattedMessage.d.ts +0 -1
  15. package/dist/types/FormattedMessage.d.ts.map +1 -1
  16. package/dist/types/IntlProvider.d.ts +0 -1
  17. package/dist/types/IntlProvider.d.ts.map +1 -1
  18. package/dist/types/context.d.ts +0 -1
  19. package/dist/types/context.d.ts.map +1 -1
  20. package/dist/types/createIntl.d.ts +0 -1
  21. package/dist/types/createIntl.d.ts.map +1 -1
  22. package/dist/types/createIntlObject.d.ts +5 -2
  23. package/dist/types/createIntlObject.d.ts.map +1 -1
  24. package/dist/types/defineMessages.d.ts +0 -1
  25. package/dist/types/defineMessages.d.ts.map +1 -1
  26. package/dist/types/dictionaryIntlShape.d.ts +53 -0
  27. package/dist/types/dictionaryIntlShape.d.ts.map +1 -0
  28. package/dist/types/errors.d.ts.map +1 -1
  29. package/dist/types/index.d.ts +5 -1
  30. package/dist/types/plugin/index.d.ts +0 -1
  31. package/dist/types/plugin/index.d.ts.map +1 -1
  32. package/dist/types/typedMessageIds.d.ts +25 -0
  33. package/dist/types/typedMessageIds.d.ts.map +1 -0
  34. package/dist/types/useDictionary.d.ts +30 -0
  35. package/dist/types/useDictionary.d.ts.map +1 -0
  36. package/dist/types/useDictionaryDynamic.d.ts +14 -0
  37. package/dist/types/useDictionaryDynamic.d.ts.map +1 -0
  38. package/dist/types/useIntl.d.ts +0 -1
  39. package/dist/types/useIntl.d.ts.map +1 -1
  40. package/package.json +14 -14
@@ -1,6 +1,6 @@
1
1
  import { Fragment } from "react";
2
2
  import { getIntlayer } from "@intlayer/core/interpreter";
3
- import { parseTaggedMessage, resolveMessage } from "@intlayer/core/messageFormat";
3
+ import { navigatePath, parseTaggedMessage, resolveMessage } from "@intlayer/core/messageFormat";
4
4
  import { Fragment as Fragment$1, jsx } from "react/jsx-runtime";
5
5
 
6
6
  //#region src/createIntlObject.tsx
@@ -16,16 +16,6 @@ const splitId = (id) => {
16
16
  path: id.slice(dotIndex + 1)
17
17
  };
18
18
  };
19
- const navigatePath = (object, path) => {
20
- if (!path) return object;
21
- const parts = path.split(".");
22
- let current = object;
23
- for (const part of parts) {
24
- if (current === null || current === void 0 || typeof current !== "object") return;
25
- current = current[part];
26
- }
27
- return current;
28
- };
29
19
  /** Looks up a message value by full dotted id; first segment = dictionary key. */
30
20
  const lookupMessage = (id, locale) => {
31
21
  const { dictionaryKey, path } = splitId(id);
@@ -62,16 +52,21 @@ const isRichValues = (values) => Object.values(values).some((value) => typeof va
62
52
  * - Translation ids use the first dot-path segment as the dictionary key.
63
53
  * - Full ICU MessageFormat syntax is supported via `@intlayer/core/messageFormat`.
64
54
  * - Rich text tags (`<b>chunks</b>`) are resolved through render functions in `values`.
55
+ *
56
+ * @param locale - The locale messages are resolved for.
57
+ * @param lookupOverride - Optional message lookup replacing the registry-based
58
+ * id resolution; used by the dictionary-bound `useDictionary` variant.
65
59
  */
66
- const createIntlObject = (locale) => {
60
+ const createIntlObject = (locale, lookupOverride) => {
67
61
  const localeString = locale;
68
62
  const formatMessage = (descriptor, values) => {
69
63
  const { id = "", defaultMessage } = descriptor;
70
- const rawValue = lookupMessage(id, locale);
64
+ const rawValue = lookupOverride ? lookupOverride(id) : lookupMessage(id, locale);
71
65
  const messageTemplate = rawValue !== void 0 && rawValue !== null ? rawValue : typeof defaultMessage === "string" ? defaultMessage : id;
72
66
  if (!values || !isRichValues(values)) return resolveMessage(messageTemplate, values ?? {}, locale, "icu") ?? id;
73
67
  const { scalarValues, renderers } = splitRichValues(values);
74
- return renderRichTokens(parseTaggedMessage(resolveMessage(messageTemplate, scalarValues, locale, "icu") ?? id), renderers);
68
+ const message = resolveMessage(messageTemplate, scalarValues, locale, "icu") ?? id;
69
+ return renderRichTokens(parseTaggedMessage(message), renderers);
75
70
  };
76
71
  const toDate = (value) => value instanceof Date ? value : new Date(value);
77
72
  const formatDate = (value, options) => {
@@ -1 +1 @@
1
- {"version":3,"file":"createIntlObject.mjs","names":[],"sources":["../../src/createIntlObject.tsx"],"sourcesContent":["import { getIntlayer } from '@intlayer/core/interpreter';\nimport {\n type MessageValues,\n parseTaggedMessage,\n resolveMessage,\n type TaggedMessageToken,\n} from '@intlayer/core/messageFormat';\nimport type {\n DictionaryKeys,\n LocalesValues,\n} from '@intlayer/types/module_augmentation';\nimport { Fragment, type ReactNode } from 'react';\nimport type { IntlShape, MessageDescriptor } from 'react-intl';\n\ntype RichRenderer = (chunks: ReactNode) => ReactNode;\n\n/** Splits a full dotted id into the dictionary key and remaining path. */\nconst splitId = (id: string): { dictionaryKey: string; path: string } => {\n const dotIndex = id.indexOf('.');\n if (dotIndex === -1) return { dictionaryKey: id, path: '' };\n return {\n dictionaryKey: id.slice(0, dotIndex),\n path: id.slice(dotIndex + 1),\n };\n};\n\nconst navigatePath = (object: unknown, path: string): unknown => {\n if (!path) return object;\n const parts = path.split('.');\n let current: unknown = object;\n for (const part of parts) {\n if (\n current === null ||\n current === undefined ||\n typeof current !== 'object'\n ) {\n return undefined;\n }\n current = (current as Record<string, unknown>)[part];\n }\n return current;\n};\n\n/** Looks up a message value by full dotted id; first segment = dictionary key. */\nconst lookupMessage = (id: string, locale: LocalesValues): unknown => {\n const { dictionaryKey, path } = splitId(id);\n if (!dictionaryKey) return undefined;\n try {\n const dictionary = getIntlayer(dictionaryKey as DictionaryKeys, locale);\n return navigatePath(dictionary, path);\n } catch {\n return undefined;\n }\n};\n\n/** Maps tagged tokens to React nodes using the provided renderer functions. */\nconst renderRichTokens = (\n tokens: TaggedMessageToken[],\n renderers: Record<string, unknown>\n): ReactNode[] =>\n tokens.map((token, tokenIndex) => {\n if (typeof token === 'string') return token;\n const children = renderRichTokens(token.children, renderers);\n const renderer = renderers[token.tag];\n if (typeof renderer === 'function') {\n return (\n <Fragment key={tokenIndex}>\n {(renderer as RichRenderer)(<>{children}</>)}\n </Fragment>\n );\n }\n return <Fragment key={tokenIndex}>{children}</Fragment>;\n });\n\n/** Partitions values into scalar interpolation params and tag renderers. */\nconst splitRichValues = (\n values: Record<string, unknown>\n): { scalarValues: MessageValues; renderers: Record<string, unknown> } => {\n const scalarValues: MessageValues = {};\n const renderers: Record<string, unknown> = {};\n for (const [key, value] of Object.entries(values)) {\n if (typeof value === 'function') renderers[key] = value;\n else scalarValues[key] = value as MessageValues[string];\n }\n return { scalarValues, renderers };\n};\n\nconst isRichValues = (values: Record<string, unknown>): boolean =>\n Object.values(values).some((value) => typeof value === 'function');\n\n/**\n * Builds an intlayer-backed `IntlShape` object for the given locale.\n *\n * - Translation ids use the first dot-path segment as the dictionary key.\n * - Full ICU MessageFormat syntax is supported via `@intlayer/core/messageFormat`.\n * - Rich text tags (`<b>chunks</b>`) are resolved through render functions in `values`.\n */\nexport const createIntlObject = (locale: LocalesValues): IntlShape => {\n const localeString = locale as string;\n\n const formatMessage = (\n descriptor: MessageDescriptor,\n values?: Record<string, unknown>\n ): string | ReactNode[] => {\n const { id = '', defaultMessage } = descriptor;\n const rawValue = lookupMessage(id, locale);\n const messageTemplate =\n rawValue !== undefined && rawValue !== null\n ? (rawValue as string)\n : typeof defaultMessage === 'string'\n ? defaultMessage\n : id;\n\n if (!values || !isRichValues(values)) {\n return (\n resolveMessage(\n messageTemplate,\n (values ?? {}) as MessageValues,\n locale,\n 'icu'\n ) ?? id\n );\n }\n\n const { scalarValues, renderers } = splitRichValues(values);\n const message =\n resolveMessage(messageTemplate, scalarValues, locale, 'icu') ?? id;\n return renderRichTokens(parseTaggedMessage(message), renderers);\n };\n\n const toDate = (value: Date | number | string): Date =>\n value instanceof Date ? value : new Date(value);\n\n const formatDate = (\n value: string | number | Date | undefined,\n options?: Intl.DateTimeFormatOptions\n ): string => {\n if (value === undefined || value === null) return '';\n return new Intl.DateTimeFormat(localeString, options).format(toDate(value));\n };\n\n const formatNumber = (\n value: number | bigint,\n options?: Intl.NumberFormatOptions\n ): string => new Intl.NumberFormat(localeString, options).format(value);\n\n const formatPlural = (\n value: number,\n options?: Intl.PluralRulesOptions\n ): Intl.LDMLPluralRule =>\n new Intl.PluralRules(localeString, options).select(value);\n\n const formatList = (\n list: Iterable<unknown> | readonly unknown[],\n options?: Intl.ListFormatOptions\n ): string => {\n const strings = Array.from(list).filter(\n (item): item is string => typeof item === 'string'\n );\n return new Intl.ListFormat(localeString, options).format(strings);\n };\n\n const formatListToParts = (\n list: Iterable<unknown> | readonly unknown[],\n options?: Intl.ListFormatOptions\n ): ReturnType<Intl.ListFormat['formatToParts']> => {\n const strings = Array.from(list).filter(\n (item): item is string => typeof item === 'string'\n );\n return new Intl.ListFormat(localeString, options).formatToParts(strings);\n };\n\n const formatDisplayName = (\n value: string,\n options?: Intl.DisplayNamesOptions\n ): string | undefined =>\n new Intl.DisplayNames([localeString], options ?? { type: 'language' }).of(\n value\n );\n\n const formatRelativeTime = (\n value: number,\n unit?: Intl.RelativeTimeFormatUnit,\n options?: Intl.RelativeTimeFormatOptions\n ): string =>\n new Intl.RelativeTimeFormat(localeString, {\n numeric: 'auto',\n ...options,\n }).format(value, unit ?? 'second');\n\n const formatDateTimeRange = (\n from: Date | number,\n to: Date | number,\n options?: Intl.DateTimeFormatOptions\n ): string =>\n new Intl.DateTimeFormat(localeString, options).formatRange(\n toDate(from),\n toDate(to)\n );\n\n const formatDateToParts = (\n value: Parameters<Intl.DateTimeFormat['format']>[0] | string,\n options?: Intl.DateTimeFormatOptions\n ): Intl.DateTimeFormatPart[] =>\n new Intl.DateTimeFormat(localeString, options).formatToParts(\n typeof value === 'string' ? new Date(value) : value\n );\n\n const formatNumberToParts = (\n value: number | bigint,\n options?: Intl.NumberFormatOptions\n ): Intl.NumberFormatPart[] =>\n new Intl.NumberFormat(localeString, options).formatToParts(value);\n\n /** Alias of `formatMessage` — provided for `@formatjs/intl` v4 compatibility. */\n const $t = formatMessage as IntlShape['$t'];\n\n return {\n locale: localeString,\n defaultLocale: localeString,\n messages: {},\n formats: {},\n defaultFormats: {},\n timeZone: undefined,\n textComponent: Fragment,\n wrapRichTextChunksInFragment: false,\n fallbackOnEmptyString: true,\n onError: () => {},\n onWarn: () => {},\n formatters: {} as IntlShape['formatters'],\n formatMessage: formatMessage as IntlShape['formatMessage'],\n $t,\n formatDate,\n formatTime: formatDate,\n formatNumber,\n formatPlural,\n formatList: formatList as IntlShape['formatList'],\n formatListToParts: formatListToParts as IntlShape['formatListToParts'],\n formatDisplayName: formatDisplayName as IntlShape['formatDisplayName'],\n formatRelativeTime,\n formatDateTimeRange,\n formatDateToParts: formatDateToParts as IntlShape['formatDateToParts'],\n formatTimeToParts: formatDateToParts as IntlShape['formatTimeToParts'],\n formatNumberToParts:\n formatNumberToParts as IntlShape['formatNumberToParts'],\n } as unknown as IntlShape;\n};\n"],"mappings":";;;;;;;AAiBA,MAAM,WAAW,OAAwD;CACvE,MAAM,WAAW,GAAG,QAAQ,GAAG;CAC/B,IAAI,aAAa,IAAI,OAAO;EAAE,eAAe;EAAI,MAAM;CAAG;CAC1D,OAAO;EACL,eAAe,GAAG,MAAM,GAAG,QAAQ;EACnC,MAAM,GAAG,MAAM,WAAW,CAAC;CAC7B;AACF;AAEA,MAAM,gBAAgB,QAAiB,SAA0B;CAC/D,IAAI,CAAC,MAAM,OAAO;CAClB,MAAM,QAAQ,KAAK,MAAM,GAAG;CAC5B,IAAI,UAAmB;CACvB,KAAK,MAAM,QAAQ,OAAO;EACxB,IACE,YAAY,QACZ,YAAY,UACZ,OAAO,YAAY,UAEnB;EAEF,UAAW,QAAoC;CACjD;CACA,OAAO;AACT;;AAGA,MAAM,iBAAiB,IAAY,WAAmC;CACpE,MAAM,EAAE,eAAe,SAAS,QAAQ,EAAE;CAC1C,IAAI,CAAC,eAAe,OAAO;CAC3B,IAAI;EAEF,OAAO,aADY,YAAY,eAAiC,MACnC,GAAG,IAAI;CACtC,QAAQ;EACN;CACF;AACF;;AAGA,MAAM,oBACJ,QACA,cAEA,OAAO,KAAK,OAAO,eAAe;CAChC,IAAI,OAAO,UAAU,UAAU,OAAO;CACtC,MAAM,WAAW,iBAAiB,MAAM,UAAU,SAAS;CAC3D,MAAM,WAAW,UAAU,MAAM;CACjC,IAAI,OAAO,aAAa,YACtB,OACE,oBAAC,UAAD,YACI,SAA0B,kCAAG,SAAW,EAAC,EACnC,GAFK,UAEL;CAGd,OAAO,oBAAC,UAAD,EAA4B,SAAmB,GAAhC,UAAgC;AACxD,CAAC;;AAGH,MAAM,mBACJ,WACwE;CACxE,MAAM,eAA8B,CAAC;CACrC,MAAM,YAAqC,CAAC;CAC5C,KAAK,MAAM,CAAC,KAAK,UAAU,OAAO,QAAQ,MAAM,GAC9C,IAAI,OAAO,UAAU,YAAY,UAAU,OAAO;MAC7C,aAAa,OAAO;CAE3B,OAAO;EAAE;EAAc;CAAU;AACnC;AAEA,MAAM,gBAAgB,WACpB,OAAO,OAAO,MAAM,CAAC,CAAC,MAAM,UAAU,OAAO,UAAU,UAAU;;;;;;;;AASnE,MAAa,oBAAoB,WAAqC;CACpE,MAAM,eAAe;CAErB,MAAM,iBACJ,YACA,WACyB;EACzB,MAAM,EAAE,KAAK,IAAI,mBAAmB;EACpC,MAAM,WAAW,cAAc,IAAI,MAAM;EACzC,MAAM,kBACJ,aAAa,UAAa,aAAa,OAClC,WACD,OAAO,mBAAmB,WACxB,iBACA;EAER,IAAI,CAAC,UAAU,CAAC,aAAa,MAAM,GACjC,OACE,eACE,iBACC,UAAU,CAAC,GACZ,QACA,KACF,KAAK;EAIT,MAAM,EAAE,cAAc,cAAc,gBAAgB,MAAM;EAG1D,OAAO,iBAAiB,mBADtB,eAAe,iBAAiB,cAAc,QAAQ,KAAK,KAAK,EAChB,GAAG,SAAS;CAChE;CAEA,MAAM,UAAU,UACd,iBAAiB,OAAO,QAAQ,IAAI,KAAK,KAAK;CAEhD,MAAM,cACJ,OACA,YACW;EACX,IAAI,UAAU,UAAa,UAAU,MAAM,OAAO;EAClD,OAAO,IAAI,KAAK,eAAe,cAAc,OAAO,CAAC,CAAC,OAAO,OAAO,KAAK,CAAC;CAC5E;CAEA,MAAM,gBACJ,OACA,YACW,IAAI,KAAK,aAAa,cAAc,OAAO,CAAC,CAAC,OAAO,KAAK;CAEtE,MAAM,gBACJ,OACA,YAEA,IAAI,KAAK,YAAY,cAAc,OAAO,CAAC,CAAC,OAAO,KAAK;CAE1D,MAAM,cACJ,MACA,YACW;EACX,MAAM,UAAU,MAAM,KAAK,IAAI,CAAC,CAAC,QAC9B,SAAyB,OAAO,SAAS,QAC5C;EACA,OAAO,IAAI,KAAK,WAAW,cAAc,OAAO,CAAC,CAAC,OAAO,OAAO;CAClE;CAEA,MAAM,qBACJ,MACA,YACiD;EACjD,MAAM,UAAU,MAAM,KAAK,IAAI,CAAC,CAAC,QAC9B,SAAyB,OAAO,SAAS,QAC5C;EACA,OAAO,IAAI,KAAK,WAAW,cAAc,OAAO,CAAC,CAAC,cAAc,OAAO;CACzE;CAEA,MAAM,qBACJ,OACA,YAEA,IAAI,KAAK,aAAa,CAAC,YAAY,GAAG,WAAW,EAAE,MAAM,WAAW,CAAC,CAAC,CAAC,GACrE,KACF;CAEF,MAAM,sBACJ,OACA,MACA,YAEA,IAAI,KAAK,mBAAmB,cAAc;EACxC,SAAS;EACT,GAAG;CACL,CAAC,CAAC,CAAC,OAAO,OAAO,QAAQ,QAAQ;CAEnC,MAAM,uBACJ,MACA,IACA,YAEA,IAAI,KAAK,eAAe,cAAc,OAAO,CAAC,CAAC,YAC7C,OAAO,IAAI,GACX,OAAO,EAAE,CACX;CAEF,MAAM,qBACJ,OACA,YAEA,IAAI,KAAK,eAAe,cAAc,OAAO,CAAC,CAAC,cAC7C,OAAO,UAAU,WAAW,IAAI,KAAK,KAAK,IAAI,KAChD;CAEF,MAAM,uBACJ,OACA,YAEA,IAAI,KAAK,aAAa,cAAc,OAAO,CAAC,CAAC,cAAc,KAAK;CAKlE,OAAO;EACL,QAAQ;EACR,eAAe;EACf,UAAU,CAAC;EACX,SAAS,CAAC;EACV,gBAAgB,CAAC;EACjB,UAAU;EACV,eAAe;EACf,8BAA8B;EAC9B,uBAAuB;EACvB,eAAe,CAAC;EAChB,cAAc,CAAC;EACf,YAAY,CAAC;EACE;EACf;EACA;EACA,YAAY;EACZ;EACA;EACY;EACO;EACA;EACnB;EACA;EACmB;EACnB,mBAAmB;EAEjB;CACJ;AACF"}
1
+ {"version":3,"file":"createIntlObject.mjs","names":[],"sources":["../../src/createIntlObject.tsx"],"sourcesContent":["import { getIntlayer } from '@intlayer/core/interpreter';\nimport {\n type MessageValues,\n navigatePath,\n parseTaggedMessage,\n resolveMessage,\n type TaggedMessageToken,\n} from '@intlayer/core/messageFormat';\nimport type {\n DictionaryKeys,\n LocalesValues,\n} from '@intlayer/types/module_augmentation';\nimport { Fragment, type ReactNode } from 'react';\nimport type { IntlShape, MessageDescriptor } from 'react-intl';\n\ntype RichRenderer = (chunks: ReactNode) => ReactNode;\n\n/** Splits a full dotted id into the dictionary key and remaining path. */\nconst splitId = (id: string): { dictionaryKey: string; path: string } => {\n const dotIndex = id.indexOf('.');\n if (dotIndex === -1) return { dictionaryKey: id, path: '' };\n return {\n dictionaryKey: id.slice(0, dotIndex),\n path: id.slice(dotIndex + 1),\n };\n};\n\n/** Looks up a message value by full dotted id; first segment = dictionary key. */\nconst lookupMessage = (id: string, locale: LocalesValues): unknown => {\n const { dictionaryKey, path } = splitId(id);\n if (!dictionaryKey) return undefined;\n try {\n const dictionary = getIntlayer(dictionaryKey as DictionaryKeys, locale);\n return navigatePath(dictionary, path);\n } catch {\n return undefined;\n }\n};\n\n/** Maps tagged tokens to React nodes using the provided renderer functions. */\nconst renderRichTokens = (\n tokens: TaggedMessageToken[],\n renderers: Record<string, unknown>\n): ReactNode[] =>\n tokens.map((token, tokenIndex) => {\n if (typeof token === 'string') return token;\n const children = renderRichTokens(token.children, renderers);\n const renderer = renderers[token.tag];\n if (typeof renderer === 'function') {\n return (\n <Fragment key={tokenIndex}>\n {(renderer as RichRenderer)(<>{children}</>)}\n </Fragment>\n );\n }\n return <Fragment key={tokenIndex}>{children}</Fragment>;\n });\n\n/** Partitions values into scalar interpolation params and tag renderers. */\nconst splitRichValues = (\n values: Record<string, unknown>\n): { scalarValues: MessageValues; renderers: Record<string, unknown> } => {\n const scalarValues: MessageValues = {};\n const renderers: Record<string, unknown> = {};\n for (const [key, value] of Object.entries(values)) {\n if (typeof value === 'function') renderers[key] = value;\n else scalarValues[key] = value as MessageValues[string];\n }\n return { scalarValues, renderers };\n};\n\nconst isRichValues = (values: Record<string, unknown>): boolean =>\n Object.values(values).some((value) => typeof value === 'function');\n\n/**\n * Builds an intlayer-backed `IntlShape` object for the given locale.\n *\n * - Translation ids use the first dot-path segment as the dictionary key.\n * - Full ICU MessageFormat syntax is supported via `@intlayer/core/messageFormat`.\n * - Rich text tags (`<b>chunks</b>`) are resolved through render functions in `values`.\n *\n * @param locale - The locale messages are resolved for.\n * @param lookupOverride - Optional message lookup replacing the registry-based\n * id resolution; used by the dictionary-bound `useDictionary` variant.\n */\nexport const createIntlObject = (\n locale: LocalesValues,\n lookupOverride?: (id: string) => unknown\n): IntlShape => {\n const localeString = locale as string;\n\n const formatMessage = (\n descriptor: MessageDescriptor,\n values?: Record<string, unknown>\n ): string | ReactNode[] => {\n const { id = '', defaultMessage } = descriptor;\n const rawValue = lookupOverride\n ? lookupOverride(id)\n : lookupMessage(id, locale);\n const messageTemplate =\n rawValue !== undefined && rawValue !== null\n ? (rawValue as string)\n : typeof defaultMessage === 'string'\n ? defaultMessage\n : id;\n\n if (!values || !isRichValues(values)) {\n return (\n resolveMessage(\n messageTemplate,\n (values ?? {}) as MessageValues,\n locale,\n 'icu'\n ) ?? id\n );\n }\n\n const { scalarValues, renderers } = splitRichValues(values);\n const message =\n resolveMessage(messageTemplate, scalarValues, locale, 'icu') ?? id;\n return renderRichTokens(parseTaggedMessage(message), renderers);\n };\n\n const toDate = (value: Date | number | string): Date =>\n value instanceof Date ? value : new Date(value);\n\n const formatDate = (\n value: string | number | Date | undefined,\n options?: Intl.DateTimeFormatOptions\n ): string => {\n if (value === undefined || value === null) return '';\n return new Intl.DateTimeFormat(localeString, options).format(toDate(value));\n };\n\n const formatNumber = (\n value: number | bigint,\n options?: Intl.NumberFormatOptions\n ): string => new Intl.NumberFormat(localeString, options).format(value);\n\n const formatPlural = (\n value: number,\n options?: Intl.PluralRulesOptions\n ): Intl.LDMLPluralRule =>\n new Intl.PluralRules(localeString, options).select(value);\n\n const formatList = (\n list: Iterable<unknown> | readonly unknown[],\n options?: Intl.ListFormatOptions\n ): string => {\n const strings = Array.from(list).filter(\n (item): item is string => typeof item === 'string'\n );\n return new Intl.ListFormat(localeString, options).format(strings);\n };\n\n const formatListToParts = (\n list: Iterable<unknown> | readonly unknown[],\n options?: Intl.ListFormatOptions\n ): ReturnType<Intl.ListFormat['formatToParts']> => {\n const strings = Array.from(list).filter(\n (item): item is string => typeof item === 'string'\n );\n return new Intl.ListFormat(localeString, options).formatToParts(strings);\n };\n\n const formatDisplayName = (\n value: string,\n options?: Intl.DisplayNamesOptions\n ): string | undefined =>\n new Intl.DisplayNames([localeString], options ?? { type: 'language' }).of(\n value\n );\n\n const formatRelativeTime = (\n value: number,\n unit?: Intl.RelativeTimeFormatUnit,\n options?: Intl.RelativeTimeFormatOptions\n ): string =>\n new Intl.RelativeTimeFormat(localeString, {\n numeric: 'auto',\n ...options,\n }).format(value, unit ?? 'second');\n\n const formatDateTimeRange = (\n from: Date | number,\n to: Date | number,\n options?: Intl.DateTimeFormatOptions\n ): string =>\n new Intl.DateTimeFormat(localeString, options).formatRange(\n toDate(from),\n toDate(to)\n );\n\n const formatDateToParts = (\n value: Parameters<Intl.DateTimeFormat['format']>[0] | string,\n options?: Intl.DateTimeFormatOptions\n ): Intl.DateTimeFormatPart[] =>\n new Intl.DateTimeFormat(localeString, options).formatToParts(\n typeof value === 'string' ? new Date(value) : value\n );\n\n const formatNumberToParts = (\n value: number | bigint,\n options?: Intl.NumberFormatOptions\n ): Intl.NumberFormatPart[] =>\n new Intl.NumberFormat(localeString, options).formatToParts(value);\n\n /** Alias of `formatMessage` — provided for `@formatjs/intl` v4 compatibility. */\n const $t = formatMessage as IntlShape['$t'];\n\n return {\n locale: localeString,\n defaultLocale: localeString,\n messages: {},\n formats: {},\n defaultFormats: {},\n timeZone: undefined,\n textComponent: Fragment,\n wrapRichTextChunksInFragment: false,\n fallbackOnEmptyString: true,\n onError: () => {},\n onWarn: () => {},\n formatters: {} as IntlShape['formatters'],\n formatMessage: formatMessage as IntlShape['formatMessage'],\n $t,\n formatDate,\n formatTime: formatDate,\n formatNumber,\n formatPlural,\n formatList: formatList as IntlShape['formatList'],\n formatListToParts: formatListToParts as IntlShape['formatListToParts'],\n formatDisplayName: formatDisplayName as IntlShape['formatDisplayName'],\n formatRelativeTime,\n formatDateTimeRange,\n formatDateToParts: formatDateToParts as IntlShape['formatDateToParts'],\n formatTimeToParts: formatDateToParts as IntlShape['formatTimeToParts'],\n formatNumberToParts:\n formatNumberToParts as IntlShape['formatNumberToParts'],\n } as unknown as IntlShape;\n};\n"],"mappings":"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"}
File without changes
@@ -8,5 +8,7 @@ import { InvalidConfigError, MessageFormatError, MissingDataError, MissingTransl
8
8
  import { defineMessage, defineMessages } from "./defineMessages.mjs";
9
9
  import { createIntl, createIntlCache } from "./createIntl.mjs";
10
10
  import { FormattedMessage } from "./FormattedMessage.mjs";
11
+ import { useDictionary } from "./useDictionary.mjs";
12
+ import { useDictionaryDynamic } from "./useDictionaryDynamic.mjs";
11
13
 
12
- export { FormattedDate, FormattedDateParts, FormattedDateTimeRange, FormattedDisplayName, FormattedList, FormattedListParts, FormattedMessage, FormattedNumber, FormattedNumberParts, FormattedPlural, FormattedRelativeTime, FormattedTime, FormattedTimeParts, IntlContext, IntlProvider, InvalidConfigError, MessageFormatError, MissingDataError, MissingTranslationError, RawIntlProvider, ReactIntlError, ReactIntlErrorCode, UnsupportedFormatterError, createIntl, createIntlCache, defineMessage, defineMessages, useIntl };
14
+ export { FormattedDate, FormattedDateParts, FormattedDateTimeRange, FormattedDisplayName, FormattedList, FormattedListParts, FormattedMessage, FormattedNumber, FormattedNumberParts, FormattedPlural, FormattedRelativeTime, FormattedTime, FormattedTimeParts, IntlContext, IntlProvider, InvalidConfigError, MessageFormatError, MissingDataError, MissingTranslationError, RawIntlProvider, ReactIntlError, ReactIntlErrorCode, UnsupportedFormatterError, createIntl, createIntlCache, defineMessage, defineMessages, useDictionary, useDictionaryDynamic, useIntl };
@@ -1,46 +1,13 @@
1
1
  import * as ANSIColors from "@intlayer/config/colors";
2
2
  import { colorize, getAppLogger } from "@intlayer/config/logger";
3
3
  import { join } from "node:path";
4
- import { runOnce } from "@intlayer/chokidar/utils";
4
+ import { REACT_INTL_CALLERS } from "@intlayer/config/callers";
5
5
  import { getConfiguration } from "@intlayer/config/node";
6
+ import { runOnce } from "@intlayer/engine/utils";
6
7
  import { intlayer } from "vite-intlayer";
7
8
 
8
9
  //#region src/plugin/index.ts
9
10
  /**
10
- * Caller configurations for react-intl's two message APIs.
11
- *
12
- * react-intl encodes both the dictionary key and the field path in a single
13
- * dotted id string, so the `path-first-segment` namespace source extracts the
14
- * first segment as the dictionary key and `translationFunction: 'self'` records
15
- * the second segment as the consumed field:
16
- *
17
- * `'home.title'` → dictionaryKey='home', field='title'
18
- * `'greeting'` → dictionaryKey='greeting', field='all' (single segment)
19
- * dynamic id → unresolvable → skipped (all fields kept)
20
- *
21
- * Both call sites are tracked:
22
- * - `intl.formatMessage({ id })` — matched as a method on any object.
23
- * - `<FormattedMessage id />` — matched as a JSX element (import-gated).
24
- *
25
- * The JSX form is mandatory: the prune context is shared across all files, so
26
- * tracking only `formatMessage` would let a field referenced solely from
27
- * `<FormattedMessage>` be pruned away whenever the same dictionary is also read
28
- * through `formatMessage`.
29
- */
30
- const REACT_INTL_COMPAT_CALLERS = [{
31
- callerName: "formatMessage",
32
- importSources: ["react-intl", "@intlayer/react-intl"],
33
- matchAsMethod: true,
34
- namespace: { from: "path-first-segment" },
35
- translationFunction: "self"
36
- }, {
37
- callerName: "FormattedMessage",
38
- importSources: ["react-intl", "@intlayer/react-intl"],
39
- jsxIdAttribute: "id",
40
- namespace: { from: "path-first-segment" },
41
- translationFunction: "self"
42
- }];
43
- /**
44
11
  * A Vite plugin for react-intl compat that wraps vite-intlayer
45
12
  * and injects a resolve alias mapping `react-intl` to
46
13
  * `@intlayer/react-intl`.
@@ -63,7 +30,7 @@ const reactIntlVitePlugin = (options) => {
63
30
  }, { cacheTimeoutMs: 1e3 * 60 * 60 });
64
31
  const basePlugins = intlayer({
65
32
  ...options,
66
- compatCallers: [...options?.compatCallers ?? [], ...REACT_INTL_COMPAT_CALLERS]
33
+ compatCallers: [...options?.compatCallers ?? [], ...REACT_INTL_CALLERS]
67
34
  });
68
35
  const compatPlugin = {
69
36
  name: "vite-react-intl-compat-plugin",
@@ -1 +1 @@
1
- {"version":3,"file":"index.mjs","names":[],"sources":["../../../src/plugin/index.ts"],"sourcesContent":["import { join } from 'node:path';\nimport { runOnce } from '@intlayer/chokidar/utils';\nimport * as ANSIColors from '@intlayer/config/colors';\nimport { colorize, getAppLogger } from '@intlayer/config/logger';\nimport { getConfiguration } from '@intlayer/config/node';\nimport type { PluginOption } from 'vite';\nimport { type CompatCallerConfig, intlayer } from 'vite-intlayer';\n\n/**\n * Caller configurations for react-intl's two message APIs.\n *\n * react-intl encodes both the dictionary key and the field path in a single\n * dotted id string, so the `path-first-segment` namespace source extracts the\n * first segment as the dictionary key and `translationFunction: 'self'` records\n * the second segment as the consumed field:\n *\n * `'home.title'` → dictionaryKey='home', field='title'\n * `'greeting'` → dictionaryKey='greeting', field='all' (single segment)\n * dynamic id → unresolvable → skipped (all fields kept)\n *\n * Both call sites are tracked:\n * - `intl.formatMessage({ id })` — matched as a method on any object.\n * - `<FormattedMessage id />` — matched as a JSX element (import-gated).\n *\n * The JSX form is mandatory: the prune context is shared across all files, so\n * tracking only `formatMessage` would let a field referenced solely from\n * `<FormattedMessage>` be pruned away whenever the same dictionary is also read\n * through `formatMessage`.\n */\nconst REACT_INTL_COMPAT_CALLERS: CompatCallerConfig[] = [\n {\n callerName: 'formatMessage',\n importSources: ['react-intl', '@intlayer/react-intl'],\n matchAsMethod: true,\n namespace: { from: 'path-first-segment' },\n translationFunction: 'self',\n },\n // `<FormattedMessage id=\"home.title\" />` — the dominant react-intl API. This\n // JSX form MUST be tracked alongside `formatMessage`: the prune context is\n // global across files, so a field referenced only from JSX would otherwise be\n // pruned away when the same dictionary is also read via `formatMessage`.\n {\n callerName: 'FormattedMessage',\n importSources: ['react-intl', '@intlayer/react-intl'],\n jsxIdAttribute: 'id',\n namespace: { from: 'path-first-segment' },\n translationFunction: 'self',\n },\n];\n\n/**\n * A Vite plugin for react-intl compat that wraps vite-intlayer\n * and injects a resolve alias mapping `react-intl` to\n * `@intlayer/react-intl`.\n *\n * @example\n * ```ts\n * // vite.config.ts\n * import reactIntlVitePlugin from '@intlayer/react-intl/plugin';\n *\n * export default defineConfig({\n * plugins: [reactIntlVitePlugin()],\n * });\n * ```\n */\nexport const reactIntlVitePlugin = (\n options?: Parameters<typeof intlayer>[0]\n): PluginOption[] => {\n const intlayerConfig = getConfiguration();\n const appLogger = getAppLogger(intlayerConfig);\n\n runOnce(\n join(\n intlayerConfig.system.baseDir,\n '.intlayer',\n 'cache',\n 'intlayer-issues-invitation.lock'\n ),\n () => {\n appLogger([\n colorize(\n 'Please report any issues you met on GitHub:',\n ANSIColors.GREY\n ),\n colorize(\n 'https://github.com/aymericzip/intlayer/issues',\n ANSIColors.GREY_LIGHT\n ),\n ]);\n },\n {\n cacheTimeoutMs: 1000 * 60 * 60, // 1 hour\n }\n );\n\n const basePlugins = intlayer({\n ...options,\n compatCallers: [\n ...(options?.compatCallers ?? []),\n ...REACT_INTL_COMPAT_CALLERS,\n ],\n });\n\n const compatPlugin: PluginOption = {\n name: 'vite-react-intl-compat-plugin',\n config: () => ({\n resolve: {\n alias: {\n 'react-intl': '@intlayer/react-intl',\n },\n },\n }),\n };\n\n return [\n ...(Array.isArray(basePlugins) ? basePlugins : [basePlugins]),\n compatPlugin,\n ];\n};\n\nexport default reactIntlVitePlugin;\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA6BA,MAAM,4BAAkD,CACtD;CACE,YAAY;CACZ,eAAe,CAAC,cAAc,sBAAsB;CACpD,eAAe;CACf,WAAW,EAAE,MAAM,qBAAqB;CACxC,qBAAqB;AACvB,GAKA;CACE,YAAY;CACZ,eAAe,CAAC,cAAc,sBAAsB;CACpD,gBAAgB;CAChB,WAAW,EAAE,MAAM,qBAAqB;CACxC,qBAAqB;AACvB,CACF;;;;;;;;;;;;;;;;AAiBA,MAAa,uBACX,YACmB;CACnB,MAAM,iBAAiB,iBAAiB;CACxC,MAAM,YAAY,aAAa,cAAc;CAE7C,QACE,KACE,eAAe,OAAO,SACtB,aACA,SACA,iCACF,SACM;EACJ,UAAU,CACR,SACE,+CACA,WAAW,IACb,GACA,SACE,iDACA,WAAW,UACb,CACF,CAAC;CACH,GACA,EACE,gBAAgB,MAAO,KAAK,GAC9B,CACF;CAEA,MAAM,cAAc,SAAS;EAC3B,GAAG;EACH,eAAe,CACb,GAAI,SAAS,iBAAiB,CAAC,GAC/B,GAAG,yBACL;CACF,CAAC;CAED,MAAM,eAA6B;EACjC,MAAM;EACN,eAAe,EACb,SAAS,EACP,OAAO,EACL,cAAc,uBAChB,EACF,EACF;CACF;CAEA,OAAO,CACL,GAAI,MAAM,QAAQ,WAAW,IAAI,cAAc,CAAC,WAAW,GAC3D,YACF;AACF"}
1
+ {"version":3,"file":"index.mjs","names":[],"sources":["../../../src/plugin/index.ts"],"sourcesContent":["import { join } from 'node:path';\nimport { REACT_INTL_CALLERS } from '@intlayer/config/callers';\nimport * as ANSIColors from '@intlayer/config/colors';\nimport { colorize, getAppLogger } from '@intlayer/config/logger';\nimport { getConfiguration } from '@intlayer/config/node';\nimport { runOnce } from '@intlayer/engine/utils';\nimport type { PluginOption } from 'vite';\nimport { intlayer } from 'vite-intlayer';\n\n/**\n * A Vite plugin for react-intl compat that wraps vite-intlayer\n * and injects a resolve alias mapping `react-intl` to\n * `@intlayer/react-intl`.\n *\n * @example\n * ```ts\n * // vite.config.ts\n * import reactIntlVitePlugin from '@intlayer/react-intl/plugin';\n *\n * export default defineConfig({\n * plugins: [reactIntlVitePlugin()],\n * });\n * ```\n */\nexport const reactIntlVitePlugin = (\n options?: Parameters<typeof intlayer>[0]\n): PluginOption[] => {\n const intlayerConfig = getConfiguration();\n const appLogger = getAppLogger(intlayerConfig);\n\n runOnce(\n join(\n intlayerConfig.system.baseDir,\n '.intlayer',\n 'cache',\n 'intlayer-issues-invitation.lock'\n ),\n () => {\n appLogger([\n colorize(\n 'Please report any issues you met on GitHub:',\n ANSIColors.GREY\n ),\n colorize(\n 'https://github.com/aymericzip/intlayer/issues',\n ANSIColors.GREY_LIGHT\n ),\n ]);\n },\n {\n cacheTimeoutMs: 1000 * 60 * 60, // 1 hour\n }\n );\n\n const basePlugins = intlayer({\n ...options,\n compatCallers: [...(options?.compatCallers ?? []), ...REACT_INTL_CALLERS],\n });\n\n const compatPlugin: PluginOption = {\n name: 'vite-react-intl-compat-plugin',\n config: () => ({\n resolve: {\n alias: {\n 'react-intl': '@intlayer/react-intl',\n },\n },\n }),\n };\n\n return [\n ...(Array.isArray(basePlugins) ? basePlugins : [basePlugins]),\n compatPlugin,\n ];\n};\n\nexport default reactIntlVitePlugin;\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;AAwBA,MAAa,uBACX,YACmB;CACnB,MAAM,iBAAiB,iBAAiB;CACxC,MAAM,YAAY,aAAa,cAAc;CAE7C,QACE,KACE,eAAe,OAAO,SACtB,aACA,SACA,iCACF,SACM;EACJ,UAAU,CACR,SACE,+CACA,WAAW,IACb,GACA,SACE,iDACA,WAAW,UACb,CACF,CAAC;CACH,GACA,EACE,gBAAgB,MAAO,KAAK,GAC9B,CACF;CAEA,MAAM,cAAc,SAAS;EAC3B,GAAG;EACH,eAAe,CAAC,GAAI,SAAS,iBAAiB,CAAC,GAAI,GAAG,kBAAkB;CAC1E,CAAC;CAED,MAAM,eAA6B;EACjC,MAAM;EACN,eAAe,EACb,SAAS,EACP,OAAO,EACL,cAAc,uBAChB,EACF,EACF;CACF;CAEA,OAAO,CACL,GAAI,MAAM,QAAQ,WAAW,IAAI,cAAc,CAAC,WAAW,GAC3D,YACF;AACF"}
File without changes
@@ -0,0 +1,45 @@
1
+ 'use client';
2
+
3
+ import { createIntlObject } from "./createIntlObject.mjs";
4
+ import { useMemo } from "react";
5
+ import { useDictionary as useDictionary$1, useLocale } from "react-intlayer";
6
+ import { navigatePath } from "@intlayer/core/messageFormat";
7
+
8
+ //#region src/useDictionary.ts
9
+ /**
10
+ * Builds the id lookup of a dictionary-bound intl object.
11
+ *
12
+ * react-intl ids encode the dictionary key as their first dot-segment
13
+ * (`'home.title'` → dictionary `home`, field `title`). When the content is
14
+ * supplied directly, the leading `<dictionaryKey>.` is stripped so both the
15
+ * absolute (`'home.title'`) and relative (`'title'`) forms resolve.
16
+ */
17
+ const createDictionaryLookup = (dictionaryKey, content) => (id) => {
18
+ return navigatePath(content, id.startsWith(`${dictionaryKey}.`) ? id.slice(dictionaryKey.length + 1) : id === dictionaryKey ? "" : id);
19
+ };
20
+ /**
21
+ * Dictionary-accepting variant of `useIntl`.
22
+ *
23
+ * Returns an `IntlShape` whose `formatMessage` resolves ids inside the
24
+ * supplied dictionary instead of the runtime registry, enabling tree-shaking
25
+ * of unused locale content. All `Intl`-backed formatters (`formatNumber`,
26
+ * `formatDate`, …) behave exactly like `useIntl()`.
27
+ *
28
+ * @example
29
+ * import _abc from '.intlayer/dictionaries/home.json' with { type: 'json' };
30
+ * const intl = useDictionary(_abc);
31
+ * intl.formatMessage({ id: 'home.title' }); // or { id: 'title' } — both typed
32
+ */
33
+ const useDictionary = (dictionary) => {
34
+ const content = useDictionary$1(dictionary);
35
+ const { locale } = useLocale();
36
+ return useMemo(() => createIntlObject(locale, createDictionaryLookup(dictionary.key, content)), [
37
+ locale,
38
+ dictionary.key,
39
+ content
40
+ ]);
41
+ };
42
+
43
+ //#endregion
44
+ export { createDictionaryLookup, useDictionary };
45
+ //# sourceMappingURL=useDictionary.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useDictionary.mjs","names":["useDictionaryBase"],"sources":["../../src/useDictionary.ts"],"sourcesContent":["'use client';\n\nimport { navigatePath } from '@intlayer/core/messageFormat';\nimport type { Dictionary } from '@intlayer/types/dictionary';\nimport type {\n DictionaryKeys,\n LocalesValues,\n} from '@intlayer/types/module_augmentation';\nimport { useMemo } from 'react';\nimport { useDictionary as useDictionaryBase, useLocale } from 'react-intlayer';\nimport { createIntlObject } from './createIntlObject';\nimport type { DictionaryIntlShape } from './dictionaryIntlShape';\n\n/**\n * Builds the id lookup of a dictionary-bound intl object.\n *\n * react-intl ids encode the dictionary key as their first dot-segment\n * (`'home.title'` → dictionary `home`, field `title`). When the content is\n * supplied directly, the leading `<dictionaryKey>.` is stripped so both the\n * absolute (`'home.title'`) and relative (`'title'`) forms resolve.\n */\nexport const createDictionaryLookup =\n (dictionaryKey: string, content: unknown) =>\n (id: string): unknown => {\n const relativePath = id.startsWith(`${dictionaryKey}.`)\n ? id.slice(dictionaryKey.length + 1)\n : id === dictionaryKey\n ? ''\n : id;\n return navigatePath(content, relativePath);\n };\n\n/**\n * Dictionary-accepting variant of `useIntl`.\n *\n * Returns an `IntlShape` whose `formatMessage` resolves ids inside the\n * supplied dictionary instead of the runtime registry, enabling tree-shaking\n * of unused locale content. All `Intl`-backed formatters (`formatNumber`,\n * `formatDate`, …) behave exactly like `useIntl()`.\n *\n * @example\n * import _abc from '.intlayer/dictionaries/home.json' with { type: 'json' };\n * const intl = useDictionary(_abc);\n * intl.formatMessage({ id: 'home.title' }); // or { id: 'title' } — both typed\n */\nexport const useDictionary = <T extends Dictionary>(\n dictionary: T\n): DictionaryIntlShape<T['key'] & DictionaryKeys> => {\n const content = useDictionaryBase(dictionary);\n const { locale } = useLocale();\n\n return useMemo(\n () =>\n createIntlObject(\n locale as LocalesValues,\n createDictionaryLookup(dictionary.key, content)\n ) as DictionaryIntlShape<T['key'] & DictionaryKeys>,\n [locale, dictionary.key, content]\n );\n};\n"],"mappings":";;;;;;;;;;;;;;;;AAqBA,MAAa,0BACV,eAAuB,aACvB,OAAwB;CAMvB,OAAO,aAAa,SALC,GAAG,WAAW,GAAG,cAAc,EAAE,IAClD,GAAG,MAAM,cAAc,SAAS,CAAC,IACjC,OAAO,gBACL,KACA,EACmC;AAC3C;;;;;;;;;;;;;;AAeF,MAAa,iBACX,eACmD;CACnD,MAAM,UAAUA,gBAAkB,UAAU;CAC5C,MAAM,EAAE,WAAW,UAAU;CAE7B,OAAO,cAEH,iBACE,QACA,uBAAuB,WAAW,KAAK,OAAO,CAChD,GACF;EAAC;EAAQ,WAAW;EAAK;CAAO,CAClC;AACF"}
@@ -0,0 +1,27 @@
1
+ 'use client';
2
+
3
+ import { createIntlObject } from "./createIntlObject.mjs";
4
+ import { createDictionaryLookup } from "./useDictionary.mjs";
5
+ import { useMemo } from "react";
6
+ import { useDictionaryDynamic as useDictionaryDynamic$1, useLocale } from "react-intlayer";
7
+
8
+ //#region src/useDictionaryDynamic.ts
9
+ /**
10
+ * Dynamic dictionary-accepting variant of `useIntl`.
11
+ *
12
+ * Counterpart to {@link useDictionary} for dictionaries imported lazily per
13
+ * locale. Used internally by the build-time optimization.
14
+ */
15
+ const useDictionaryDynamic = (dictionaryPromise, key) => {
16
+ const content = useDictionaryDynamic$1(dictionaryPromise, key);
17
+ const { locale } = useLocale();
18
+ return useMemo(() => createIntlObject(locale, createDictionaryLookup(key, content)), [
19
+ locale,
20
+ key,
21
+ content
22
+ ]);
23
+ };
24
+
25
+ //#endregion
26
+ export { useDictionaryDynamic };
27
+ //# sourceMappingURL=useDictionaryDynamic.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useDictionaryDynamic.mjs","names":["useDictionaryDynamicBase"],"sources":["../../src/useDictionaryDynamic.ts"],"sourcesContent":["'use client';\n\nimport type { Dictionary } from '@intlayer/types/dictionary';\nimport type {\n DictionaryKeys,\n LocalesValues,\n StrictModeLocaleMap,\n} from '@intlayer/types/module_augmentation';\nimport { useMemo } from 'react';\nimport {\n useDictionaryDynamic as useDictionaryDynamicBase,\n useLocale,\n} from 'react-intlayer';\nimport { createIntlObject } from './createIntlObject';\nimport type { DictionaryIntlShape } from './dictionaryIntlShape';\nimport { createDictionaryLookup } from './useDictionary';\n\n/**\n * Dynamic dictionary-accepting variant of `useIntl`.\n *\n * Counterpart to {@link useDictionary} for dictionaries imported lazily per\n * locale. Used internally by the build-time optimization.\n */\nexport const useDictionaryDynamic = <\n const T extends Dictionary,\n const K extends DictionaryKeys,\n>(\n dictionaryPromise: StrictModeLocaleMap<() => Promise<T>>,\n key: K\n): DictionaryIntlShape<K> => {\n const content = useDictionaryDynamicBase<T, K>(dictionaryPromise, key);\n const { locale } = useLocale();\n\n return useMemo(\n () =>\n createIntlObject(\n locale as LocalesValues,\n createDictionaryLookup(key, content)\n ) as DictionaryIntlShape<K>,\n [locale, key, content]\n );\n};\n"],"mappings":";;;;;;;;;;;;;;AAuBA,MAAa,wBAIX,mBACA,QAC2B;CAC3B,MAAM,UAAUA,uBAA+B,mBAAmB,GAAG;CACrE,MAAM,EAAE,WAAW,UAAU;CAE7B,OAAO,cAEH,iBACE,QACA,uBAAuB,KAAK,OAAO,CACrC,GACF;EAAC;EAAQ;EAAK;CAAO,CACvB;AACF"}
@@ -1,5 +1,4 @@
1
1
  import { FormattedDate as FormattedDate$1, FormattedDateParts as FormattedDateParts$1, FormattedDateTimeRange as FormattedDateTimeRange$1, FormattedDisplayName as FormattedDisplayName$1, FormattedList as FormattedList$1, FormattedListParts as FormattedListParts$1, FormattedNumber as FormattedNumber$1, FormattedNumberParts as FormattedNumberParts$1, FormattedPlural as FormattedPlural$1, FormattedRelativeTime as FormattedRelativeTime$1, FormattedTime as FormattedTime$1, FormattedTimeParts as FormattedTimeParts$1 } from "react-intl";
2
-
3
2
  //#region src/FormattedComponents.d.ts
4
3
  /**
5
4
  * Drop-in for react-intl's `<FormattedDate>`.
@@ -1 +1 @@
1
- {"version":3,"file":"FormattedComponents.d.ts","names":[],"sources":["../../src/FormattedComponents.tsx"],"mappings":";;;;;AA8BA;;cAAa,aAAA,SAAsB,eAYlC;;AAAA;AAMD;;cAAa,aAAA,SAAsB,eAYlC;;AAAA;AAMD;;cAAa,eAAA,SAAwB,iBAYpC;;AAAA;AAMD;;cAAa,aAAA,SAAsB,eAOlC;;AAAA;AAMD;;cAAa,oBAAA,SAA6B,sBAUzC;;AAAA;AAOD;;;cAAa,qBAAA,SAA8B,uBAa1C;AAAA;AAMD;;;AANC,cAMY,eAAA,SAAwB,iBA6BpC;AAAA;AAMD;;;AANC,cAMY,sBAAA,SAA+B,wBAY3C;AAAA;AAMD;;;AANC,cAMY,kBAAA,SAA2B,oBAYvC;AAAA;AAMD;;;AANC,cAMY,kBAAA,SAA2B,oBAYvC;AAAA;AAMD;;;AANC,cAMY,oBAAA,SAA6B,sBASzC;AAAA;AAMD;;;AANC,cAMY,kBAAA,SAA2B,oBAWvC"}
1
+ {"version":3,"file":"FormattedComponents.d.ts","names":[],"sources":["../../src/FormattedComponents.tsx"],"mappings":";;;;;;cA8Ba,sBAAsB;;;;;cAkBtB,sBAAsB;;;;;cAkBtB,wBAAwB;;;;;cAkBxB,sBAAsB;;;;;cAatB,6BAA6B;;;;;;cAiB7B,8BAA8B;;;;;cAmB9B,wBAAwB;;;;;cAmCxB,+BAA+B;;;;;cAkB/B,2BAA2B;;;;;cAkB3B,2BAA2B;;;;;cAkB3B,6BAA6B;;;;;cAe7B,2BAA2B"}
@@ -1,5 +1,4 @@
1
1
  import { FormattedMessage as FormattedMessage$1 } from "react-intl";
2
-
3
2
  //#region src/FormattedMessage.d.ts
4
3
  /**
5
4
  * Drop-in for react-intl's `<FormattedMessage>`.
@@ -1 +1 @@
1
- {"version":3,"file":"FormattedMessage.d.ts","names":[],"sources":["../../src/FormattedMessage.tsx"],"mappings":";;;;;AA2BA;;;;AAgCC;;;;;;;;;;;;;;;cAhCY,gBAAA,SAAyB,kBAgCrC"}
1
+ {"version":3,"file":"FormattedMessage.d.ts","names":[],"sources":["../../src/FormattedMessage.tsx"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;cA2Ba,yBAAyB"}
@@ -1,5 +1,4 @@
1
1
  import { IntlProvider as IntlProvider$1 } from "react-intl";
2
-
3
2
  //#region src/IntlProvider.d.ts
4
3
  /**
5
4
  * Drop-in for react-intl's `IntlProvider`.
@@ -1 +1 @@
1
- {"version":3,"file":"IntlProvider.d.ts","names":[],"sources":["../../src/IntlProvider.tsx"],"mappings":";;;;;AAqBA;;;;AAgCC;;;cAhCY,YAAA,SAAqB,cAgCjC"}
1
+ {"version":3,"file":"IntlProvider.d.ts","names":[],"sources":["../../src/IntlProvider.tsx"],"mappings":";;;;;;;;;;;cAqBa,qBAAqB"}
@@ -1,5 +1,4 @@
1
1
  import { IntlShape } from "react-intl";
2
-
3
2
  //#region src/context.d.ts
4
3
  /**
5
4
  * React context holding the active intlayer-backed `IntlShape` instance.
@@ -1 +1 @@
1
- {"version":3,"file":"context.d.ts","names":[],"sources":["../../src/context.tsx"],"mappings":";;;;;AAOA;;cAAa,WAAA,kBAAW,OAAA,CAAA,SAAA;;cAKX,eAAA,kBAAe,QAAA,CAAA,SAAA"}
1
+ {"version":3,"file":"context.d.ts","names":[],"sources":["../../src/context.tsx"],"mappings":";;;;;;cAOa,6BAAW,QAAA;;cAKX,iCAAe,SAAA"}
@@ -1,5 +1,4 @@
1
1
  import { createIntl as createIntl$1, createIntlCache as createIntlCache$1 } from "react-intl";
2
-
3
2
  //#region src/createIntl.d.ts
4
3
  /**
5
4
  * Drop-in for react-intl's `createIntlCache`.
@@ -1 +1 @@
1
- {"version":3,"file":"createIntl.d.ts","names":[],"sources":["../../src/createIntl.ts"],"mappings":";;;;;AAoBA;;;;AASiB;AAmBjB;;;cA5Ba,eAAA,SAAwB,iBASpB;AAsBwC;;;;;;;;;;;;;;;;;AAAA,cAH5C,UAAA,SAAmB,YAGyB"}
1
+ {"version":3,"file":"createIntl.d.ts","names":[],"sources":["../../src/createIntl.ts"],"mappings":";;;;;;;;;;;;cAoBa,wBAAwB;;;;;;;;;;;;;;;;;;cA4BxB,mBAAmB"}
@@ -1,6 +1,5 @@
1
1
  import { IntlShape } from "react-intl";
2
2
  import { LocalesValues } from "@intlayer/types/module_augmentation";
3
-
4
3
  //#region src/createIntlObject.d.ts
5
4
  /**
6
5
  * Builds an intlayer-backed `IntlShape` object for the given locale.
@@ -8,8 +7,12 @@ import { LocalesValues } from "@intlayer/types/module_augmentation";
8
7
  * - Translation ids use the first dot-path segment as the dictionary key.
9
8
  * - Full ICU MessageFormat syntax is supported via `@intlayer/core/messageFormat`.
10
9
  * - Rich text tags (`<b>chunks</b>`) are resolved through render functions in `values`.
10
+ *
11
+ * @param locale - The locale messages are resolved for.
12
+ * @param lookupOverride - Optional message lookup replacing the registry-based
13
+ * id resolution; used by the dictionary-bound `useDictionary` variant.
11
14
  */
12
- declare const createIntlObject: (locale: LocalesValues) => IntlShape;
15
+ declare const createIntlObject: (locale: LocalesValues, lookupOverride?: (id: string) => unknown) => IntlShape;
13
16
  //#endregion
14
17
  export { createIntlObject };
15
18
  //# sourceMappingURL=createIntlObject.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"createIntlObject.d.ts","names":[],"sources":["../../src/createIntlObject.tsx"],"mappings":";;;;;;AAiGA;;;;;cAAa,gBAAA,GAAoB,MAAA,EAAQ,aAAA,KAAgB,SAqJxD"}
1
+ {"version":3,"file":"createIntlObject.d.ts","names":[],"sources":["../../src/createIntlObject.tsx"],"mappings":";;;;;;;;;;;;;;cAqFa,mBAAgB,QACnB,eAAa,kBACH,2BACjB"}
@@ -1,5 +1,4 @@
1
1
  import { defineMessage as defineMessage$1, defineMessages as defineMessages$1 } from "react-intl";
2
-
3
2
  //#region src/defineMessages.d.ts
4
3
  /**
5
4
  * Drop-in for react-intl's `defineMessages`.
@@ -1 +1 @@
1
- {"version":3,"file":"defineMessages.d.ts","names":[],"sources":["../../src/defineMessages.ts"],"mappings":";;;;;AAWA;;;;cAAa,cAAA,SAAuB,gBAAwC;AAM5E;;;;AAAA,cAAa,aAAA,SAAsB,eAAqC"}
1
+ {"version":3,"file":"defineMessages.d.ts","names":[],"sources":["../../src/defineMessages.ts"],"mappings":";;;;;;;;cAWa,uBAAuB;;;;;cAMvB,sBAAsB"}
@@ -0,0 +1,53 @@
1
+ import { IntlShape, MessageDescriptor, PrimitiveType } from "react-intl";
2
+ import { DictionaryKeys } from "@intlayer/types/module_augmentation";
3
+ import { GetNestingResult } from "@intlayer/core/interpreter";
4
+ import { ValidDotPathsFor } from "@intlayer/core/transpiler";
5
+ import { ReactNode } from "react";
6
+ //#region src/dictionaryIntlShape.d.ts
7
+ /**
8
+ * The interpreter-resolved content type at dot-path `P` of dictionary `N` —
9
+ * the same type strength as the base `useIntlayer` hook.
10
+ */
11
+ type ContentAtPath<N extends DictionaryKeys, P> = GetNestingResult<N, P>;
12
+ /**
13
+ * The value returned by `formatMessage` for the path `P` of dictionary `N`:
14
+ * string literals declared in the dictionary keep their literal type, every
15
+ * other node resolves to `string` at runtime.
16
+ */
17
+ type TranslatedValue<N extends DictionaryKeys, P> = ContentAtPath<N, P> extends string ? ContentAtPath<N, P> : string;
18
+ /**
19
+ * Ids accepted by a dictionary-bound intl object: the dictionary's dot-paths,
20
+ * either relative (`'title'`) or absolute (`'home.title'`).
21
+ */
22
+ type DictionaryMessageIds<N extends DictionaryKeys> = ValidDotPathsFor<N> | `${N & string}.${ValidDotPathsFor<N> & string}`;
23
+ /**
24
+ * Resolves the translated value type for an id: the absolute form strips the
25
+ * leading `<dictionaryKey>.` first, matching the runtime lookup.
26
+ */
27
+ type MessageValueForId<N extends DictionaryKeys, Id extends string> = Id extends `${N & string}.${infer RelativePath}` ? TranslatedValue<N, RelativePath> : TranslatedValue<N, Id>;
28
+ /**
29
+ * `formatMessage` bound to dictionary `N`: ids are validated against the
30
+ * dictionary's dot-paths and the return type is resolved from the content at
31
+ * that path. With rich-text render functions in `values`, React nodes are
32
+ * returned.
33
+ */
34
+ type TypedFormatMessage<N extends DictionaryKeys> = {
35
+ <Id extends DictionaryMessageIds<N> & string>(descriptor: Omit<MessageDescriptor, 'id'> & {
36
+ id: Id;
37
+ }, values?: Record<string, PrimitiveType>): MessageValueForId<N, Id>;
38
+ <Id extends DictionaryMessageIds<N> & string>(descriptor: Omit<MessageDescriptor, 'id'> & {
39
+ id: Id;
40
+ }, values?: Record<string, ReactNode | PrimitiveType | ((chunks: ReactNode) => ReactNode)>): string | ReactNode[];
41
+ };
42
+ /**
43
+ * `IntlShape` whose `formatMessage` / `$t` are typed against the dictionary
44
+ * `N`. Returned by the dictionary-bound `useDictionary` /
45
+ * `useDictionaryDynamic` variants.
46
+ */
47
+ type DictionaryIntlShape<N extends DictionaryKeys> = Omit<IntlShape, 'formatMessage' | '$t'> & {
48
+ formatMessage: TypedFormatMessage<N>;
49
+ $t: TypedFormatMessage<N>;
50
+ };
51
+ //#endregion
52
+ export { DictionaryIntlShape, DictionaryMessageIds, MessageValueForId, TypedFormatMessage };
53
+ //# sourceMappingURL=dictionaryIntlShape.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dictionaryIntlShape.d.ts","names":[],"sources":["../../src/dictionaryIntlShape.ts"],"mappings":";;;;;;;;;;KAUK,cAAc,UAAU,gBAAgB,KAAK,iBAAiB,GAAG;;;;;;KAOjE,gBAAgB,UAAU,gBAAgB,KAC7C,cAAc,GAAG,oBAAoB,cAAc,GAAG;;;;;KAM5C,qBAAqB,UAAU,kBACvC,iBAAiB,QACd,cAAc,iBAAiB;;;;;KAM1B,kBACV,UAAU,gBACV,qBACE,cAAc,oBAAoB,iBAClC,gBAAgB,GAAG,gBACnB,gBAAgB,GAAG;;;;;;;KAQX,mBAAmB,UAAU;GACtC,WAAW,qBAAqB,aAC/B,YAAY,KAAK;IAA6B,IAAI;KAClD,SAAS,eAAe,iBACvB,kBAAkB,GAAG;GACvB,WAAW,qBAAqB,aAC/B,YAAY,KAAK;IAA6B,IAAI;KAClD,SAAS,eAEP,YAAY,kBAAkB,QAAQ,cAAc,uBAE5C;;;;;;;KAQF,oBAAoB,UAAU,kBAAkB,KAC1D;EAGA,eAAe,mBAAmB;EAClC,IAAI,mBAAmB"}
@@ -1 +1 @@
1
- {"version":3,"file":"errors.d.ts","names":[],"sources":["../../src/errors.ts"],"mappings":";;AAMA;;;;;aAAY,kBAAA;EACV,YAAA;EACA,qBAAA;EACA,cAAA;EACA,YAAA;EACA,mBAAA;AAAA;;;;;;cAQW,cAAA,SAAuB,KAAA;EAAA,SAClB,IAAA,EAAM,kBAAA;cAEV,IAAA,EAAM,kBAAA,EAAoB,OAAA;AAAA;;;;cAU3B,kBAAA,SAA2B,cAAc;cACxC,OAAA;AAAA;AAXyC;AAUvD;;AAVuD,cAoB1C,kBAAA,SAA2B,cAAc;cACxC,OAAA;AAAA;;;;cASD,gBAAA,SAAyB,cAAc;cACtC,OAAA;AAAA;;;;cASD,uBAAA,SAAgC,cAAc;cAC7C,OAAA;AAAA;AApBe;AAS7B;;AAT6B,cA6BhB,yBAAA,SAAkC,cAAc;cAC/C,OAAA;AAAA"}
1
+ {"version":3,"file":"errors.d.ts","names":[],"sources":["../../src/errors.ts"],"mappings":";;;;;;;aAMY;EACV;EACA;EACA;EACA;EACA;;;;;;;cAQW,uBAAuB;WAClB,MAAM;EAEtB,YAAY,MAAM,oBAAoB;;;;;cAU3B,2BAA2B;EACtC,YAAY;;;;;cASD,2BAA2B;EACtC,YAAY;;;;;cASD,yBAAyB;EACpC,YAAY;;;;;cASD,gCAAgC;EAC3C,YAAY;;;;;cASD,kCAAkC;EAC7C,YAAY"}
@@ -4,7 +4,11 @@ import { IntlProvider } from "./IntlProvider.js";
4
4
  import { IntlContext, RawIntlProvider } from "./context.js";
5
5
  import { createIntl, createIntlCache } from "./createIntl.js";
6
6
  import { defineMessage, defineMessages } from "./defineMessages.js";
7
+ import { DictionaryIntlShape, DictionaryMessageIds, MessageValueForId, TypedFormatMessage } from "./dictionaryIntlShape.js";
7
8
  import { InvalidConfigError, MessageFormatError, MissingDataError, MissingTranslationError, ReactIntlError, ReactIntlErrorCode, UnsupportedFormatterError } from "./errors.js";
9
+ import { RootMessageIds } from "./typedMessageIds.js";
10
+ import { useDictionary } from "./useDictionary.js";
11
+ import { useDictionaryDynamic } from "./useDictionaryDynamic.js";
8
12
  import { useIntl } from "./useIntl.js";
9
13
  import { CustomFormats, FormatDateOptions, FormatDisplayNameOptions, FormatListOptions, FormatNumberOptions, FormatPluralOptions, FormatRelativeTimeOptions, Formatters, IntlCache, IntlConfig, IntlFormatters, IntlShape, MessageDescriptor, MessageFormatElement, PrimitiveType, ResolvedIntlConfig } from "react-intl";
10
- export { type CustomFormats, type FormatDateOptions, type FormatDisplayNameOptions, type FormatListOptions, type FormatNumberOptions, type FormatPluralOptions, type FormatRelativeTimeOptions, FormattedDate, FormattedDateParts, FormattedDateTimeRange, FormattedDisplayName, FormattedList, FormattedListParts, FormattedMessage, FormattedNumber, FormattedNumberParts, FormattedPlural, FormattedRelativeTime, FormattedTime, FormattedTimeParts, type Formatters, type IntlCache, type IntlConfig, IntlContext, type IntlFormatters, IntlProvider, type IntlShape, InvalidConfigError, type MessageDescriptor, type MessageFormatElement, MessageFormatError, MissingDataError, MissingTranslationError, type PrimitiveType, RawIntlProvider, ReactIntlError, ReactIntlErrorCode, type ResolvedIntlConfig, UnsupportedFormatterError, createIntl, createIntlCache, defineMessage, defineMessages, useIntl };
14
+ export { type CustomFormats, type DictionaryIntlShape, type DictionaryMessageIds, type FormatDateOptions, type FormatDisplayNameOptions, type FormatListOptions, type FormatNumberOptions, type FormatPluralOptions, type FormatRelativeTimeOptions, FormattedDate, FormattedDateParts, FormattedDateTimeRange, FormattedDisplayName, FormattedList, FormattedListParts, FormattedMessage, FormattedNumber, FormattedNumberParts, FormattedPlural, FormattedRelativeTime, FormattedTime, FormattedTimeParts, type Formatters, type IntlCache, type IntlConfig, IntlContext, type IntlFormatters, IntlProvider, type IntlShape, InvalidConfigError, type MessageDescriptor, type MessageFormatElement, MessageFormatError, type MessageValueForId, MissingDataError, MissingTranslationError, type PrimitiveType, RawIntlProvider, ReactIntlError, ReactIntlErrorCode, type ResolvedIntlConfig, type RootMessageIds, type TypedFormatMessage, UnsupportedFormatterError, createIntl, createIntlCache, defineMessage, defineMessages, useDictionary, useDictionaryDynamic, useIntl };
@@ -1,6 +1,5 @@
1
1
  import { PluginOption } from "vite";
2
2
  import { intlayer } from "vite-intlayer";
3
-
4
3
  //#region src/plugin/index.d.ts
5
4
  /**
6
5
  * A Vite plugin for react-intl compat that wraps vite-intlayer
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","names":[],"sources":["../../../src/plugin/index.ts"],"mappings":";;;;;;AAiEA;;;;;;;;;;;;;cAAa,mBAAA,GACX,OAAA,GAAU,UAAA,QAAkB,QAAA,SAC3B,YAAA"}
1
+ {"version":3,"file":"index.d.ts","names":[],"sources":["../../../src/plugin/index.ts"],"mappings":";;;;;;;;;;;;;;;;;;cAwBa,sBAAmB,UACpB,kBAAkB,iBAC3B"}
@@ -0,0 +1,25 @@
1
+ import { DictionaryKeys } from "@intlayer/types/module_augmentation";
2
+ import { ValidDotPathsFor } from "@intlayer/core/transpiler";
3
+ //#region src/typedMessageIds.d.ts
4
+ /**
5
+ * Every valid react-intl message id: `<dictionaryKey>.<dotPath>`, where the
6
+ * first segment designates the intlayer dictionary. Falls back to `string`
7
+ * when no dictionary registry is declared (e.g. before the first build).
8
+ */
9
+ type RootMessageIds = string extends DictionaryKeys ? string : { [K in DictionaryKeys]: `${K & string}.${ValidDotPathsFor<K> & string}`; }[DictionaryKeys];
10
+ declare global {
11
+ namespace FormatjsIntl {
12
+ interface Message {
13
+ /**
14
+ * Types every react-intl message id (`formatMessage`,
15
+ * `<FormattedMessage>`, `defineMessages`, …) against the intlayer
16
+ * dictionary registry — the same strength as the base `useIntlayer`
17
+ * hook.
18
+ */
19
+ ids: RootMessageIds;
20
+ }
21
+ }
22
+ }
23
+ //#endregion
24
+ export { RootMessageIds };
25
+ //# sourceMappingURL=typedMessageIds.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"typedMessageIds.d.ts","names":[],"sources":["../../src/typedMessageIds.ts"],"mappings":";;;;;;;;KAQY,gCAAgC,6BAGrC,KAAK,oBAAoB,cAAc,iBAAiB,iBACzD;QAEE;YACI;cACE;;;;;;;MAOR,KAAK"}
@@ -0,0 +1,30 @@
1
+ import { DictionaryIntlShape } from "./dictionaryIntlShape.js";
2
+ import { DictionaryKeys } from "@intlayer/types/module_augmentation";
3
+ import { Dictionary } from "@intlayer/types/dictionary";
4
+ //#region src/useDictionary.d.ts
5
+ /**
6
+ * Builds the id lookup of a dictionary-bound intl object.
7
+ *
8
+ * react-intl ids encode the dictionary key as their first dot-segment
9
+ * (`'home.title'` → dictionary `home`, field `title`). When the content is
10
+ * supplied directly, the leading `<dictionaryKey>.` is stripped so both the
11
+ * absolute (`'home.title'`) and relative (`'title'`) forms resolve.
12
+ */
13
+ declare const createDictionaryLookup: (dictionaryKey: string, content: unknown) => (id: string) => unknown;
14
+ /**
15
+ * Dictionary-accepting variant of `useIntl`.
16
+ *
17
+ * Returns an `IntlShape` whose `formatMessage` resolves ids inside the
18
+ * supplied dictionary instead of the runtime registry, enabling tree-shaking
19
+ * of unused locale content. All `Intl`-backed formatters (`formatNumber`,
20
+ * `formatDate`, …) behave exactly like `useIntl()`.
21
+ *
22
+ * @example
23
+ * import _abc from '.intlayer/dictionaries/home.json' with { type: 'json' };
24
+ * const intl = useDictionary(_abc);
25
+ * intl.formatMessage({ id: 'home.title' }); // or { id: 'title' } — both typed
26
+ */
27
+ declare const useDictionary: <T extends Dictionary>(dictionary: T) => DictionaryIntlShape<T['key'] & DictionaryKeys>;
28
+ //#endregion
29
+ export { createDictionaryLookup, useDictionary };
30
+ //# sourceMappingURL=useDictionary.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useDictionary.d.ts","names":[],"sources":["../../src/useDictionary.ts"],"mappings":";;;;;;;;;;;;cAqBa,yBAAsB,uBACX,sBAAkB;;;;;;;;;;;;;;cAuB7B,gBAAiB,UAAU,YAAU,YACpC,MACX,oBAAoB,WAAW"}
@@ -0,0 +1,14 @@
1
+ import { DictionaryIntlShape } from "./dictionaryIntlShape.js";
2
+ import { DictionaryKeys, StrictModeLocaleMap } from "@intlayer/types/module_augmentation";
3
+ import { Dictionary } from "@intlayer/types/dictionary";
4
+ //#region src/useDictionaryDynamic.d.ts
5
+ /**
6
+ * Dynamic dictionary-accepting variant of `useIntl`.
7
+ *
8
+ * Counterpart to {@link useDictionary} for dictionaries imported lazily per
9
+ * locale. Used internally by the build-time optimization.
10
+ */
11
+ declare const useDictionaryDynamic: <const T extends Dictionary, const K extends DictionaryKeys>(dictionaryPromise: StrictModeLocaleMap<() => Promise<T>>, key: K) => DictionaryIntlShape<K>;
12
+ //#endregion
13
+ export { useDictionaryDynamic };
14
+ //# sourceMappingURL=useDictionaryDynamic.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useDictionaryDynamic.d.ts","names":[],"sources":["../../src/useDictionaryDynamic.ts"],"mappings":";;;;;;;;;;cAuBa,6BACL,UAAU,kBACV,UAAU,gBAAc,mBAEX,0BAA0B,QAAQ,KAAG,KACnD,MACJ,oBAAoB"}
@@ -1,5 +1,4 @@
1
1
  import { useIntl as useIntl$1 } from "react-intl";
2
-
3
2
  //#region src/useIntl.d.ts
4
3
  /**
5
4
  * Drop-in for react-intl's `useIntl`.
@@ -1 +1 @@
1
- {"version":3,"file":"useIntl.d.ts","names":[],"sources":["../../src/useIntl.ts"],"mappings":";;;;;AAuBA;;;;AAUC;;;;;;;;cAVY,OAAA,SAAgB,SAU5B"}
1
+ {"version":3,"file":"useIntl.d.ts","names":[],"sources":["../../src/useIntl.ts"],"mappings":";;;;;;;;;;;;;;;;cAuBa,gBAAgB"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@intlayer/react-intl",
3
- "version": "9.0.0-canary.8",
3
+ "version": "9.0.0",
4
4
  "private": false,
5
5
  "description": "react-intl API adapter for intlayer — drop-in compatibility layer",
6
6
  "keywords": [
@@ -74,26 +74,26 @@
74
74
  "typecheck": "tsc --noEmit --project tsconfig.types.json"
75
75
  },
76
76
  "dependencies": {
77
- "@intlayer/chokidar": "9.0.0-canary.8",
78
- "@intlayer/config": "9.0.0-canary.8",
79
- "@intlayer/core": "9.0.0-canary.8",
80
- "@intlayer/dictionaries-entry": "9.0.0-canary.8",
81
- "@intlayer/types": "9.0.0-canary.8",
82
- "react-intlayer": "9.0.0-canary.8",
83
- "vite-intlayer": "9.0.0-canary.8"
77
+ "@intlayer/config": "9.0.0",
78
+ "@intlayer/core": "9.0.0",
79
+ "@intlayer/dictionaries-entry": "9.0.0",
80
+ "@intlayer/engine": "9.0.0",
81
+ "@intlayer/types": "9.0.0",
82
+ "react-intlayer": "9.0.0",
83
+ "vite-intlayer": "9.0.0"
84
84
  },
85
85
  "devDependencies": {
86
- "@types/node": "25.9.4",
86
+ "@types/node": "26.1.1",
87
87
  "@types/react": "19.1.8",
88
88
  "@utils/ts-config": "1.0.4",
89
89
  "@utils/ts-config-types": "1.0.4",
90
90
  "@utils/tsdown-config": "1.0.4",
91
- "react-intl": "^10.1.13",
91
+ "react-intl": "^10.1.18",
92
92
  "rimraf": "6.1.3",
93
- "tsdown": "0.22.2",
94
- "typescript": "6.0.3",
95
- "vite": "8.1.0",
96
- "vitest": "4.1.9"
93
+ "tsdown": "0.22.13",
94
+ "typescript": "7.0.2",
95
+ "vite": "8.1.5",
96
+ "vitest": "4.1.10"
97
97
  },
98
98
  "peerDependencies": {
99
99
  "react": ">=16.0.0",