@intlayer/core 9.3.0 → 9.3.1

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 (160) hide show
  1. package/README.md +24 -24
  2. package/dist/cjs/_virtual/_rolldown/runtime.cjs +1 -2
  3. package/dist/cjs/deepTransformPlugins/getReplacedValuesContent.cjs +2 -1
  4. package/dist/cjs/deepTransformPlugins/getReplacedValuesContent.cjs.map +1 -1
  5. package/dist/cjs/deepTransformPlugins/insertContentInDictionary.cjs +41 -32
  6. package/dist/cjs/deepTransformPlugins/insertContentInDictionary.cjs.map +1 -1
  7. package/dist/cjs/dictionaryManipulator/editDictionaryByKeyPath.cjs +6 -5
  8. package/dist/cjs/dictionaryManipulator/editDictionaryByKeyPath.cjs.map +1 -1
  9. package/dist/cjs/dictionaryManipulator/mergeDictionaries.cjs +4 -3
  10. package/dist/cjs/dictionaryManipulator/mergeDictionaries.cjs.map +1 -1
  11. package/dist/cjs/dictionaryManipulator/mergeQualifiedDictionaries.cjs.map +1 -1
  12. package/dist/cjs/dictionaryManipulator/qualifiedDictionary.cjs +0 -1
  13. package/dist/cjs/dictionaryManipulator/qualifiedDictionary.cjs.map +1 -1
  14. package/dist/cjs/dictionaryManipulator/qualifiedDictionary.test-d.cjs.map +1 -1
  15. package/dist/cjs/dictionaryManipulator/removeContentNodeByKeyPath.cjs +4 -2
  16. package/dist/cjs/dictionaryManipulator/removeContentNodeByKeyPath.cjs.map +1 -1
  17. package/dist/cjs/dictionaryManipulator/renameContentNodeByKeyPath.cjs +11 -9
  18. package/dist/cjs/dictionaryManipulator/renameContentNodeByKeyPath.cjs.map +1 -1
  19. package/dist/cjs/formatters/date.cjs +2 -1
  20. package/dist/cjs/formatters/date.cjs.map +1 -1
  21. package/dist/cjs/formatters/relativeTime.cjs +3 -3
  22. package/dist/cjs/formatters/relativeTime.cjs.map +1 -1
  23. package/dist/cjs/interpreter/getCondition.cjs +0 -1
  24. package/dist/cjs/interpreter/getCondition.cjs.map +1 -1
  25. package/dist/cjs/interpreter/getEnumeration.cjs +0 -1
  26. package/dist/cjs/interpreter/getEnumeration.cjs.map +1 -1
  27. package/dist/cjs/interpreter/getGender.cjs +0 -1
  28. package/dist/cjs/interpreter/getGender.cjs.map +1 -1
  29. package/dist/cjs/interpreter/getHTML.cjs +0 -1
  30. package/dist/cjs/interpreter/getHTML.cjs.map +1 -1
  31. package/dist/cjs/interpreter/getInsertion.cjs +0 -1
  32. package/dist/cjs/interpreter/getInsertion.cjs.map +1 -1
  33. package/dist/cjs/interpreter/getIntlayer.cjs.map +1 -1
  34. package/dist/cjs/interpreter/getIntlayer.test-d.cjs.map +1 -1
  35. package/dist/cjs/interpreter/getSelect.cjs +0 -1
  36. package/dist/cjs/interpreter/getSelect.cjs.map +1 -1
  37. package/dist/cjs/interpreter/getTranslation.cjs +0 -1
  38. package/dist/cjs/interpreter/getTranslation.cjs.map +1 -1
  39. package/dist/cjs/interpreter/splitAndJoinInsertion.cjs +0 -1
  40. package/dist/cjs/interpreter/splitAndJoinInsertion.cjs.map +1 -1
  41. package/dist/cjs/localization/domainUtils.cjs +0 -1
  42. package/dist/cjs/localization/domainUtils.cjs.map +1 -1
  43. package/dist/cjs/localization/getBrowserLocale.cjs +2 -1
  44. package/dist/cjs/localization/getBrowserLocale.cjs.map +1 -1
  45. package/dist/cjs/localization/getHTMLTextDir.cjs +0 -1
  46. package/dist/cjs/localization/getHTMLTextDir.cjs.map +1 -1
  47. package/dist/cjs/localization/getLocale.cjs +2 -1
  48. package/dist/cjs/localization/getLocale.cjs.map +1 -1
  49. package/dist/cjs/localization/getLocaleLang.cjs +0 -1
  50. package/dist/cjs/localization/getLocaleLang.cjs.map +1 -1
  51. package/dist/cjs/localization/localeDetector.cjs +2 -1
  52. package/dist/cjs/localization/localeDetector.cjs.map +1 -1
  53. package/dist/cjs/localization/proxyMode.cjs.map +1 -1
  54. package/dist/cjs/localization/rewriteUtils.cjs +0 -1
  55. package/dist/cjs/localization/rewriteUtils.cjs.map +1 -1
  56. package/dist/cjs/markdown/compiler.cjs +9 -6
  57. package/dist/cjs/markdown/compiler.cjs.map +1 -1
  58. package/dist/cjs/markdown/constants.cjs +0 -1
  59. package/dist/cjs/markdown/constants.cjs.map +1 -1
  60. package/dist/cjs/markdown/utils.cjs.map +1 -1
  61. package/dist/cjs/messageFormat/ICU.cjs +17 -14
  62. package/dist/cjs/messageFormat/ICU.cjs.map +1 -1
  63. package/dist/cjs/messageFormat/i18next.cjs +4 -2
  64. package/dist/cjs/messageFormat/i18next.cjs.map +1 -1
  65. package/dist/cjs/messageFormat/navigatePath.cjs +0 -1
  66. package/dist/cjs/messageFormat/navigatePath.cjs.map +1 -1
  67. package/dist/cjs/messageFormat/resolveMessage.cjs +2 -1
  68. package/dist/cjs/messageFormat/resolveMessage.cjs.map +1 -1
  69. package/dist/cjs/messageFormat/verify-icu-format.cjs +3 -2
  70. package/dist/cjs/messageFormat/verify-icu-format.cjs.map +1 -1
  71. package/dist/cjs/messageFormat/vue-i18n.cjs +2 -1
  72. package/dist/cjs/messageFormat/vue-i18n.cjs.map +1 -1
  73. package/dist/cjs/transpiler/condition/condition.cjs.map +1 -1
  74. package/dist/cjs/transpiler/enumeration/enumeration.cjs.map +1 -1
  75. package/dist/cjs/transpiler/file/file.cjs +2 -1
  76. package/dist/cjs/transpiler/file/file.cjs.map +1 -1
  77. package/dist/cjs/transpiler/file/fileBrowser.cjs +0 -1
  78. package/dist/cjs/transpiler/file/fileBrowser.cjs.map +1 -1
  79. package/dist/cjs/transpiler/gender/gender.cjs.map +1 -1
  80. package/dist/cjs/transpiler/html/getHTMLCustomComponents.cjs +0 -1
  81. package/dist/cjs/transpiler/html/getHTMLCustomComponents.cjs.map +1 -1
  82. package/dist/cjs/transpiler/html/html.cjs.map +1 -1
  83. package/dist/cjs/transpiler/html/htmlTags.cjs +0 -1
  84. package/dist/cjs/transpiler/html/htmlTags.cjs.map +1 -1
  85. package/dist/cjs/transpiler/html/validateHTML.cjs +12 -12
  86. package/dist/cjs/transpiler/html/validateHTML.cjs.map +1 -1
  87. package/dist/cjs/transpiler/insertion/getInsertionValues.cjs +0 -1
  88. package/dist/cjs/transpiler/insertion/getInsertionValues.cjs.map +1 -1
  89. package/dist/cjs/transpiler/insertion/insertion.cjs.map +1 -1
  90. package/dist/cjs/transpiler/markdown/getMarkdownMetadata.cjs +2 -1
  91. package/dist/cjs/transpiler/markdown/getMarkdownMetadata.cjs.map +1 -1
  92. package/dist/cjs/transpiler/markdown/markdown.cjs +2 -1
  93. package/dist/cjs/transpiler/markdown/markdown.cjs.map +1 -1
  94. package/dist/cjs/transpiler/markdown/validateMarkdown.cjs +7 -6
  95. package/dist/cjs/transpiler/markdown/validateMarkdown.cjs.map +1 -1
  96. package/dist/cjs/transpiler/nesting/nesting.cjs.map +1 -1
  97. package/dist/cjs/transpiler/plural/plural.cjs.map +1 -1
  98. package/dist/cjs/transpiler/select/select.cjs.map +1 -1
  99. package/dist/cjs/transpiler/translation/translation.cjs.map +1 -1
  100. package/dist/cjs/utils/checkIsURLAbsolute.cjs +0 -1
  101. package/dist/cjs/utils/checkIsURLAbsolute.cjs.map +1 -1
  102. package/dist/cjs/utils/cookieExpiry.cjs +0 -1
  103. package/dist/cjs/utils/cookieExpiry.cjs.map +1 -1
  104. package/dist/cjs/utils/getCookie.cjs +0 -1
  105. package/dist/cjs/utils/getCookie.cjs.map +1 -1
  106. package/dist/cjs/utils/isSameKeyPath.cjs +0 -1
  107. package/dist/cjs/utils/isSameKeyPath.cjs.map +1 -1
  108. package/dist/cjs/utils/isValidReactElement.cjs +0 -1
  109. package/dist/cjs/utils/isValidReactElement.cjs.map +1 -1
  110. package/dist/cjs/utils/parseYaml.cjs +0 -1
  111. package/dist/cjs/utils/parseYaml.cjs.map +1 -1
  112. package/dist/cjs/utils/stringifyYaml.cjs +0 -1
  113. package/dist/cjs/utils/stringifyYaml.cjs.map +1 -1
  114. package/dist/esm/deepTransformPlugins/getReplacedValuesContent.mjs +2 -1
  115. package/dist/esm/deepTransformPlugins/getReplacedValuesContent.mjs.map +1 -1
  116. package/dist/esm/deepTransformPlugins/insertContentInDictionary.mjs +41 -32
  117. package/dist/esm/deepTransformPlugins/insertContentInDictionary.mjs.map +1 -1
  118. package/dist/esm/dictionaryManipulator/editDictionaryByKeyPath.mjs +6 -5
  119. package/dist/esm/dictionaryManipulator/editDictionaryByKeyPath.mjs.map +1 -1
  120. package/dist/esm/dictionaryManipulator/mergeDictionaries.mjs +4 -3
  121. package/dist/esm/dictionaryManipulator/mergeDictionaries.mjs.map +1 -1
  122. package/dist/esm/dictionaryManipulator/removeContentNodeByKeyPath.mjs +4 -2
  123. package/dist/esm/dictionaryManipulator/removeContentNodeByKeyPath.mjs.map +1 -1
  124. package/dist/esm/dictionaryManipulator/renameContentNodeByKeyPath.mjs +11 -9
  125. package/dist/esm/dictionaryManipulator/renameContentNodeByKeyPath.mjs.map +1 -1
  126. package/dist/esm/formatters/date.mjs +2 -1
  127. package/dist/esm/formatters/date.mjs.map +1 -1
  128. package/dist/esm/formatters/relativeTime.mjs +3 -3
  129. package/dist/esm/formatters/relativeTime.mjs.map +1 -1
  130. package/dist/esm/localization/getBrowserLocale.mjs +2 -1
  131. package/dist/esm/localization/getBrowserLocale.mjs.map +1 -1
  132. package/dist/esm/localization/getLocale.mjs +2 -1
  133. package/dist/esm/localization/getLocale.mjs.map +1 -1
  134. package/dist/esm/localization/localeDetector.mjs +2 -1
  135. package/dist/esm/localization/localeDetector.mjs.map +1 -1
  136. package/dist/esm/markdown/compiler.mjs +9 -6
  137. package/dist/esm/markdown/compiler.mjs.map +1 -1
  138. package/dist/esm/markdown/utils.mjs.map +1 -1
  139. package/dist/esm/messageFormat/ICU.mjs +17 -14
  140. package/dist/esm/messageFormat/ICU.mjs.map +1 -1
  141. package/dist/esm/messageFormat/i18next.mjs +4 -2
  142. package/dist/esm/messageFormat/i18next.mjs.map +1 -1
  143. package/dist/esm/messageFormat/resolveMessage.mjs +2 -1
  144. package/dist/esm/messageFormat/resolveMessage.mjs.map +1 -1
  145. package/dist/esm/messageFormat/verify-icu-format.mjs +3 -2
  146. package/dist/esm/messageFormat/verify-icu-format.mjs.map +1 -1
  147. package/dist/esm/messageFormat/vue-i18n.mjs +2 -1
  148. package/dist/esm/messageFormat/vue-i18n.mjs.map +1 -1
  149. package/dist/esm/transpiler/file/file.mjs +2 -1
  150. package/dist/esm/transpiler/file/file.mjs.map +1 -1
  151. package/dist/esm/transpiler/html/validateHTML.mjs +12 -11
  152. package/dist/esm/transpiler/html/validateHTML.mjs.map +1 -1
  153. package/dist/esm/transpiler/markdown/getMarkdownMetadata.mjs +2 -1
  154. package/dist/esm/transpiler/markdown/getMarkdownMetadata.mjs.map +1 -1
  155. package/dist/esm/transpiler/markdown/markdown.mjs +2 -1
  156. package/dist/esm/transpiler/markdown/markdown.mjs.map +1 -1
  157. package/dist/esm/transpiler/markdown/validateMarkdown.mjs +7 -6
  158. package/dist/esm/transpiler/markdown/validateMarkdown.mjs.map +1 -1
  159. package/dist/esm/utils/parseYaml.mjs.map +1 -1
  160. package/package.json +6 -6
@@ -58,7 +58,8 @@ const detectLanguage = (order, options) => {
58
58
  };
59
59
  const navigatorDetector = () => {
60
60
  if (typeof navigator === "undefined") return;
61
- const locale = require_localization_localeDetector.localeDetector({ "accept-language": (navigator.languages ?? [navigator.language]).join(",") }, _intlayer_config_built.internationalization.locales, _intlayer_config_built.internationalization.defaultLocale);
61
+ const languages = navigator.languages ?? [navigator.language];
62
+ const locale = require_localization_localeDetector.localeDetector({ "accept-language": languages.join(",") }, _intlayer_config_built.internationalization.locales, _intlayer_config_built.internationalization.defaultLocale);
62
63
  if (locale) detected["navigator"] = locale;
63
64
  };
64
65
  const htmlTagDetector = () => {
@@ -1 +1 @@
1
- {"version":3,"file":"getBrowserLocale.cjs","names":["getLocaleFromStorageClient","localeDetector","internationalization","DEFAULT_LOCALE"],"sources":["../../../src/localization/getBrowserLocale.tsx"],"sourcesContent":["import { internationalization } from '@intlayer/config/built';\nimport { DEFAULT_LOCALE } from '@intlayer/config/defaultValues';\nimport type { Locale } from '@intlayer/types/allLocales';\nimport { getLocaleFromStorageClient } from '../utils/localeStorage';\nimport { localeDetector } from './localeDetector';\n\nexport enum LanguageDetector {\n Querystring = 'querystring',\n Storage = 'storage',\n Navigator = 'navigator',\n HtmlTag = 'htmlTag',\n}\n\n// Default settings for the language detector\ntype LanguageDetectorOptions = {\n order?: LanguageDetector[];\n lookupQuerystring?: string;\n htmlTag?: HTMLElement | null;\n};\n\nconst getDefaultsOptions = (): LanguageDetectorOptions => {\n return {\n order: [\n LanguageDetector.Querystring,\n LanguageDetector.Storage,\n LanguageDetector.Navigator,\n LanguageDetector.HtmlTag,\n ],\n lookupQuerystring: 'locale',\n htmlTag: typeof document !== 'undefined' ? document.documentElement : null,\n };\n};\n\nconst detectLanguage = (\n order: string[],\n options: LanguageDetectorOptions\n): Record<LanguageDetector, Locale | undefined> => {\n const detected: Record<LanguageDetector, Locale | undefined> = {} as Record<\n LanguageDetector,\n Locale | undefined\n >;\n\n const queryStringDetector = () => {\n // `window` exists in React Native but carries no `location`, so the\n // property must be probed rather than inferred from `window` alone.\n if (typeof window === 'undefined' || !window.location) return;\n const search = window.location.search || '';\n const params = new URLSearchParams(search);\n const value = params.get(options.lookupQuerystring ?? '');\n if (value) {\n detected[LanguageDetector.Querystring] = value as Locale;\n }\n };\n\n const storageDetector = () => {\n if (typeof window === 'undefined') return;\n\n const locale = getLocaleFromStorageClient({\n getCookie: (name: string) => {\n try {\n const cookies = document.cookie.split(';');\n const cookieName = `${name}=`;\n\n const cookie = cookies.find((cookie) =>\n cookie.trim().startsWith(cookieName)\n );\n\n if (cookie) {\n return cookie.split('=')[1]?.trim();\n }\n } catch {}\n return undefined;\n },\n getSessionStorage: (name: string) => {\n try {\n return window.sessionStorage.getItem(name) ?? undefined;\n } catch {}\n return undefined;\n },\n getLocaleStorage: (name: string) => {\n try {\n return window.localStorage.getItem(name) ?? undefined;\n } catch {}\n return undefined;\n },\n });\n\n if (locale) {\n detected[LanguageDetector.Storage] = locale;\n }\n };\n\n const navigatorDetector = () => {\n if (typeof navigator === 'undefined') return;\n\n const languages = navigator.languages ?? [navigator.language];\n\n // Use localeDetector to find the best matching locale\n const locale = localeDetector(\n { 'accept-language': languages.join(',') },\n internationalization.locales,\n internationalization.defaultLocale\n );\n\n if (locale) {\n detected[LanguageDetector.Navigator] = locale;\n }\n };\n\n const htmlTagDetector = () => {\n const htmlTag = options.htmlTag;\n if (htmlTag && typeof htmlTag.getAttribute === 'function') {\n const lang = htmlTag.getAttribute('lang');\n if (lang) {\n // Validate and resolve the locale\n\n const locale = localeDetector(\n { 'accept-language': lang },\n internationalization.locales,\n internationalization.defaultLocale\n );\n\n detected[LanguageDetector.HtmlTag] = locale;\n }\n }\n };\n\n // Map detector names to their corresponding functions\n const detectors: Record<string, () => void> = {\n [LanguageDetector.Querystring]: queryStringDetector,\n [LanguageDetector.Storage]: storageDetector,\n [LanguageDetector.Navigator]: navigatorDetector,\n [LanguageDetector.HtmlTag]: htmlTagDetector,\n };\n\n // Use the provided order to run each detector\n order.forEach((detectorName) => {\n detectors[detectorName]?.();\n });\n\n return detected;\n};\n\nconst getFirstAvailableLocale = (\n locales: Record<LanguageDetector, Locale | undefined>,\n order: LanguageDetector[]\n): Locale => {\n for (const detector of order) {\n const locale = locales[detector];\n\n if (locale && internationalization.locales.includes(locale)) {\n return locale;\n }\n }\n\n return internationalization?.defaultLocale ?? DEFAULT_LOCALE;\n};\n\n/**\n * Core language detector function for browser environments.\n *\n * Detects the user's preferred locale by checking multiple sources in order:\n * 1. Query string parameter\n * 2. Storage (cookies, localStorage, sessionStorage) - uses getLocaleFromStorage\n * 3. Navigator languages - uses localeDetector\n * 4. HTML lang attribute - uses localeDetector\n *\n * @param userOptions - Optional configuration for detection order and lookup keys\n * @returns The detected locale or the default locale\n *\n * @example\n * const locale = getBrowserLocale({ order: [LanguageDetector.Storage, LanguageDetector.Navigator] });\n */\nexport const getBrowserLocale = (\n userOptions: LanguageDetectorOptions | undefined = {}\n): Locale => {\n const options = { ...getDefaultsOptions(), ...userOptions };\n\n const locales = detectLanguage(options.order ?? [], options);\n\n return getFirstAvailableLocale(locales, options.order ?? []);\n};\n"],"mappings":";;;;;;;AAMA,IAAY,mBAAL;CACL;CACA;CACA;CACA;;AACF;AASA,MAAM,2BAAoD;CACxD,OAAO;EACL,OAAO;;;;;EAKP;EACA,mBAAmB;EACnB,SAAS,OAAO,aAAa,cAAc,SAAS,kBAAkB;CACxE;AACF;AAEA,MAAM,kBACJ,OACA,YACiD;CACjD,MAAM,WAAyD,CAAC;CAKhE,MAAM,4BAA4B;EAGhC,IAAI,OAAO,WAAW,eAAe,CAAC,OAAO,UAAU;EACvD,MAAM,SAAS,OAAO,SAAS,UAAU;EAEzC,MAAM,QAAQ,IADK,gBAAgB,MAChB,CAAC,CAAC,IAAI,QAAQ,qBAAqB,EAAE;EACxD,IAAI,OACF,0BAAyC;CAE7C;CAEA,MAAM,wBAAwB;EAC5B,IAAI,OAAO,WAAW,aAAa;EAEnC,MAAM,SAASA,uDAA2B;GACxC,YAAY,SAAiB;IAC3B,IAAI;KACF,MAAM,UAAU,SAAS,OAAO,MAAM,GAAG;KACzC,MAAM,aAAa,GAAG,KAAK;KAE3B,MAAM,SAAS,QAAQ,MAAM,WAC3B,OAAO,KAAK,CAAC,CAAC,WAAW,UAAU,CACrC;KAEA,IAAI,QACF,OAAO,OAAO,MAAM,GAAG,CAAC,CAAC,EAAE,EAAE,KAAK;IAEtC,QAAQ,CAAC;GAEX;GACA,oBAAoB,SAAiB;IACnC,IAAI;KACF,OAAO,OAAO,eAAe,QAAQ,IAAI,KAAK;IAChD,QAAQ,CAAC;GAEX;GACA,mBAAmB,SAAiB;IAClC,IAAI;KACF,OAAO,OAAO,aAAa,QAAQ,IAAI,KAAK;IAC9C,QAAQ,CAAC;GAEX;EACF,CAAC;EAED,IAAI,QACF,sBAAqC;CAEzC;CAEA,MAAM,0BAA0B;EAC9B,IAAI,OAAO,cAAc,aAAa;EAKtC,MAAM,SAASC,mDACb,EAAE,oBAJc,UAAU,aAAa,CAAC,UAAU,QAAQ,EAI5B,CAAC,KAAK,GAAG,EAAE,GACzCC,4CAAqB,SACrBA,4CAAqB,aACvB;EAEA,IAAI,QACF,wBAAuC;CAE3C;CAEA,MAAM,wBAAwB;EAC5B,MAAM,UAAU,QAAQ;EACxB,IAAI,WAAW,OAAO,QAAQ,iBAAiB,YAAY;GACzD,MAAM,OAAO,QAAQ,aAAa,MAAM;GACxC,IAAI,MAAM;IAGR,MAAM,SAASD,mDACb,EAAE,mBAAmB,KAAK,GAC1BC,4CAAqB,SACrBA,4CAAqB,aACvB;IAEA,sBAAqC;GACvC;EACF;CACF;CAGA,MAAM,YAAwC;mBACZ;eACJ;iBACE;eACF;CAC9B;CAGA,MAAM,SAAS,iBAAiB;EAC9B,UAAU,aAAa,GAAG;CAC5B,CAAC;CAED,OAAO;AACT;AAEA,MAAM,2BACJ,SACA,UACW;CACX,KAAK,MAAM,YAAY,OAAO;EAC5B,MAAM,SAAS,QAAQ;EAEvB,IAAI,UAAUA,4CAAqB,QAAQ,SAAS,MAAM,GACxD,OAAO;CAEX;CAEA,OAAOA,6CAAsB,iBAAiBC;AAChD;;;;;;;;;;;;;;;;AAiBA,MAAa,oBACX,cAAmD,CAAC,MACzC;CACX,MAAM,UAAU;EAAE,GAAG,mBAAmB;EAAG,GAAG;CAAY;CAE1D,MAAM,UAAU,eAAe,QAAQ,SAAS,CAAC,GAAG,OAAO;CAE3D,OAAO,wBAAwB,SAAS,QAAQ,SAAS,CAAC,CAAC;AAC7D"}
1
+ {"version":3,"file":"getBrowserLocale.cjs","names":["getLocaleFromStorageClient","localeDetector","internationalization","DEFAULT_LOCALE"],"sources":["../../../src/localization/getBrowserLocale.tsx"],"sourcesContent":["import { internationalization } from '@intlayer/config/built';\nimport { DEFAULT_LOCALE } from '@intlayer/config/defaultValues';\nimport type { Locale } from '@intlayer/types/allLocales';\nimport { getLocaleFromStorageClient } from '../utils/localeStorage';\nimport { localeDetector } from './localeDetector';\n\nexport enum LanguageDetector {\n Querystring = 'querystring',\n Storage = 'storage',\n Navigator = 'navigator',\n HtmlTag = 'htmlTag',\n}\n\n// Default settings for the language detector\ntype LanguageDetectorOptions = {\n order?: LanguageDetector[];\n lookupQuerystring?: string;\n htmlTag?: HTMLElement | null;\n};\n\nconst getDefaultsOptions = (): LanguageDetectorOptions => {\n return {\n order: [\n LanguageDetector.Querystring,\n LanguageDetector.Storage,\n LanguageDetector.Navigator,\n LanguageDetector.HtmlTag,\n ],\n lookupQuerystring: 'locale',\n htmlTag: typeof document !== 'undefined' ? document.documentElement : null,\n };\n};\n\nconst detectLanguage = (\n order: string[],\n options: LanguageDetectorOptions\n): Record<LanguageDetector, Locale | undefined> => {\n const detected: Record<LanguageDetector, Locale | undefined> = {} as Record<\n LanguageDetector,\n Locale | undefined\n >;\n\n const queryStringDetector = () => {\n // `window` exists in React Native but carries no `location`, so the\n // property must be probed rather than inferred from `window` alone.\n if (typeof window === 'undefined' || !window.location) return;\n const search = window.location.search || '';\n const params = new URLSearchParams(search);\n const value = params.get(options.lookupQuerystring ?? '');\n if (value) {\n detected[LanguageDetector.Querystring] = value as Locale;\n }\n };\n\n const storageDetector = () => {\n if (typeof window === 'undefined') return;\n\n const locale = getLocaleFromStorageClient({\n getCookie: (name: string) => {\n try {\n const cookies = document.cookie.split(';');\n const cookieName = `${name}=`;\n\n const cookie = cookies.find((cookie) =>\n cookie.trim().startsWith(cookieName)\n );\n\n if (cookie) {\n return cookie.split('=')[1]?.trim();\n }\n } catch {}\n return undefined;\n },\n getSessionStorage: (name: string) => {\n try {\n return window.sessionStorage.getItem(name) ?? undefined;\n } catch {}\n return undefined;\n },\n getLocaleStorage: (name: string) => {\n try {\n return window.localStorage.getItem(name) ?? undefined;\n } catch {}\n return undefined;\n },\n });\n\n if (locale) {\n detected[LanguageDetector.Storage] = locale;\n }\n };\n\n const navigatorDetector = () => {\n if (typeof navigator === 'undefined') return;\n\n const languages = navigator.languages ?? [navigator.language];\n\n // Use localeDetector to find the best matching locale\n const locale = localeDetector(\n { 'accept-language': languages.join(',') },\n internationalization.locales,\n internationalization.defaultLocale\n );\n\n if (locale) {\n detected[LanguageDetector.Navigator] = locale;\n }\n };\n\n const htmlTagDetector = () => {\n const htmlTag = options.htmlTag;\n if (htmlTag && typeof htmlTag.getAttribute === 'function') {\n const lang = htmlTag.getAttribute('lang');\n if (lang) {\n // Validate and resolve the locale\n\n const locale = localeDetector(\n { 'accept-language': lang },\n internationalization.locales,\n internationalization.defaultLocale\n );\n\n detected[LanguageDetector.HtmlTag] = locale;\n }\n }\n };\n\n // Map detector names to their corresponding functions\n const detectors: Record<string, () => void> = {\n [LanguageDetector.Querystring]: queryStringDetector,\n [LanguageDetector.Storage]: storageDetector,\n [LanguageDetector.Navigator]: navigatorDetector,\n [LanguageDetector.HtmlTag]: htmlTagDetector,\n };\n\n // Use the provided order to run each detector\n order.forEach((detectorName) => {\n detectors[detectorName]?.();\n });\n\n return detected;\n};\n\nconst getFirstAvailableLocale = (\n locales: Record<LanguageDetector, Locale | undefined>,\n order: LanguageDetector[]\n): Locale => {\n for (const detector of order) {\n const locale = locales[detector];\n\n if (locale && internationalization.locales.includes(locale)) {\n return locale;\n }\n }\n\n return internationalization?.defaultLocale ?? DEFAULT_LOCALE;\n};\n\n/**\n * Core language detector function for browser environments.\n *\n * Detects the user's preferred locale by checking multiple sources in order:\n * 1. Query string parameter\n * 2. Storage (cookies, localStorage, sessionStorage) - uses getLocaleFromStorage\n * 3. Navigator languages - uses localeDetector\n * 4. HTML lang attribute - uses localeDetector\n *\n * @param userOptions - Optional configuration for detection order and lookup keys\n * @returns The detected locale or the default locale\n *\n * @example\n * const locale = getBrowserLocale({ order: [LanguageDetector.Storage, LanguageDetector.Navigator] });\n */\nexport const getBrowserLocale = (\n userOptions: LanguageDetectorOptions | undefined = {}\n): Locale => {\n const options = { ...getDefaultsOptions(), ...userOptions };\n\n const locales = detectLanguage(options.order ?? [], options);\n\n return getFirstAvailableLocale(locales, options.order ?? []);\n};\n"],"mappings":";;;;;;;AAMA,IAAY,mBAAL;CACL;CACA;CACA;CACA;;AACF;AASA,MAAM,2BAAoD;CACxD,OAAO;EACL,OAAO;;;;;EAKP;EACA,mBAAmB;EACnB,SAAS,OAAO,aAAa,cAAc,SAAS,kBAAkB;CACxE;AACF;AAEA,MAAM,kBACJ,OACA,YACiD;CACjD,MAAM,WAAyD,CAAC;CAKhE,MAAM,4BAA4B;EAGhC,IAAI,OAAO,WAAW,eAAe,CAAC,OAAO,UAAU;EACvD,MAAM,SAAS,OAAO,SAAS,UAAU;EAEzC,MAAM,QAAQ,IADK,gBAAgB,MAChB,CAAC,CAAC,IAAI,QAAQ,qBAAqB,EAAE;EACxD,IAAI,OACF,0BAAyC;CAE7C;CAEA,MAAM,wBAAwB;EAC5B,IAAI,OAAO,WAAW,aAAa;EAEnC,MAAM,SAASA,uDAA2B;GACxC,YAAY,SAAiB;IAC3B,IAAI;KACF,MAAM,UAAU,SAAS,OAAO,MAAM,GAAG;KACzC,MAAM,aAAa,GAAG,KAAK;KAE3B,MAAM,SAAS,QAAQ,MAAM,WAC3B,OAAO,KAAK,CAAC,CAAC,WAAW,UAAU,CACrC;KAEA,IAAI,QACF,OAAO,OAAO,MAAM,GAAG,CAAC,CAAC,EAAE,EAAE,KAAK;IAEtC,QAAQ,CAAC;GAEX;GACA,oBAAoB,SAAiB;IACnC,IAAI;KACF,OAAO,OAAO,eAAe,QAAQ,IAAI,KAAK;IAChD,QAAQ,CAAC;GAEX;GACA,mBAAmB,SAAiB;IAClC,IAAI;KACF,OAAO,OAAO,aAAa,QAAQ,IAAI,KAAK;IAC9C,QAAQ,CAAC;GAEX;EACF,CAAC;EAED,IAAI,QACF,sBAAqC;CAEzC;CAEA,MAAM,0BAA0B;EAC9B,IAAI,OAAO,cAAc,aAAa;EAEtC,MAAM,YAAY,UAAU,aAAa,CAAC,UAAU,QAAQ;EAG5D,MAAM,SAASC,mDACb,EAAE,mBAAmB,UAAU,KAAK,GAAG,EAAE,GACzCC,4CAAqB,SACrBA,4CAAqB,aACvB;EAEA,IAAI,QACF,wBAAuC;CAE3C;CAEA,MAAM,wBAAwB;EAC5B,MAAM,UAAU,QAAQ;EACxB,IAAI,WAAW,OAAO,QAAQ,iBAAiB,YAAY;GACzD,MAAM,OAAO,QAAQ,aAAa,MAAM;GACxC,IAAI,MAAM;IAGR,MAAM,SAASD,mDACb,EAAE,mBAAmB,KAAK,GAC1BC,4CAAqB,SACrBA,4CAAqB,aACvB;IAEA,sBAAqC;GACvC;EACF;CACF;CAGA,MAAM,YAAwC;mBACZ;eACJ;iBACE;eACF;CAC9B;CAGA,MAAM,SAAS,iBAAiB;EAC9B,UAAU,aAAa,GAAG;CAC5B,CAAC;CAED,OAAO;AACT;AAEA,MAAM,2BACJ,SACA,UACW;CACX,KAAK,MAAM,YAAY,OAAO;EAC5B,MAAM,SAAS,QAAQ;EAEvB,IAAI,UAAUA,4CAAqB,QAAQ,SAAS,MAAM,GACxD,OAAO;CAEX;CAEA,OAAOA,6CAAsB,iBAAiBC;AAChD;;;;;;;;;;;;;;;;AAiBA,MAAa,oBACX,cAAmD,CAAC,MACzC;CACX,MAAM,UAAU;EAAE,GAAG,mBAAmB;EAAG,GAAG;CAAY;CAE1D,MAAM,UAAU,eAAe,QAAQ,SAAS,CAAC,GAAG,OAAO;CAE3D,OAAO,wBAAwB,SAAS,QAAQ,SAAS,CAAC,CAAC;AAC7D"}
@@ -1,5 +1,4 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
2
-
3
2
  //#region src/localization/getHTMLTextDir.ts
4
3
  /**
5
4
  * Returns the text direction of the given locale.
@@ -1 +1 @@
1
- {"version":3,"file":"getHTMLTextDir.cjs","names":[],"sources":["../../../src/localization/getHTMLTextDir.ts"],"sourcesContent":["import type { LocalesValues } from '@intlayer/types/module_augmentation';\n\ntype Dir = 'ltr' | 'rtl' | 'auto';\n\n/**\n * Returns the text direction of the given locale.\n *\n * Example:\n *\n * getHTMLTextDir('en-US') // 'ltr'\n * getHTMLTextDir('en') // 'ltr'\n * getHTMLTextDir('fr-CA') // 'ltr'\n * getHTMLTextDir('fr') // 'ltr'\n *\n * @param locale The locale to get the text direction for.\n * @returns The text direction of the given locale.\n */\nexport const getHTMLTextDir = (locale?: LocalesValues): Dir => {\n if (!locale) return 'ltr';\n\n try {\n const localeInfo = new Intl.Locale(locale);\n\n // Check for the 'textInfo' property (part of the Intl Enumeration API)\n // Most modern browsers support 'direction' via 'getTextInfo()' or 'textInfo'\n if ('getTextInfo' in localeInfo) {\n return (localeInfo as any).getTextInfo().direction as Dir;\n }\n\n // Fallback for environments supporting 'textInfo' property\n if ('textInfo' in localeInfo) {\n return (localeInfo as any).textInfo.direction as Dir;\n }\n\n // Manual fallback for older environments using script detection\n const maximized = localeInfo.maximize();\n const rtlScripts = [\n 'Arab',\n 'Hebr',\n 'Thaa',\n 'Syrc',\n 'Mand',\n 'Adlm',\n 'Rohg',\n 'Nkoo',\n ];\n\n return rtlScripts.includes(maximized.script ?? '') ? 'rtl' : 'ltr';\n } catch {\n return 'ltr';\n }\n};\n"],"mappings":";;;;;;;;;;;;;;;;AAiBA,MAAa,kBAAkB,WAAgC;CAC7D,IAAI,CAAC,QAAQ,OAAO;CAEpB,IAAI;EACF,MAAM,aAAa,IAAI,KAAK,OAAO,MAAM;EAIzC,IAAI,iBAAiB,YACnB,OAAQ,WAAmB,YAAY,CAAC,CAAC;EAI3C,IAAI,cAAc,YAChB,OAAQ,WAAmB,SAAS;EAItC,MAAM,YAAY,WAAW,SAAS;EAYtC,OAAO;GAVL;GACA;GACA;GACA;GACA;GACA;GACA;GACA;EAGc,CAAC,CAAC,SAAS,UAAU,UAAU,EAAE,IAAI,QAAQ;CAC/D,QAAQ;EACN,OAAO;CACT;AACF"}
1
+ {"version":3,"file":"getHTMLTextDir.cjs","names":[],"sources":["../../../src/localization/getHTMLTextDir.ts"],"sourcesContent":["import type { LocalesValues } from '@intlayer/types/module_augmentation';\n\ntype Dir = 'ltr' | 'rtl' | 'auto';\n\n/**\n * Returns the text direction of the given locale.\n *\n * Example:\n *\n * getHTMLTextDir('en-US') // 'ltr'\n * getHTMLTextDir('en') // 'ltr'\n * getHTMLTextDir('fr-CA') // 'ltr'\n * getHTMLTextDir('fr') // 'ltr'\n *\n * @param locale The locale to get the text direction for.\n * @returns The text direction of the given locale.\n */\nexport const getHTMLTextDir = (locale?: LocalesValues): Dir => {\n if (!locale) return 'ltr';\n\n try {\n const localeInfo = new Intl.Locale(locale);\n\n // Check for the 'textInfo' property (part of the Intl Enumeration API)\n // Most modern browsers support 'direction' via 'getTextInfo()' or 'textInfo'\n if ('getTextInfo' in localeInfo) {\n return (localeInfo as any).getTextInfo().direction as Dir;\n }\n\n // Fallback for environments supporting 'textInfo' property\n if ('textInfo' in localeInfo) {\n return (localeInfo as any).textInfo.direction as Dir;\n }\n\n // Manual fallback for older environments using script detection\n const maximized = localeInfo.maximize();\n const rtlScripts = [\n 'Arab',\n 'Hebr',\n 'Thaa',\n 'Syrc',\n 'Mand',\n 'Adlm',\n 'Rohg',\n 'Nkoo',\n ];\n\n return rtlScripts.includes(maximized.script ?? '') ? 'rtl' : 'ltr';\n } catch {\n return 'ltr';\n }\n};\n"],"mappings":";;;;;;;;;;;;;;;AAiBA,MAAa,kBAAkB,WAAgC;CAC7D,IAAI,CAAC,QAAQ,OAAO;CAEpB,IAAI;EACF,MAAM,aAAa,IAAI,KAAK,OAAO,MAAM;EAIzC,IAAI,iBAAiB,YACnB,OAAQ,WAAmB,YAAY,CAAC,CAAC;EAI3C,IAAI,cAAc,YAChB,OAAQ,WAAmB,SAAS;EAItC,MAAM,YAAY,WAAW,SAAS;EAYtC,OAAO;GAVL;GACA;GACA;GACA;GACA;GACA;GACA;GACA;EAGc,CAAC,CAAC,SAAS,UAAU,UAAU,EAAE,IAAI,QAAQ;CAC/D,QAAQ;EACN,OAAO;CACT;AACF"}
@@ -16,7 +16,8 @@ const getLocale = async (ctx = {}) => {
16
16
  if (storedLocale) return storedLocale;
17
17
  const acceptLanguageHeader = ctx.getHeader?.("accept-language");
18
18
  if (!acceptLanguageHeader) return defaultLocale;
19
- const userFallbackLocale = require_localization_localeResolver.localeResolver(require_localization_localeDetector.getPreferredLanguages(acceptLanguageHeader, availableLocales), availableLocales, defaultLocale);
19
+ const preferredLocaleStrings = require_localization_localeDetector.getPreferredLanguages(acceptLanguageHeader, availableLocales);
20
+ const userFallbackLocale = require_localization_localeResolver.localeResolver(preferredLocaleStrings, availableLocales, defaultLocale);
20
21
  if (userFallbackLocale) return userFallbackLocale;
21
22
  return defaultLocale;
22
23
  };
@@ -1 +1 @@
1
- {"version":3,"file":"getLocale.cjs","names":["internationalization","DEFAULT_LOCALE","LOCALES","getLocaleFromStorageServer","localeResolver","getPreferredLanguages"],"sources":["../../../src/localization/getLocale.ts"],"sourcesContent":["import { internationalization } from '@intlayer/config/built';\nimport { DEFAULT_LOCALE, LOCALES } from '@intlayer/config/defaultValues';\nimport type { Locale } from '@intlayer/types/allLocales';\nimport { getLocaleFromStorageServer } from '../utils/localeStorage';\nimport { getPreferredLanguages } from './localeDetector';\nimport { localeResolver } from './localeResolver';\n\nexport type RequestContext = {\n getHeader?: (name: string) => string | null | undefined;\n getCookie?: (name: string) => string | null | undefined;\n};\n\nexport const getLocale = async (ctx: RequestContext = {}): Promise<Locale> => {\n const defaultLocale = internationalization?.defaultLocale ?? DEFAULT_LOCALE;\n const availableLocales = internationalization?.locales ?? LOCALES;\n\n // Try locale from storage (cookie or header)\n const storedLocale = getLocaleFromStorageServer({\n getCookie: ctx.getCookie,\n getHeader: ctx.getHeader,\n });\n\n if (storedLocale) {\n return storedLocale;\n }\n\n // Fallback to Accept-Language negotiation\n const acceptLanguageHeader = ctx.getHeader?.('accept-language');\n\n if (!acceptLanguageHeader) {\n return defaultLocale;\n }\n\n const preferredLocaleStrings = getPreferredLanguages(\n acceptLanguageHeader,\n availableLocales\n );\n\n const userFallbackLocale = localeResolver(\n preferredLocaleStrings,\n availableLocales,\n defaultLocale\n );\n\n if (userFallbackLocale) {\n return userFallbackLocale;\n }\n\n // Default locale\n return defaultLocale;\n};\n"],"mappings":";;;;;;;;AAYA,MAAa,YAAY,OAAO,MAAsB,CAAC,MAAuB;CAC5E,MAAM,gBAAgBA,6CAAsB,iBAAiBC;CAC7D,MAAM,mBAAmBD,6CAAsB,WAAWE;CAG1D,MAAM,eAAeC,uDAA2B;EAC9C,WAAW,IAAI;EACf,WAAW,IAAI;CACjB,CAAC;CAED,IAAI,cACF,OAAO;CAIT,MAAM,uBAAuB,IAAI,YAAY,iBAAiB;CAE9D,IAAI,CAAC,sBACH,OAAO;CAQT,MAAM,qBAAqBC,mDALIC,0DAC7B,sBACA,gBAIqB,GACrB,kBACA,aACF;CAEA,IAAI,oBACF,OAAO;CAIT,OAAO;AACT"}
1
+ {"version":3,"file":"getLocale.cjs","names":["internationalization","DEFAULT_LOCALE","LOCALES","getLocaleFromStorageServer","getPreferredLanguages","localeResolver"],"sources":["../../../src/localization/getLocale.ts"],"sourcesContent":["import { internationalization } from '@intlayer/config/built';\nimport { DEFAULT_LOCALE, LOCALES } from '@intlayer/config/defaultValues';\nimport type { Locale } from '@intlayer/types/allLocales';\nimport { getLocaleFromStorageServer } from '../utils/localeStorage';\nimport { getPreferredLanguages } from './localeDetector';\nimport { localeResolver } from './localeResolver';\n\nexport type RequestContext = {\n getHeader?: (name: string) => string | null | undefined;\n getCookie?: (name: string) => string | null | undefined;\n};\n\nexport const getLocale = async (ctx: RequestContext = {}): Promise<Locale> => {\n const defaultLocale = internationalization?.defaultLocale ?? DEFAULT_LOCALE;\n const availableLocales = internationalization?.locales ?? LOCALES;\n\n // Try locale from storage (cookie or header)\n const storedLocale = getLocaleFromStorageServer({\n getCookie: ctx.getCookie,\n getHeader: ctx.getHeader,\n });\n\n if (storedLocale) {\n return storedLocale;\n }\n\n // Fallback to Accept-Language negotiation\n const acceptLanguageHeader = ctx.getHeader?.('accept-language');\n\n if (!acceptLanguageHeader) {\n return defaultLocale;\n }\n\n const preferredLocaleStrings = getPreferredLanguages(\n acceptLanguageHeader,\n availableLocales\n );\n\n const userFallbackLocale = localeResolver(\n preferredLocaleStrings,\n availableLocales,\n defaultLocale\n );\n\n if (userFallbackLocale) {\n return userFallbackLocale;\n }\n\n // Default locale\n return defaultLocale;\n};\n"],"mappings":";;;;;;;;AAYA,MAAa,YAAY,OAAO,MAAsB,CAAC,MAAuB;CAC5E,MAAM,gBAAgBA,6CAAsB,iBAAiBC;CAC7D,MAAM,mBAAmBD,6CAAsB,WAAWE;CAG1D,MAAM,eAAeC,uDAA2B;EAC9C,WAAW,IAAI;EACf,WAAW,IAAI;CACjB,CAAC;CAED,IAAI,cACF,OAAO;CAIT,MAAM,uBAAuB,IAAI,YAAY,iBAAiB;CAE9D,IAAI,CAAC,sBACH,OAAO;CAGT,MAAM,yBAAyBC,0DAC7B,sBACA,gBACF;CAEA,MAAM,qBAAqBC,mDACzB,wBACA,kBACA,aACF;CAEA,IAAI,oBACF,OAAO;CAIT,OAAO;AACT"}
@@ -1,5 +1,4 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
2
-
3
2
  //#region src/localization/getLocaleLang.ts
4
3
  /**
5
4
  * Returns the language code of the given locale for locales including the country code.
@@ -1 +1 @@
1
- {"version":3,"file":"getLocaleLang.cjs","names":[],"sources":["../../../src/localization/getLocaleLang.ts"],"sourcesContent":["import type {\n GetLocaleLang,\n LocalesValues,\n} from '@intlayer/types/module_augmentation';\n\n/**\n * Returns the language code of the given locale for locales including the country code.\n *\n * Example:\n *\n * getLocaleLang('en-US') // 'en'\n * getLocaleLang('en') // 'en'\n * getLocaleLang('fr-CA') // 'fr'\n * getLocaleLang('fr') // 'fr'\n *\n * @param locale The locale to get the language code for.\n * @returns The language code of the given locale.\n */\nexport const getLocaleLang = <const L extends LocalesValues>(\n locale?: L\n): GetLocaleLang<L & string> =>\n (locale?.split('-')[0] ?? '') as GetLocaleLang<L & string>;\n"],"mappings":";;;;;;;;;;;;;;;;AAkBA,MAAa,iBACX,WAEC,QAAQ,MAAM,GAAG,CAAC,CAAC,MAAM"}
1
+ {"version":3,"file":"getLocaleLang.cjs","names":[],"sources":["../../../src/localization/getLocaleLang.ts"],"sourcesContent":["import type {\n GetLocaleLang,\n LocalesValues,\n} from '@intlayer/types/module_augmentation';\n\n/**\n * Returns the language code of the given locale for locales including the country code.\n *\n * Example:\n *\n * getLocaleLang('en-US') // 'en'\n * getLocaleLang('en') // 'en'\n * getLocaleLang('fr-CA') // 'fr'\n * getLocaleLang('fr') // 'fr'\n *\n * @param locale The locale to get the language code for.\n * @returns The language code of the given locale.\n */\nexport const getLocaleLang = <const L extends LocalesValues>(\n locale?: L\n): GetLocaleLang<L & string> =>\n (locale?.split('-')[0] ?? '') as GetLocaleLang<L & string>;\n"],"mappings":";;;;;;;;;;;;;;;AAkBA,MAAa,iBACX,WAEC,QAAQ,MAAM,GAAG,CAAC,CAAC,MAAM"}
@@ -115,7 +115,8 @@ const getPreferredLanguages = (acceptHeader, availableLanguages) => {
115
115
  */
116
116
  const localeDetector = (headers, availableLocales, defaultLocale) => {
117
117
  const acceptLanguageHeader = headers["accept-language"];
118
- return require_localization_localeResolver.localeResolver(getPreferredLanguages(acceptLanguageHeader, availableLocales), availableLocales, defaultLocale);
118
+ const preferredLocaleStrings = getPreferredLanguages(acceptLanguageHeader, availableLocales);
119
+ return require_localization_localeResolver.localeResolver(preferredLocaleStrings, availableLocales, defaultLocale);
119
120
  };
120
121
 
121
122
  //#endregion
@@ -1 +1 @@
1
- {"version":3,"file":"localeDetector.cjs","names":["localeResolver"],"sources":["../../../src/localization/localeDetector.ts"],"sourcesContent":["import type { Locale } from '@intlayer/types/allLocales';\nimport { localeResolver } from './localeResolver';\n\n/**\n * Constants\n */\nconst LANGUAGE_FORMAT_REGULAR_EXPRESSION =\n /^\\s*([^\\s\\-;]+)(?:-([^\\s;]+))?\\s*(?:;(.*))?$/;\nconst DEFAULT_QUALITY_SCORE = 1;\n\n/**\n * Enumeration for specificity weights.\n * Higher values indicate a more precise match.\n */\nenum SpecificityWeight {\n None = 0,\n Broad = 1, // Matches prefix (e.g., 'en' matches 'en-US')\n Prefix = 2, // Matches prefix in reverse (e.g., 'en-US' matches 'en')\n Exact = 4, // Matches exact string (e.g., 'en-US' matches 'en-US')\n}\n\n/**\n * Represents a parsed language tag from the header.\n */\ntype LanguagePreference = {\n languageCode: string;\n regionCode?: string;\n fullLocale: string;\n qualityScore: number;\n originalIndex: number;\n};\n\n/**\n * Represents the result of matching a requested language against an available language.\n */\ntype MatchResult = {\n providedIndex: number;\n headerIndex: number;\n qualityScore: number;\n specificityScore: number;\n};\n\n/**\n * Parses a single language tag string from the Accept-Language header.\n * Example input: \"en-US;q=0.8\"\n */\nconst parseLanguageTag = (\n tagString: string,\n index: number\n): LanguagePreference | null => {\n const match = LANGUAGE_FORMAT_REGULAR_EXPRESSION.exec(tagString);\n if (!match) {\n return null;\n }\n\n const languageCode = match[1];\n const regionCode = match[2];\n const parameters = match[3];\n\n // Construct the full locale string (e.g., \"en-US\" or \"en\")\n const fullLocale = regionCode\n ? `${languageCode}-${regionCode}`\n : languageCode;\n\n let qualityScore = DEFAULT_QUALITY_SCORE;\n\n // Parse parameters to find the quality score (\"q\")\n if (parameters) {\n const parameterList = parameters.split(';');\n for (const parameter of parameterList) {\n const [key, value] = parameter.split('=');\n if (key === 'q') {\n qualityScore = parseFloat(value);\n }\n }\n }\n\n return {\n languageCode,\n regionCode,\n qualityScore,\n originalIndex: index,\n fullLocale,\n };\n};\n\n/**\n * Parses the entire Accept-Language header string into a list of preferences.\n */\nconst parseAcceptLanguageHeader = (\n headerValue: string\n): LanguagePreference[] => {\n const rawTags = headerValue.split(',');\n const preferences: LanguagePreference[] = [];\n\n for (let index = 0; index < rawTags.length; index++) {\n const tag = rawTags[index].trim();\n const parsedLanguage = parseLanguageTag(tag, index);\n\n if (parsedLanguage) {\n preferences.push(parsedLanguage);\n }\n }\n\n return preferences;\n};\n\n/**\n * Calculates the specificity of a match between a provided language and a requested preference.\n */\nconst calculateMatchSpecificity = (\n providedLanguage: string,\n preference: LanguagePreference,\n providedIndex: number\n): MatchResult | null => {\n const parsedProvided = parseLanguageTag(providedLanguage, providedIndex);\n if (!parsedProvided) {\n return null;\n }\n\n let specificityScore = SpecificityWeight.None;\n\n const preferenceFullLower = preference.fullLocale.toLowerCase();\n const preferencePrefixLower = preference.languageCode.toLowerCase();\n const providedFullLower = parsedProvided.fullLocale.toLowerCase();\n const providedPrefixLower = parsedProvided.languageCode.toLowerCase();\n\n if (preferenceFullLower === providedFullLower) {\n specificityScore |= SpecificityWeight.Exact;\n } else if (preferencePrefixLower === providedFullLower) {\n specificityScore |= SpecificityWeight.Prefix;\n } else if (preferenceFullLower === providedPrefixLower) {\n specificityScore |= SpecificityWeight.Broad;\n } else if (preference.fullLocale !== '*') {\n return null;\n }\n\n return {\n providedIndex,\n headerIndex: preference.originalIndex,\n qualityScore: preference.qualityScore,\n specificityScore,\n };\n};\n\n/**\n * Determines the best match for a specific available language against the list of user accepted languages.\n */\nconst getBestMatchForLanguage = (\n providedLanguage: string,\n acceptedPreferences: LanguagePreference[],\n providedIndex: number\n): MatchResult => {\n // Initialize with a non-match priority\n let bestMatch: MatchResult = {\n headerIndex: -1,\n qualityScore: 0,\n specificityScore: 0,\n providedIndex,\n };\n\n for (const preference of acceptedPreferences) {\n const matchSpec = calculateMatchSpecificity(\n providedLanguage,\n preference,\n providedIndex\n );\n\n if (matchSpec) {\n // Compare current best match with new match\n const scoreDifference =\n bestMatch.specificityScore - matchSpec.specificityScore ||\n bestMatch.qualityScore - matchSpec.qualityScore ||\n bestMatch.headerIndex - matchSpec.headerIndex;\n\n // If the new match is better (difference < 0), update priority\n if (scoreDifference < 0) {\n bestMatch = matchSpec;\n }\n }\n }\n\n return bestMatch;\n};\n\n/**\n * Comparator function to sort language matches.\n * Sorting order:\n * 1. Quality Score (Descending)\n * 2. Specificity Score (Descending)\n * 3. Order in Header (Ascending - lower index is better)\n * 4. Order in Provided List (Ascending)\n */\nconst compareMatchResults = (a: MatchResult, b: MatchResult): number => {\n return (\n b.qualityScore - a.qualityScore ||\n b.specificityScore - a.specificityScore ||\n a.headerIndex - b.headerIndex ||\n a.providedIndex - b.providedIndex ||\n 0\n );\n};\n\n/**\n * Derives the list of preferred languages based on the Accept-Language header\n * and an optional list of available languages.\n */\nexport const getPreferredLanguages = (\n acceptHeader: string | undefined,\n availableLanguages?: string[]\n): string[] => {\n // RFC 2616 sec 14.4: no header implies '*'\n const headerValue = acceptHeader === undefined ? '*' : acceptHeader || '';\n const acceptedPreferences = parseAcceptLanguageHeader(headerValue);\n\n // If no specific languages are provided to filter against, return the header languages sorted by quality\n if (!availableLanguages) {\n return acceptedPreferences\n .filter((preference) => preference.qualityScore > 0)\n .sort((a, b) => b.qualityScore - a.qualityScore) // Simple sort by quality\n .map((preference) => preference.fullLocale);\n }\n\n // Map available languages to their match priority against the header\n const matchResults = availableLanguages.map((language, index) =>\n getBestMatchForLanguage(language, acceptedPreferences, index)\n );\n\n return matchResults\n .filter((result) => result.qualityScore > 0)\n .sort(compareMatchResults)\n .map((result) => availableLanguages[result.providedIndex]);\n};\n\n/**\n * Detects the locale from the request headers.\n *\n * Headers are provided by the browser/client and can be used to determine the user's preferred language.\n * This function intersects the user's `Accept-Language` header with the application's available locales.\n */\nexport const localeDetector = (\n headers: Record<string, string | undefined>,\n availableLocales?: Locale[],\n defaultLocale?: Locale\n): Locale => {\n const acceptLanguageHeader = headers['accept-language'];\n\n const preferredLocaleStrings = getPreferredLanguages(\n acceptLanguageHeader,\n availableLocales as string[]\n );\n\n return localeResolver(\n preferredLocaleStrings as Locale[],\n availableLocales,\n defaultLocale\n );\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"localeDetector.cjs","names":["localeResolver"],"sources":["../../../src/localization/localeDetector.ts"],"sourcesContent":["import type { Locale } from '@intlayer/types/allLocales';\nimport { localeResolver } from './localeResolver';\n\n/**\n * Constants\n */\nconst LANGUAGE_FORMAT_REGULAR_EXPRESSION =\n /^\\s*([^\\s\\-;]+)(?:-([^\\s;]+))?\\s*(?:;(.*))?$/;\nconst DEFAULT_QUALITY_SCORE = 1;\n\n/**\n * Enumeration for specificity weights.\n * Higher values indicate a more precise match.\n */\nenum SpecificityWeight {\n None = 0,\n Broad = 1, // Matches prefix (e.g., 'en' matches 'en-US')\n Prefix = 2, // Matches prefix in reverse (e.g., 'en-US' matches 'en')\n Exact = 4, // Matches exact string (e.g., 'en-US' matches 'en-US')\n}\n\n/**\n * Represents a parsed language tag from the header.\n */\ntype LanguagePreference = {\n languageCode: string;\n regionCode?: string;\n fullLocale: string;\n qualityScore: number;\n originalIndex: number;\n};\n\n/**\n * Represents the result of matching a requested language against an available language.\n */\ntype MatchResult = {\n providedIndex: number;\n headerIndex: number;\n qualityScore: number;\n specificityScore: number;\n};\n\n/**\n * Parses a single language tag string from the Accept-Language header.\n * Example input: \"en-US;q=0.8\"\n */\nconst parseLanguageTag = (\n tagString: string,\n index: number\n): LanguagePreference | null => {\n const match = LANGUAGE_FORMAT_REGULAR_EXPRESSION.exec(tagString);\n if (!match) {\n return null;\n }\n\n const languageCode = match[1];\n const regionCode = match[2];\n const parameters = match[3];\n\n // Construct the full locale string (e.g., \"en-US\" or \"en\")\n const fullLocale = regionCode\n ? `${languageCode}-${regionCode}`\n : languageCode;\n\n let qualityScore = DEFAULT_QUALITY_SCORE;\n\n // Parse parameters to find the quality score (\"q\")\n if (parameters) {\n const parameterList = parameters.split(';');\n for (const parameter of parameterList) {\n const [key, value] = parameter.split('=');\n if (key === 'q') {\n qualityScore = parseFloat(value);\n }\n }\n }\n\n return {\n languageCode,\n regionCode,\n qualityScore,\n originalIndex: index,\n fullLocale,\n };\n};\n\n/**\n * Parses the entire Accept-Language header string into a list of preferences.\n */\nconst parseAcceptLanguageHeader = (\n headerValue: string\n): LanguagePreference[] => {\n const rawTags = headerValue.split(',');\n const preferences: LanguagePreference[] = [];\n\n for (let index = 0; index < rawTags.length; index++) {\n const tag = rawTags[index].trim();\n const parsedLanguage = parseLanguageTag(tag, index);\n\n if (parsedLanguage) {\n preferences.push(parsedLanguage);\n }\n }\n\n return preferences;\n};\n\n/**\n * Calculates the specificity of a match between a provided language and a requested preference.\n */\nconst calculateMatchSpecificity = (\n providedLanguage: string,\n preference: LanguagePreference,\n providedIndex: number\n): MatchResult | null => {\n const parsedProvided = parseLanguageTag(providedLanguage, providedIndex);\n if (!parsedProvided) {\n return null;\n }\n\n let specificityScore = SpecificityWeight.None;\n\n const preferenceFullLower = preference.fullLocale.toLowerCase();\n const preferencePrefixLower = preference.languageCode.toLowerCase();\n const providedFullLower = parsedProvided.fullLocale.toLowerCase();\n const providedPrefixLower = parsedProvided.languageCode.toLowerCase();\n\n if (preferenceFullLower === providedFullLower) {\n specificityScore |= SpecificityWeight.Exact;\n } else if (preferencePrefixLower === providedFullLower) {\n specificityScore |= SpecificityWeight.Prefix;\n } else if (preferenceFullLower === providedPrefixLower) {\n specificityScore |= SpecificityWeight.Broad;\n } else if (preference.fullLocale !== '*') {\n return null;\n }\n\n return {\n providedIndex,\n headerIndex: preference.originalIndex,\n qualityScore: preference.qualityScore,\n specificityScore,\n };\n};\n\n/**\n * Determines the best match for a specific available language against the list of user accepted languages.\n */\nconst getBestMatchForLanguage = (\n providedLanguage: string,\n acceptedPreferences: LanguagePreference[],\n providedIndex: number\n): MatchResult => {\n // Initialize with a non-match priority\n let bestMatch: MatchResult = {\n headerIndex: -1,\n qualityScore: 0,\n specificityScore: 0,\n providedIndex,\n };\n\n for (const preference of acceptedPreferences) {\n const matchSpec = calculateMatchSpecificity(\n providedLanguage,\n preference,\n providedIndex\n );\n\n if (matchSpec) {\n // Compare current best match with new match\n const scoreDifference =\n bestMatch.specificityScore - matchSpec.specificityScore ||\n bestMatch.qualityScore - matchSpec.qualityScore ||\n bestMatch.headerIndex - matchSpec.headerIndex;\n\n // If the new match is better (difference < 0), update priority\n if (scoreDifference < 0) {\n bestMatch = matchSpec;\n }\n }\n }\n\n return bestMatch;\n};\n\n/**\n * Comparator function to sort language matches.\n * Sorting order:\n * 1. Quality Score (Descending)\n * 2. Specificity Score (Descending)\n * 3. Order in Header (Ascending - lower index is better)\n * 4. Order in Provided List (Ascending)\n */\nconst compareMatchResults = (a: MatchResult, b: MatchResult): number => {\n return (\n b.qualityScore - a.qualityScore ||\n b.specificityScore - a.specificityScore ||\n a.headerIndex - b.headerIndex ||\n a.providedIndex - b.providedIndex ||\n 0\n );\n};\n\n/**\n * Derives the list of preferred languages based on the Accept-Language header\n * and an optional list of available languages.\n */\nexport const getPreferredLanguages = (\n acceptHeader: string | undefined,\n availableLanguages?: string[]\n): string[] => {\n // RFC 2616 sec 14.4: no header implies '*'\n const headerValue = acceptHeader === undefined ? '*' : acceptHeader || '';\n const acceptedPreferences = parseAcceptLanguageHeader(headerValue);\n\n // If no specific languages are provided to filter against, return the header languages sorted by quality\n if (!availableLanguages) {\n return acceptedPreferences\n .filter((preference) => preference.qualityScore > 0)\n .sort((a, b) => b.qualityScore - a.qualityScore) // Simple sort by quality\n .map((preference) => preference.fullLocale);\n }\n\n // Map available languages to their match priority against the header\n const matchResults = availableLanguages.map((language, index) =>\n getBestMatchForLanguage(language, acceptedPreferences, index)\n );\n\n return matchResults\n .filter((result) => result.qualityScore > 0)\n .sort(compareMatchResults)\n .map((result) => availableLanguages[result.providedIndex]);\n};\n\n/**\n * Detects the locale from the request headers.\n *\n * Headers are provided by the browser/client and can be used to determine the user's preferred language.\n * This function intersects the user's `Accept-Language` header with the application's available locales.\n */\nexport const localeDetector = (\n headers: Record<string, string | undefined>,\n availableLocales?: Locale[],\n defaultLocale?: Locale\n): Locale => {\n const acceptLanguageHeader = headers['accept-language'];\n\n const preferredLocaleStrings = getPreferredLanguages(\n acceptLanguageHeader,\n availableLocales as string[]\n );\n\n return localeResolver(\n preferredLocaleStrings as Locale[],\n availableLocales,\n defaultLocale\n );\n};\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"proxyMode.cjs","names":["ANSIColors"],"sources":["../../../src/localization/proxyMode.ts"],"sourcesContent":["import * as ANSIColors from '@intlayer/config/colors';\nimport { colorize } from '@intlayer/config/logger';\n\n/**\n * Effective mode of the Intlayer locale-routing proxy, resolved from the\n * `routing.enableProxy` configuration option.\n *\n * - `'auto'` — the option was left unset. The proxy is registered, but it stays\n * URL-driven while a development or preview server is serving the app: the\n * stored locale (cookie / header) is not used as a redirect source, so a\n * stale cookie cannot silently pull every navigation to another locale. In\n * production the mode behaves exactly like `'forced'`.\n * - `'forced'` — the option was explicitly set to `true`. Full proxy behaviour\n * in every environment, storage-driven redirects included.\n * - `'disabled'` — the option was explicitly set to `false`. The proxy is not\n * registered at all (Vite) or becomes a pass-through (Next.js).\n */\nexport type ProxyMode = 'auto' | 'forced' | 'disabled';\n\n/**\n * Resolves the effective {@link ProxyMode} from the `routing.enableProxy`\n * configuration value.\n *\n * `process.env.INTLAYER_ROUTING_ENABLE_PROXY` is injected at build time by\n * `getConfigEnvVars` and takes precedence, so bundlers can dead-code-eliminate\n * the branches guarded by the resolved mode. The variable is only emitted for\n * the two explicit states; its absence means `'auto'` and defers to the\n * configuration value read at runtime.\n *\n * @param enableProxy - The `routing.enableProxy` value; `undefined` means auto.\n * @returns The resolved proxy mode.\n *\n * @example\n * ```ts\n * resolveProxyMode(undefined); // 'auto'\n * resolveProxyMode(true); // 'forced'\n * resolveProxyMode(false); // 'disabled'\n * ```\n */\nexport const resolveProxyMode = (enableProxy?: boolean): ProxyMode => {\n if (process.env.INTLAYER_ROUTING_ENABLE_PROXY === 'false') return 'disabled';\n if (process.env.INTLAYER_ROUTING_ENABLE_PROXY === 'true') return 'forced';\n\n if (enableProxy === false) return 'disabled';\n if (enableProxy === true) return 'forced';\n\n return 'auto';\n};\n\n/**\n * Indicates whether the proxy may use the locale held in storage (cookie or\n * header) as a source when deciding which locale a request resolves to.\n *\n * Auto mode suppresses it on development and preview servers only. Every other\n * combination keeps the stored locale active, which notably preserves the\n * behaviour of `createIntlayerProxyHandler` when it is mounted manually in a\n * production Nitro server.\n *\n * Suppressing the read affects redirect *sources* only — the locale is still\n * persisted onto responses, the URL locale prefix still wins over everything,\n * and `Accept-Language` detection still applies as the fallback.\n *\n * @param proxyMode - The resolved proxy mode.\n * @param isDevServer - Whether a development or preview server is serving the app.\n * @returns `true` when the stored locale may drive locale resolution.\n *\n * @example\n * ```ts\n * isProxyStorageLocaleEnabled('auto', true); // false — dev server, URL-driven only\n * isProxyStorageLocaleEnabled('auto', false); // true — production\n * isProxyStorageLocaleEnabled('forced', true); // true — explicitly opted in\n * ```\n */\nexport const isProxyStorageLocaleEnabled = (\n proxyMode: ProxyMode,\n isDevServer: boolean\n): boolean => !(proxyMode === 'auto' && isDevServer);\n\n/**\n * Builds the line announcing that a server has mounted the locale-routing\n * proxy.\n *\n * Shared by every integration (Vite plugin, Next.js middleware) so the reported\n * state cannot drift between them: when the stored locale is suppressed the\n * message says so, which would otherwise look like a broken proxy to anyone\n * testing locale switching with a cookie already set.\n *\n * Takes the suppression flag rather than the {@link ProxyMode} on purpose. Auto\n * mode only suppresses storage on a dev server, so a mode-based signature would\n * let a production caller — such as the Nitro production handler — announce a\n * suppression that is not actually in effect.\n *\n * @param isStorageLocaleSuppressed - Whether the stored locale is barred from\n * driving redirects, i.e. the negation of {@link isProxyStorageLocaleEnabled}.\n * @returns An ANSI-coloured, ready-to-log message.\n *\n * @example\n * ```ts\n * formatProxyEnabledMessage(true);\n * // Intlayer proxy enabled - storage redirection disabled for dev purpose\n * formatProxyEnabledMessage(false);\n * // Intlayer proxy enabled\n * ```\n */\nexport const formatProxyEnabledMessage = (\n isStorageLocaleSuppressed: boolean\n): string =>\n [\n `Intlayer proxy ${colorize('enabled', ANSIColors.GREEN)}`,\n isStorageLocaleSuppressed &&\n colorize(\n '- storage redirection disabled for dev purpose',\n ANSIColors.GREY\n ),\n ]\n .filter(Boolean)\n .join(' ');\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;AAuCA,MAAa,oBAAoB,gBAAqC;CACpE,IAAI,QAAQ,IAAI,kCAAkC,SAAS,OAAO;CAClE,IAAI,QAAQ,IAAI,kCAAkC,QAAQ,OAAO;CAEjE,IAAI,gBAAgB,OAAO,OAAO;CAClC,IAAI,gBAAgB,MAAM,OAAO;CAEjC,OAAO;AACT;;;;;;;;;;;;;;;;;;;;;;;;;AA0BA,MAAa,+BACX,WACA,gBACY,EAAE,cAAc,UAAU;;;;;;;;;;;;;;;;;;;;;;;;;;;AA4BxC,MAAa,6BACX,8BAEA,CACE,wDAA2B,WAAWA,wBAAW,KAAK,KACtD,mEAEI,kDACAA,wBAAW,IACb,CACJ,CAAC,CACE,OAAO,OAAO,CAAC,CACf,KAAK,GAAG"}
1
+ {"version":3,"file":"proxyMode.cjs","names":["colorize","ANSIColors"],"sources":["../../../src/localization/proxyMode.ts"],"sourcesContent":["import * as ANSIColors from '@intlayer/config/colors';\nimport { colorize } from '@intlayer/config/logger';\n\n/**\n * Effective mode of the Intlayer locale-routing proxy, resolved from the\n * `routing.enableProxy` configuration option.\n *\n * - `'auto'` — the option was left unset. The proxy is registered, but it stays\n * URL-driven while a development or preview server is serving the app: the\n * stored locale (cookie / header) is not used as a redirect source, so a\n * stale cookie cannot silently pull every navigation to another locale. In\n * production the mode behaves exactly like `'forced'`.\n * - `'forced'` — the option was explicitly set to `true`. Full proxy behaviour\n * in every environment, storage-driven redirects included.\n * - `'disabled'` — the option was explicitly set to `false`. The proxy is not\n * registered at all (Vite) or becomes a pass-through (Next.js).\n */\nexport type ProxyMode = 'auto' | 'forced' | 'disabled';\n\n/**\n * Resolves the effective {@link ProxyMode} from the `routing.enableProxy`\n * configuration value.\n *\n * `process.env.INTLAYER_ROUTING_ENABLE_PROXY` is injected at build time by\n * `getConfigEnvVars` and takes precedence, so bundlers can dead-code-eliminate\n * the branches guarded by the resolved mode. The variable is only emitted for\n * the two explicit states; its absence means `'auto'` and defers to the\n * configuration value read at runtime.\n *\n * @param enableProxy - The `routing.enableProxy` value; `undefined` means auto.\n * @returns The resolved proxy mode.\n *\n * @example\n * ```ts\n * resolveProxyMode(undefined); // 'auto'\n * resolveProxyMode(true); // 'forced'\n * resolveProxyMode(false); // 'disabled'\n * ```\n */\nexport const resolveProxyMode = (enableProxy?: boolean): ProxyMode => {\n if (process.env.INTLAYER_ROUTING_ENABLE_PROXY === 'false') return 'disabled';\n if (process.env.INTLAYER_ROUTING_ENABLE_PROXY === 'true') return 'forced';\n\n if (enableProxy === false) return 'disabled';\n if (enableProxy === true) return 'forced';\n\n return 'auto';\n};\n\n/**\n * Indicates whether the proxy may use the locale held in storage (cookie or\n * header) as a source when deciding which locale a request resolves to.\n *\n * Auto mode suppresses it on development and preview servers only. Every other\n * combination keeps the stored locale active, which notably preserves the\n * behaviour of `createIntlayerProxyHandler` when it is mounted manually in a\n * production Nitro server.\n *\n * Suppressing the read affects redirect *sources* only — the locale is still\n * persisted onto responses, the URL locale prefix still wins over everything,\n * and `Accept-Language` detection still applies as the fallback.\n *\n * @param proxyMode - The resolved proxy mode.\n * @param isDevServer - Whether a development or preview server is serving the app.\n * @returns `true` when the stored locale may drive locale resolution.\n *\n * @example\n * ```ts\n * isProxyStorageLocaleEnabled('auto', true); // false — dev server, URL-driven only\n * isProxyStorageLocaleEnabled('auto', false); // true — production\n * isProxyStorageLocaleEnabled('forced', true); // true — explicitly opted in\n * ```\n */\nexport const isProxyStorageLocaleEnabled = (\n proxyMode: ProxyMode,\n isDevServer: boolean\n): boolean => !(proxyMode === 'auto' && isDevServer);\n\n/**\n * Builds the line announcing that a server has mounted the locale-routing\n * proxy.\n *\n * Shared by every integration (Vite plugin, Next.js middleware) so the reported\n * state cannot drift between them: when the stored locale is suppressed the\n * message says so, which would otherwise look like a broken proxy to anyone\n * testing locale switching with a cookie already set.\n *\n * Takes the suppression flag rather than the {@link ProxyMode} on purpose. Auto\n * mode only suppresses storage on a dev server, so a mode-based signature would\n * let a production caller — such as the Nitro production handler — announce a\n * suppression that is not actually in effect.\n *\n * @param isStorageLocaleSuppressed - Whether the stored locale is barred from\n * driving redirects, i.e. the negation of {@link isProxyStorageLocaleEnabled}.\n * @returns An ANSI-coloured, ready-to-log message.\n *\n * @example\n * ```ts\n * formatProxyEnabledMessage(true);\n * // Intlayer proxy enabled - storage redirection disabled for dev purpose\n * formatProxyEnabledMessage(false);\n * // Intlayer proxy enabled\n * ```\n */\nexport const formatProxyEnabledMessage = (\n isStorageLocaleSuppressed: boolean\n): string =>\n [\n `Intlayer proxy ${colorize('enabled', ANSIColors.GREEN)}`,\n isStorageLocaleSuppressed &&\n colorize(\n '- storage redirection disabled for dev purpose',\n ANSIColors.GREY\n ),\n ]\n .filter(Boolean)\n .join(' ');\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;AAuCA,MAAa,oBAAoB,gBAAqC;CACpE,IAAI,QAAQ,IAAI,kCAAkC,SAAS,OAAO;CAClE,IAAI,QAAQ,IAAI,kCAAkC,QAAQ,OAAO;CAEjE,IAAI,gBAAgB,OAAO,OAAO;CAClC,IAAI,gBAAgB,MAAM,OAAO;CAEjC,OAAO;AACT;;;;;;;;;;;;;;;;;;;;;;;;;AA0BA,MAAa,+BACX,WACA,gBACY,EAAE,cAAc,UAAU;;;;;;;;;;;;;;;;;;;;;;;;;;;AA4BxC,MAAa,6BACX,8BAEA,CACE,sBAAkBA,kCAAS,WAAWC,wBAAW,KAAK,KACtD,iCACED,kCACE,kDACAC,wBAAW,IACb,CACJ,CAAC,CACE,OAAO,OAAO,CAAC,CACf,KAAK,GAAG"}
@@ -1,5 +1,4 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
2
-
3
2
  //#region src/localization/rewriteUtils.ts
4
3
  /**
5
4
  * True when rewrite rules are explicitly disabled at build time
@@ -1 +1 @@
1
- {"version":3,"file":"rewriteUtils.cjs","names":[],"sources":["../../../src/localization/rewriteUtils.ts"],"sourcesContent":["// ── Tree-shake constants ──────────────────────────────────────────────────────\n// When these env vars are injected at build time, bundlers eliminate the\n// branches guarded by these constants.\n\n/**\n * True when rewrite rules are explicitly disabled at build time\n * (INTLAYER_ROUTING_REWRITE_RULES === 'false').\n */\nconst TREE_SHAKE_REWRITE =\n process.env.INTLAYER_ROUTING_REWRITE_RULES === 'false';\n\nimport type { Locale } from '@intlayer/types/allLocales';\nimport type {\n RewriteObject,\n RewriteRules,\n RoutingConfig,\n} from '@intlayer/types/config';\nimport type { LocalesValues } from '@intlayer/types/module_augmentation';\n\nexport type LocalizedPathResult = {\n path: string;\n isRewritten: boolean;\n};\n\n/**\n * Normalizes legacy Record format or extracts specialized rules from RewriteObject.\n */\nexport const getRewriteRules = (\n rewrite: RoutingConfig['rewrite'],\n context: keyof RewriteObject = 'url'\n): RewriteRules | undefined => {\n if (!rewrite || TREE_SHAKE_REWRITE) return undefined;\n\n if ('url' in rewrite) {\n return (rewrite as RewriteObject)[context];\n }\n\n // Normalize legacy format\n return {\n rules: Object.entries(rewrite).map(([canonical, localized]) => ({\n // Normalize canonical path\n canonical: canonical.startsWith('/')\n ? canonical.replace(/\\[([^\\]]+)\\]/g, ':$1')\n : `/${canonical.replace(/\\[([^\\]]+)\\]/g, ':$1')}`,\n\n // Normalize localized path\n localized: Object.fromEntries(\n Object.entries(localized).map(([locale, pattern]) => {\n const normalizedPattern = pattern?.startsWith('/')\n ? pattern.replace(/\\[([^\\]]+)\\]/g, ':$1')\n : `/${(pattern || '').replace(/\\[([^\\]]+)\\]/g, ':$1')}`;\n return [locale, normalizedPattern];\n })\n ),\n })),\n };\n};\n\n/**\n * Converts normalized pattern to Regex.\n * Internal syntax supports:\n * - :param -> ([^/]+) (one segment)\n * - :param* -> (.*) (zero or more segments)\n * - :param+ -> (.+) (one or more segments)\n * - :param? -> ([^/]*) (zero or one segment)\n */\nconst patternToRegex = (pattern: string) => {\n const regexString = pattern\n .replace(/\\//g, '\\\\/') // Escape slashes\n .replace(/\\\\\\/:(?:[^/\\\\*+?]+)\\*/g, '(?:\\\\/(.*))?') // /:param*\n .replace(/\\\\\\/:(?:[^/\\\\*+?]+)\\?/g, '(?:\\\\/([^\\\\/]+))?') // /:param?\n .replace(/:([^/\\\\*+?]+)\\*/g, '(.*)') // :param* (if no leading slash)\n .replace(/:([^/\\\\*+?]+)\\?/g, '([^\\\\/]*)') // :param? (if no leading slash)\n .replace(/:([^/\\\\*+?]+)\\+/g, '(.+)') // :param+\n .replace(/:([^/\\\\*+?]+)/g, '([^\\\\/]+)'); // :param\n\n return new RegExp(`^${regexString}$`);\n};\n\n/**\n * Replaces route parameters in a path with provided values.\n */\nconst fillPath = (pattern: string, params: string[]) => {\n let index = 0;\n return (\n pattern\n .replace(/:([^/\\\\*+?]+)[*+?]?/g, () => params[index++] ?? '')\n .replace(/\\/+/g, '/')\n .replace(/\\/$/, '') || '/'\n );\n};\n\n/**\n * Extract values from a URL based on a pattern.\n */\nconst extractParams = (url: string, pattern: string): string[] | null => {\n const regex = patternToRegex(pattern);\n const match = url.match(regex);\n return match ? match.slice(1) : null;\n};\n\n/**\n * Given a localized URL (e.g., \"/produits/123\"), finds the canonical internal path (e.g., \"/products/123\").\n * If locale is provided, only check for that locale. Otherwise, check for all locales.\n */\nexport const getCanonicalPath = (\n localizedPath: string,\n locale?: Locale,\n rewriteRules?: RewriteRules\n): string => {\n if (!rewriteRules || TREE_SHAKE_REWRITE) return localizedPath;\n\n for (const rule of rewriteRules.rules) {\n const { canonical, localized } = rule;\n const localesToCheck = locale ? [locale] : Object.keys(localized);\n\n for (const loc of localesToCheck) {\n const localizedPattern = localized[loc as keyof typeof localized];\n\n if (!localizedPattern) continue;\n\n const params = extractParams(localizedPath, localizedPattern);\n\n if (params) {\n return fillPath(canonical, params);\n }\n }\n }\n\n return localizedPath;\n};\n\n/**\n * Given a canonical path (e.g., \"/products/123\"), finds the localized URL pattern (e.g., \"/produits/123\").\n */\nexport const getLocalizedPath = (\n canonicalPath: string,\n locale: LocalesValues,\n rewriteRules?: RewriteRules\n): LocalizedPathResult => {\n if (!rewriteRules || TREE_SHAKE_REWRITE)\n return { path: canonicalPath, isRewritten: false };\n\n for (const rule of rewriteRules.rules) {\n const { canonical, localized } = rule;\n\n // Check if the input path matches a configured canonical pattern\n const params = extractParams(canonicalPath, canonical);\n\n if (params) {\n const targetPattern = localized[locale as keyof typeof localized];\n\n if (targetPattern) {\n return {\n path: fillPath(targetPattern, params),\n isRewritten: true,\n };\n }\n }\n }\n\n return { path: canonicalPath, isRewritten: false };\n};\n\n/**\n * Returns the internal path for a given canonical path and locale.\n * Ensures the locale prefix is present exactly once.\n */\nexport const getInternalPath = (\n canonicalPath: string,\n locale: Locale\n): string => {\n const pathWithLeadingSlash = canonicalPath.startsWith('/')\n ? canonicalPath\n : `/${canonicalPath}`;\n\n if (\n pathWithLeadingSlash.startsWith(`/${locale}/`) ||\n pathWithLeadingSlash === `/${locale}`\n ) {\n return pathWithLeadingSlash;\n }\n\n return `/${locale}${pathWithLeadingSlash === '/' ? '' : pathWithLeadingSlash}`;\n};\n\n/**\n * Given a current pathname and locale, returns the pretty localized path if a rewrite rule exists and the path is not already localized.\n */\nexport const getRewritePath = (\n pathname: string,\n locale: Locale,\n rewrite?: RoutingConfig['rewrite']\n): string | undefined => {\n if (TREE_SHAKE_REWRITE) return undefined;\n const rules = getRewriteRules(rewrite, 'url');\n if (!rules) return undefined;\n\n // Identify canonical path (relative to root, no locale prefix expected in 'url' context)\n const canonicalPath = getCanonicalPath(pathname, undefined, rules);\n\n // Get the localized path for the current locale\n const { path: localizedPath, isRewritten } = getLocalizedPath(\n canonicalPath,\n locale,\n rules\n );\n\n if (isRewritten && localizedPath !== pathname) {\n return localizedPath;\n }\n\n return undefined;\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"rewriteUtils.cjs","names":[],"sources":["../../../src/localization/rewriteUtils.ts"],"sourcesContent":["// ── Tree-shake constants ──────────────────────────────────────────────────────\n// When these env vars are injected at build time, bundlers eliminate the\n// branches guarded by these constants.\n\n/**\n * True when rewrite rules are explicitly disabled at build time\n * (INTLAYER_ROUTING_REWRITE_RULES === 'false').\n */\nconst TREE_SHAKE_REWRITE =\n process.env.INTLAYER_ROUTING_REWRITE_RULES === 'false';\n\nimport type { Locale } from '@intlayer/types/allLocales';\nimport type {\n RewriteObject,\n RewriteRules,\n RoutingConfig,\n} from '@intlayer/types/config';\nimport type { LocalesValues } from '@intlayer/types/module_augmentation';\n\nexport type LocalizedPathResult = {\n path: string;\n isRewritten: boolean;\n};\n\n/**\n * Normalizes legacy Record format or extracts specialized rules from RewriteObject.\n */\nexport const getRewriteRules = (\n rewrite: RoutingConfig['rewrite'],\n context: keyof RewriteObject = 'url'\n): RewriteRules | undefined => {\n if (!rewrite || TREE_SHAKE_REWRITE) return undefined;\n\n if ('url' in rewrite) {\n return (rewrite as RewriteObject)[context];\n }\n\n // Normalize legacy format\n return {\n rules: Object.entries(rewrite).map(([canonical, localized]) => ({\n // Normalize canonical path\n canonical: canonical.startsWith('/')\n ? canonical.replace(/\\[([^\\]]+)\\]/g, ':$1')\n : `/${canonical.replace(/\\[([^\\]]+)\\]/g, ':$1')}`,\n\n // Normalize localized path\n localized: Object.fromEntries(\n Object.entries(localized).map(([locale, pattern]) => {\n const normalizedPattern = pattern?.startsWith('/')\n ? pattern.replace(/\\[([^\\]]+)\\]/g, ':$1')\n : `/${(pattern || '').replace(/\\[([^\\]]+)\\]/g, ':$1')}`;\n return [locale, normalizedPattern];\n })\n ),\n })),\n };\n};\n\n/**\n * Converts normalized pattern to Regex.\n * Internal syntax supports:\n * - :param -> ([^/]+) (one segment)\n * - :param* -> (.*) (zero or more segments)\n * - :param+ -> (.+) (one or more segments)\n * - :param? -> ([^/]*) (zero or one segment)\n */\nconst patternToRegex = (pattern: string) => {\n const regexString = pattern\n .replace(/\\//g, '\\\\/') // Escape slashes\n .replace(/\\\\\\/:(?:[^/\\\\*+?]+)\\*/g, '(?:\\\\/(.*))?') // /:param*\n .replace(/\\\\\\/:(?:[^/\\\\*+?]+)\\?/g, '(?:\\\\/([^\\\\/]+))?') // /:param?\n .replace(/:([^/\\\\*+?]+)\\*/g, '(.*)') // :param* (if no leading slash)\n .replace(/:([^/\\\\*+?]+)\\?/g, '([^\\\\/]*)') // :param? (if no leading slash)\n .replace(/:([^/\\\\*+?]+)\\+/g, '(.+)') // :param+\n .replace(/:([^/\\\\*+?]+)/g, '([^\\\\/]+)'); // :param\n\n return new RegExp(`^${regexString}$`);\n};\n\n/**\n * Replaces route parameters in a path with provided values.\n */\nconst fillPath = (pattern: string, params: string[]) => {\n let index = 0;\n return (\n pattern\n .replace(/:([^/\\\\*+?]+)[*+?]?/g, () => params[index++] ?? '')\n .replace(/\\/+/g, '/')\n .replace(/\\/$/, '') || '/'\n );\n};\n\n/**\n * Extract values from a URL based on a pattern.\n */\nconst extractParams = (url: string, pattern: string): string[] | null => {\n const regex = patternToRegex(pattern);\n const match = url.match(regex);\n return match ? match.slice(1) : null;\n};\n\n/**\n * Given a localized URL (e.g., \"/produits/123\"), finds the canonical internal path (e.g., \"/products/123\").\n * If locale is provided, only check for that locale. Otherwise, check for all locales.\n */\nexport const getCanonicalPath = (\n localizedPath: string,\n locale?: Locale,\n rewriteRules?: RewriteRules\n): string => {\n if (!rewriteRules || TREE_SHAKE_REWRITE) return localizedPath;\n\n for (const rule of rewriteRules.rules) {\n const { canonical, localized } = rule;\n const localesToCheck = locale ? [locale] : Object.keys(localized);\n\n for (const loc of localesToCheck) {\n const localizedPattern = localized[loc as keyof typeof localized];\n\n if (!localizedPattern) continue;\n\n const params = extractParams(localizedPath, localizedPattern);\n\n if (params) {\n return fillPath(canonical, params);\n }\n }\n }\n\n return localizedPath;\n};\n\n/**\n * Given a canonical path (e.g., \"/products/123\"), finds the localized URL pattern (e.g., \"/produits/123\").\n */\nexport const getLocalizedPath = (\n canonicalPath: string,\n locale: LocalesValues,\n rewriteRules?: RewriteRules\n): LocalizedPathResult => {\n if (!rewriteRules || TREE_SHAKE_REWRITE)\n return { path: canonicalPath, isRewritten: false };\n\n for (const rule of rewriteRules.rules) {\n const { canonical, localized } = rule;\n\n // Check if the input path matches a configured canonical pattern\n const params = extractParams(canonicalPath, canonical);\n\n if (params) {\n const targetPattern = localized[locale as keyof typeof localized];\n\n if (targetPattern) {\n return {\n path: fillPath(targetPattern, params),\n isRewritten: true,\n };\n }\n }\n }\n\n return { path: canonicalPath, isRewritten: false };\n};\n\n/**\n * Returns the internal path for a given canonical path and locale.\n * Ensures the locale prefix is present exactly once.\n */\nexport const getInternalPath = (\n canonicalPath: string,\n locale: Locale\n): string => {\n const pathWithLeadingSlash = canonicalPath.startsWith('/')\n ? canonicalPath\n : `/${canonicalPath}`;\n\n if (\n pathWithLeadingSlash.startsWith(`/${locale}/`) ||\n pathWithLeadingSlash === `/${locale}`\n ) {\n return pathWithLeadingSlash;\n }\n\n return `/${locale}${pathWithLeadingSlash === '/' ? '' : pathWithLeadingSlash}`;\n};\n\n/**\n * Given a current pathname and locale, returns the pretty localized path if a rewrite rule exists and the path is not already localized.\n */\nexport const getRewritePath = (\n pathname: string,\n locale: Locale,\n rewrite?: RoutingConfig['rewrite']\n): string | undefined => {\n if (TREE_SHAKE_REWRITE) return undefined;\n const rules = getRewriteRules(rewrite, 'url');\n if (!rules) return undefined;\n\n // Identify canonical path (relative to root, no locale prefix expected in 'url' context)\n const canonicalPath = getCanonicalPath(pathname, undefined, rules);\n\n // Get the localized path for the current locale\n const { path: localizedPath, isRewritten } = getLocalizedPath(\n canonicalPath,\n locale,\n rules\n );\n\n if (isRewritten && localizedPath !== pathname) {\n return localizedPath;\n }\n\n return undefined;\n};\n"],"mappings":"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"}
@@ -732,20 +732,22 @@ const parseMarkdown = (markdown = "", ctx, options = {}) => {
732
732
  const cleaned = input.replace(require_markdown_constants.TRIM_STARTING_NEWLINES, "");
733
733
  const slice = cleaned.length > 2048 ? cleaned.slice(0, 2048) : cleaned;
734
734
  if (slice.indexOf("\n\n") !== -1) return true;
735
- return require_markdown_utils.some(options.disableParsingRawHTML ? nonParagraphBlockSyntaxes : [
735
+ const syntaxes = options.disableParsingRawHTML ? nonParagraphBlockSyntaxes : [
736
736
  ...nonParagraphBlockSyntaxes,
737
737
  require_markdown_constants.PARAGRAPH_R,
738
738
  require_markdown_constants.HTML_BLOCK_ELEMENT_R,
739
739
  require_markdown_constants.HTML_COMMENT_R,
740
740
  require_markdown_constants.HTML_SELF_CLOSING_ELEMENT_R,
741
741
  require_markdown_constants.CUSTOM_COMPONENT_R
742
- ], slice);
742
+ ];
743
+ return require_markdown_utils.some(syntaxes, slice);
743
744
  };
744
745
  const baseRules = createRules(dummyCreateElement, ctx, options, footnotes, refs, attrStringToMap, containsBlockSyntax, nonParagraphBlockSyntaxes);
745
- const parser = require_markdown_parser.parserFor(options.disableParsingRawHTML ? Object.keys(baseRules).reduce((acc, key) => {
746
+ const rules = options.disableParsingRawHTML ? Object.keys(baseRules).reduce((acc, key) => {
746
747
  if (key !== require_markdown_constants.RuleType.htmlBlock && key !== require_markdown_constants.RuleType.htmlSelfClosing) acc[key] = baseRules[key];
747
748
  return acc;
748
- }, {}) : baseRules);
749
+ }, {}) : baseRules;
750
+ const parser = require_markdown_parser.parserFor(rules);
749
751
  const result = options.preserveFrontmatter ? markdown : markdown.replace(require_markdown_constants.FRONT_MATTER_R, "");
750
752
  const inline = options.forceInline || !options.forceBlock && require_markdown_constants.SHOULD_RENDER_AS_BLOCK_R.test(result.replace(require_markdown_constants.TRIM_STARTING_NEWLINES, "")) === false;
751
753
  const ast = parser(inline ? result : `${require_markdown_utils.trimEnd(result).replace(require_markdown_constants.TRIM_STARTING_NEWLINES, "")}\n\n`, { inline });
@@ -775,10 +777,11 @@ const renderMarkdownAst = (parsed, ctx, options = {}) => {
775
777
  const attrStringToMap = () => null;
776
778
  const containsBlockSyntax = () => false;
777
779
  const baseRules = createRules(createElement, ctx, options, footnotes, refs, attrStringToMap, containsBlockSyntax, []);
778
- const emitter = require_markdown_renderer.renderFor(require_markdown_renderer.createRenderer(options.disableParsingRawHTML ? Object.keys(baseRules).reduce((acc, key) => {
780
+ const rules = options.disableParsingRawHTML ? Object.keys(baseRules).reduce((acc, key) => {
779
781
  if (key !== require_markdown_constants.RuleType.htmlBlock && key !== require_markdown_constants.RuleType.htmlSelfClosing) acc[key] = baseRules[key];
780
782
  return acc;
781
- }, {}) : baseRules, options.renderRule));
783
+ }, {}) : baseRules;
784
+ const emitter = require_markdown_renderer.renderFor(require_markdown_renderer.createRenderer(rules, options.renderRule));
782
785
  const inline = parsed.inline;
783
786
  const arr = emitter(parsed.ast, { inline });
784
787
  while (typeof arr[arr.length - 1] === "string" && !arr[arr.length - 1].trim()) arr.pop();