@turnipxenon/pineapple 4.5.0 → 5.0.0-alpha.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 (465) hide show
  1. package/dist/api/GetLatestBlogs.d.ts +1 -0
  2. package/dist/api/GetLatestBlogs.d.ts.map +1 -0
  3. package/dist/api/index.d.ts +1 -0
  4. package/dist/api/index.d.ts.map +1 -0
  5. package/dist/assets/icons/icon-visibility.svg +1 -0
  6. package/dist/components/dialog_manager/DialogManager.d.ts +2 -0
  7. package/dist/components/dialog_manager/DialogManager.d.ts.map +1 -0
  8. package/dist/components/dialog_manager/DialogManager.js +15 -9
  9. package/dist/components/dialog_manager/DialogManagerStore.d.ts +5 -1
  10. package/dist/components/dialog_manager/DialogManagerStore.d.ts.map +1 -0
  11. package/dist/components/dialog_manager/DialogManagerStore.js +5 -1
  12. package/dist/components/dialog_manager/DialogProcessor.d.ts +1 -0
  13. package/dist/components/dialog_manager/DialogProcessor.d.ts.map +1 -0
  14. package/dist/components/dialog_manager/DialogUtils.d.ts +1 -0
  15. package/dist/components/dialog_manager/DialogUtils.d.ts.map +1 -0
  16. package/dist/components/dialog_manager/IDialogManager.d.ts +1 -0
  17. package/dist/components/dialog_manager/IDialogManager.d.ts.map +1 -0
  18. package/dist/components/dialog_manager/behavior_tree/core/BTreeUtils.d.ts +1 -0
  19. package/dist/components/dialog_manager/behavior_tree/core/BTreeUtils.d.ts.map +1 -0
  20. package/dist/components/dialog_manager/behavior_tree/core/BaseBehaviorResult.d.ts +1 -0
  21. package/dist/components/dialog_manager/behavior_tree/core/BaseBehaviorResult.d.ts.map +1 -0
  22. package/dist/components/dialog_manager/behavior_tree/core/BehaviorNode.d.ts +1 -0
  23. package/dist/components/dialog_manager/behavior_tree/core/BehaviorNode.d.ts.map +1 -0
  24. package/dist/components/dialog_manager/behavior_tree/core/BehaviorStatus.d.ts +1 -0
  25. package/dist/components/dialog_manager/behavior_tree/core/BehaviorStatus.d.ts.map +1 -0
  26. package/dist/components/dialog_manager/behavior_tree/core/SelectorNode.d.ts +1 -0
  27. package/dist/components/dialog_manager/behavior_tree/core/SelectorNode.d.ts.map +1 -0
  28. package/dist/components/dialog_manager/behavior_tree/expression/ExpressionArguments.d.ts +1 -0
  29. package/dist/components/dialog_manager/behavior_tree/expression/ExpressionArguments.d.ts.map +1 -0
  30. package/dist/components/dialog_manager/behavior_tree/expression/ExpressionBehaviorNode.d.ts +1 -0
  31. package/dist/components/dialog_manager/behavior_tree/expression/ExpressionBehaviorNode.d.ts.map +1 -0
  32. package/dist/components/dialog_manager/behavior_tree/expression/ExpressionEvaluator.d.ts +1 -0
  33. package/dist/components/dialog_manager/behavior_tree/expression/ExpressionEvaluator.d.ts.map +1 -0
  34. package/dist/components/dialog_manager/behavior_tree/expression/ExpressionResult.d.ts +1 -0
  35. package/dist/components/dialog_manager/behavior_tree/expression/ExpressionResult.d.ts.map +1 -0
  36. package/dist/components/dialog_manager/behavior_tree/expression/ExpressionSelectorNode.d.ts +1 -0
  37. package/dist/components/dialog_manager/behavior_tree/expression/ExpressionSelectorNode.d.ts.map +1 -0
  38. package/dist/components/dialog_manager/behavior_tree/expression/ExpressionState.d.ts +1 -0
  39. package/dist/components/dialog_manager/behavior_tree/expression/ExpressionState.d.ts.map +1 -0
  40. package/dist/components/dialog_manager/behavior_tree/expression/OperandNode.d.ts +1 -0
  41. package/dist/components/dialog_manager/behavior_tree/expression/OperandNode.d.ts.map +1 -0
  42. package/dist/components/dialog_manager/behavior_tree/expression/OperatorNode.d.ts +1 -0
  43. package/dist/components/dialog_manager/behavior_tree/expression/OperatorNode.d.ts.map +1 -0
  44. package/dist/components/dialog_manager/behavior_tree/expression/commands/CommandExpressionNode.d.ts +1 -0
  45. package/dist/components/dialog_manager/behavior_tree/expression/commands/CommandExpressionNode.d.ts.map +1 -0
  46. package/dist/components/dialog_manager/behavior_tree/expression/commands/CommandLogicNode.d.ts +1 -0
  47. package/dist/components/dialog_manager/behavior_tree/expression/commands/CommandLogicNode.d.ts.map +1 -0
  48. package/dist/components/dialog_manager/behavior_tree/expression/commands/CommandMap.d.ts +1 -0
  49. package/dist/components/dialog_manager/behavior_tree/expression/commands/CommandMap.d.ts.map +1 -0
  50. package/dist/components/dialog_manager/behavior_tree/expression/commands/RandomRangeCommand.d.ts +1 -0
  51. package/dist/components/dialog_manager/behavior_tree/expression/commands/RandomRangeCommand.d.ts.map +1 -0
  52. package/dist/components/dialog_manager/behavior_tree/expression/commands/VisitedCommand.d.ts +1 -0
  53. package/dist/components/dialog_manager/behavior_tree/expression/commands/VisitedCommand.d.ts.map +1 -0
  54. package/dist/components/dialog_manager/behavior_tree/expression/commands/VisitedCountCommand.d.ts +1 -0
  55. package/dist/components/dialog_manager/behavior_tree/expression/commands/VisitedCountCommand.d.ts.map +1 -0
  56. package/dist/components/dialog_manager/behavior_tree/expression/operators/AndOperator.d.ts +1 -0
  57. package/dist/components/dialog_manager/behavior_tree/expression/operators/AndOperator.d.ts.map +1 -0
  58. package/dist/components/dialog_manager/behavior_tree/expression/operators/EqualityOperator.d.ts +1 -0
  59. package/dist/components/dialog_manager/behavior_tree/expression/operators/EqualityOperator.d.ts.map +1 -0
  60. package/dist/components/dialog_manager/behavior_tree/expression/operators/GreaterThanEqualOperator.d.ts +1 -0
  61. package/dist/components/dialog_manager/behavior_tree/expression/operators/GreaterThanEqualOperator.d.ts.map +1 -0
  62. package/dist/components/dialog_manager/behavior_tree/expression/operators/GreaterThanOperator.d.ts +1 -0
  63. package/dist/components/dialog_manager/behavior_tree/expression/operators/GreaterThanOperator.d.ts.map +1 -0
  64. package/dist/components/dialog_manager/behavior_tree/expression/operators/InequalityOperator.d.ts +1 -0
  65. package/dist/components/dialog_manager/behavior_tree/expression/operators/InequalityOperator.d.ts.map +1 -0
  66. package/dist/components/dialog_manager/behavior_tree/expression/operators/LessThanEqualOperator.d.ts +1 -0
  67. package/dist/components/dialog_manager/behavior_tree/expression/operators/LessThanEqualOperator.d.ts.map +1 -0
  68. package/dist/components/dialog_manager/behavior_tree/expression/operators/LessThanOperator.d.ts +1 -0
  69. package/dist/components/dialog_manager/behavior_tree/expression/operators/LessThanOperator.d.ts.map +1 -0
  70. package/dist/components/dialog_manager/behavior_tree/expression/operators/NegationOperator.d.ts +1 -0
  71. package/dist/components/dialog_manager/behavior_tree/expression/operators/NegationOperator.d.ts.map +1 -0
  72. package/dist/components/dialog_manager/behavior_tree/expression/operators/OperatorLogicNode.d.ts +1 -0
  73. package/dist/components/dialog_manager/behavior_tree/expression/operators/OperatorLogicNode.d.ts.map +1 -0
  74. package/dist/components/dialog_manager/behavior_tree/expression/operators/OperatorMap.d.ts +1 -0
  75. package/dist/components/dialog_manager/behavior_tree/expression/operators/OperatorMap.d.ts.map +1 -0
  76. package/dist/components/dialog_manager/behavior_tree/expression/operators/OrOperator.d.ts +1 -0
  77. package/dist/components/dialog_manager/behavior_tree/expression/operators/OrOperator.d.ts.map +1 -0
  78. package/dist/components/dialog_manager/behavior_tree/expression/operators/XorOperator.d.ts +1 -0
  79. package/dist/components/dialog_manager/behavior_tree/expression/operators/XorOperator.d.ts.map +1 -0
  80. package/dist/components/dialog_manager/behavior_tree/expression/operators/arithmetic/DivisionOperator.d.ts +1 -0
  81. package/dist/components/dialog_manager/behavior_tree/expression/operators/arithmetic/DivisionOperator.d.ts.map +1 -0
  82. package/dist/components/dialog_manager/behavior_tree/expression/operators/arithmetic/MinusOperator.d.ts +1 -0
  83. package/dist/components/dialog_manager/behavior_tree/expression/operators/arithmetic/MinusOperator.d.ts.map +1 -0
  84. package/dist/components/dialog_manager/behavior_tree/expression/operators/arithmetic/MultiplicationOperator.d.ts +1 -0
  85. package/dist/components/dialog_manager/behavior_tree/expression/operators/arithmetic/MultiplicationOperator.d.ts.map +1 -0
  86. package/dist/components/dialog_manager/behavior_tree/expression/operators/arithmetic/PlusOperator.d.ts +1 -0
  87. package/dist/components/dialog_manager/behavior_tree/expression/operators/arithmetic/PlusOperator.d.ts.map +1 -0
  88. package/dist/components/dialog_manager/behavior_tree/expression/operators/arithmetic/RemainderDivisionOperator.d.ts +1 -0
  89. package/dist/components/dialog_manager/behavior_tree/expression/operators/arithmetic/RemainderDivisionOperator.d.ts.map +1 -0
  90. package/dist/components/dialog_manager/behavior_tree/line_core/LineBehaviorNode.d.ts +1 -0
  91. package/dist/components/dialog_manager/behavior_tree/line_core/LineBehaviorNode.d.ts.map +1 -0
  92. package/dist/components/dialog_manager/behavior_tree/line_core/LineBehaviorResult.d.ts +1 -0
  93. package/dist/components/dialog_manager/behavior_tree/line_core/LineBehaviorResult.d.ts.map +1 -0
  94. package/dist/components/dialog_manager/behavior_tree/line_core/LineNodeArguments.d.ts +1 -0
  95. package/dist/components/dialog_manager/behavior_tree/line_core/LineNodeArguments.d.ts.map +1 -0
  96. package/dist/components/dialog_manager/behavior_tree/line_core/LineSelectorNode.d.ts +1 -0
  97. package/dist/components/dialog_manager/behavior_tree/line_core/LineSelectorNode.d.ts.map +1 -0
  98. package/dist/components/dialog_manager/behavior_tree/line_processors/BehaviorState.d.ts +1 -0
  99. package/dist/components/dialog_manager/behavior_tree/line_processors/BehaviorState.d.ts.map +1 -0
  100. package/dist/components/dialog_manager/behavior_tree/line_processors/ElseIfNode.d.ts +1 -0
  101. package/dist/components/dialog_manager/behavior_tree/line_processors/ElseIfNode.d.ts.map +1 -0
  102. package/dist/components/dialog_manager/behavior_tree/line_processors/ElseNode.d.ts +1 -0
  103. package/dist/components/dialog_manager/behavior_tree/line_processors/ElseNode.d.ts.map +1 -0
  104. package/dist/components/dialog_manager/behavior_tree/line_processors/EndIfNode.d.ts +1 -0
  105. package/dist/components/dialog_manager/behavior_tree/line_processors/EndIfNode.d.ts.map +1 -0
  106. package/dist/components/dialog_manager/behavior_tree/line_processors/IfMode.d.ts +1 -0
  107. package/dist/components/dialog_manager/behavior_tree/line_processors/IfMode.d.ts.map +1 -0
  108. package/dist/components/dialog_manager/behavior_tree/line_processors/IfNode.d.ts +1 -0
  109. package/dist/components/dialog_manager/behavior_tree/line_processors/IfNode.d.ts.map +1 -0
  110. package/dist/components/dialog_manager/behavior_tree/line_processors/IgnoreGuardNode.d.ts +1 -0
  111. package/dist/components/dialog_manager/behavior_tree/line_processors/IgnoreGuardNode.d.ts.map +1 -0
  112. package/dist/components/dialog_manager/behavior_tree/line_processors/IgnoreJumpNode.d.ts +1 -0
  113. package/dist/components/dialog_manager/behavior_tree/line_processors/IgnoreJumpNode.d.ts.map +1 -0
  114. package/dist/components/dialog_manager/behavior_tree/line_processors/LineCommentNode.d.ts +1 -0
  115. package/dist/components/dialog_manager/behavior_tree/line_processors/LineCommentNode.d.ts.map +1 -0
  116. package/dist/components/dialog_manager/behavior_tree/line_processors/NormalLineProcessorNode.d.ts +1 -0
  117. package/dist/components/dialog_manager/behavior_tree/line_processors/NormalLineProcessorNode.d.ts.map +1 -0
  118. package/dist/components/dialog_manager/behavior_tree/line_processors/SetVariableNode.d.ts +1 -0
  119. package/dist/components/dialog_manager/behavior_tree/line_processors/SetVariableNode.d.ts.map +1 -0
  120. package/dist/components/dialog_manager/behavior_tree/line_processors/commands/DeclareCommand.d.ts +1 -0
  121. package/dist/components/dialog_manager/behavior_tree/line_processors/commands/DeclareCommand.d.ts.map +1 -0
  122. package/dist/components/dialog_manager/behavior_tree/line_processors/commands/JumpCommand.d.ts +1 -0
  123. package/dist/components/dialog_manager/behavior_tree/line_processors/commands/JumpCommand.d.ts.map +1 -0
  124. package/dist/components/dialog_manager/behavior_tree/line_processors/commands/UnvisitCommand.d.ts +1 -0
  125. package/dist/components/dialog_manager/behavior_tree/line_processors/commands/UnvisitCommand.d.ts.map +1 -0
  126. package/dist/components/reveal-info/RevealInfo.svelte +86 -0
  127. package/dist/components/reveal-info/RevealInfo.svelte.d.ts +15 -0
  128. package/dist/components/reveal-info/RevealInfo.svelte.d.ts.map +1 -0
  129. package/dist/components/reveal-info/RevealInfoCollection.d.ts +6 -0
  130. package/dist/components/reveal-info/RevealInfoCollection.d.ts.map +1 -0
  131. package/dist/components/reveal-info/RevealInfoRemoteQuery.d.ts +10 -0
  132. package/dist/components/reveal-info/RevealInfoRemoteQuery.d.ts.map +1 -0
  133. package/dist/components/reveal-info/RevealInfoRemoteQuery.js +1 -0
  134. package/dist/components/reveal-info/RevealInfoRune.svelte.d.ts +6 -0
  135. package/dist/components/reveal-info/RevealInfoRune.svelte.d.ts.map +1 -0
  136. package/dist/components/reveal-info/RevealInfoRune.svelte.js +13 -0
  137. package/dist/consts.d.ts +1 -0
  138. package/dist/consts.d.ts.map +1 -0
  139. package/dist/external/paraglide/.prettierignore +3 -0
  140. package/dist/external/paraglide/messages/_index.d.ts +9 -0
  141. package/dist/external/paraglide/messages/_index.d.ts.map +1 -0
  142. package/dist/external/paraglide/messages/_index.js +51 -0
  143. package/dist/external/paraglide/messages/en.d.ts +5 -0
  144. package/dist/external/paraglide/messages/en.d.ts.map +1 -0
  145. package/dist/external/paraglide/messages/en.js +10 -0
  146. package/dist/external/paraglide/messages/fr.d.ts +5 -0
  147. package/dist/external/paraglide/messages/fr.d.ts.map +1 -0
  148. package/dist/external/paraglide/messages/fr.js +10 -0
  149. package/dist/external/paraglide/messages/tl.d.ts +5 -0
  150. package/dist/external/paraglide/messages/tl.d.ts.map +1 -0
  151. package/dist/external/paraglide/messages/tl.js +7 -0
  152. package/dist/external/paraglide/messages.d.ts +3 -0
  153. package/dist/external/paraglide/messages.d.ts.map +1 -0
  154. package/dist/external/paraglide/messages.js +4 -0
  155. package/dist/external/paraglide/registry.d.ts +22 -0
  156. package/dist/external/paraglide/registry.d.ts.map +1 -0
  157. package/dist/external/paraglide/registry.js +31 -0
  158. package/dist/external/paraglide/runtime.d.ts +584 -0
  159. package/dist/external/paraglide/runtime.d.ts.map +1 -0
  160. package/dist/external/paraglide/runtime.js +1406 -0
  161. package/dist/external/paraglide/server.d.ts +68 -0
  162. package/dist/external/paraglide/server.d.ts.map +1 -0
  163. package/dist/external/paraglide/server.js +175 -0
  164. package/dist/index.d.ts +2 -1
  165. package/dist/index.d.ts.map +1 -0
  166. package/dist/index.js +1 -1
  167. package/dist/modules/overrideable_meta/OverridableMeta.svelte +1 -2
  168. package/dist/modules/overrideable_meta/OverridableMeta.svelte.d.ts +15 -10
  169. package/dist/modules/overrideable_meta/OverridableMeta.svelte.d.ts.map +1 -0
  170. package/dist/modules/overrideable_meta/OverridableMetaProps.d.ts +1 -0
  171. package/dist/modules/overrideable_meta/OverridableMetaProps.d.ts.map +1 -0
  172. package/dist/modules/overrideable_meta/index.d.ts +1 -0
  173. package/dist/modules/overrideable_meta/index.d.ts.map +1 -0
  174. package/dist/modules/parsnip/ParsnipBlockChildren.svelte.d.ts +14 -7
  175. package/dist/modules/parsnip/ParsnipBlockChildren.svelte.d.ts.map +1 -0
  176. package/dist/modules/parsnip/ParsnipEmbedWikilink.svelte.d.ts +13 -13
  177. package/dist/modules/parsnip/ParsnipEmbedWikilink.svelte.d.ts.map +1 -0
  178. package/dist/modules/parsnip/ParsnipEntry.d.ts +1 -0
  179. package/dist/modules/parsnip/ParsnipEntry.d.ts.map +1 -0
  180. package/dist/modules/parsnip/ParsnipHeading.svelte.d.ts +14 -6
  181. package/dist/modules/parsnip/ParsnipHeading.svelte.d.ts.map +1 -0
  182. package/dist/modules/parsnip/ParsnipList.svelte.d.ts +14 -6
  183. package/dist/modules/parsnip/ParsnipList.svelte.d.ts.map +1 -0
  184. package/dist/modules/parsnip/ParsnipOverall.d.ts +1 -0
  185. package/dist/modules/parsnip/ParsnipOverall.d.ts.map +1 -0
  186. package/dist/modules/parsnip/ParsnipParagraph.svelte +10 -10
  187. package/dist/modules/parsnip/ParsnipParagraph.svelte.d.ts +14 -6
  188. package/dist/modules/parsnip/ParsnipParagraph.svelte.d.ts.map +1 -0
  189. package/dist/modules/parsnip/ParsnipPhrasingChildren.svelte +30 -30
  190. package/dist/modules/parsnip/ParsnipPhrasingChildren.svelte.d.ts +14 -6
  191. package/dist/modules/parsnip/ParsnipPhrasingChildren.svelte.d.ts.map +1 -0
  192. package/dist/modules/parsnip/ParsnipWikilink.svelte.d.ts +13 -14
  193. package/dist/modules/parsnip/ParsnipWikilink.svelte.d.ts.map +1 -0
  194. package/dist/modules/parsnip/index.d.ts +1 -0
  195. package/dist/modules/parsnip/index.d.ts.map +1 -0
  196. package/dist/modules/parsnip/route-util/ParsnipBlog.svelte.d.ts +14 -6
  197. package/dist/modules/parsnip/route-util/ParsnipBlog.svelte.d.ts.map +1 -0
  198. package/dist/modules/parsnip/route-util/getSlugEntries.d.ts +1 -0
  199. package/dist/modules/parsnip/route-util/getSlugEntries.d.ts.map +1 -0
  200. package/dist/modules/parsnip/route-util/menuPageServerLoad.d.ts +7 -0
  201. package/dist/modules/parsnip/route-util/menuPageServerLoad.d.ts.map +1 -0
  202. package/dist/modules/parsnip/route-util/menuPageServerLoad.js +28 -1
  203. package/dist/modules/parsnip/route-util/slugPageServerLoad.d.ts +2 -1
  204. package/dist/modules/parsnip/route-util/slugPageServerLoad.d.ts.map +1 -0
  205. package/dist/scripts/pineapple_fiber/PineappleFiberParser.d.ts +1 -0
  206. package/dist/scripts/pineapple_fiber/PineappleFiberParser.d.ts.map +1 -0
  207. package/dist/scripts/pineapple_fiber/PineappleWeaver.d.ts +1 -0
  208. package/dist/scripts/pineapple_fiber/PineappleWeaver.d.ts.map +1 -0
  209. package/dist/scripts/util/FileManagement.d.ts +1 -0
  210. package/dist/scripts/util/FileManagement.d.ts.map +1 -0
  211. package/dist/scripts/util/ManualCheck.d.ts +1 -0
  212. package/dist/scripts/util/ManualCheck.d.ts.map +1 -0
  213. package/dist/scripts/util/ManualCheckRun.d.ts +1 -0
  214. package/dist/scripts/util/ManualCheckRun.d.ts.map +1 -0
  215. package/dist/store.d.ts +1 -0
  216. package/dist/store.d.ts.map +1 -0
  217. package/dist/styles/app.css +61 -21
  218. package/dist/styles/color-tokens.css +23 -0
  219. package/dist/styles/surface-colors.scss +38 -0
  220. package/dist/styles/tailwind.css +3349 -0
  221. package/dist/styles/turnip-theme.css +59 -52
  222. package/dist/types/BlogBlurbMeta.d.ts +1 -0
  223. package/dist/types/BlogBlurbMeta.d.ts.map +1 -0
  224. package/dist/types/BreadcrumbData.d.ts +1 -0
  225. package/dist/types/BreadcrumbData.d.ts.map +1 -0
  226. package/dist/types/api/CreateUrl.d.ts +1 -0
  227. package/dist/types/api/CreateUrl.d.ts.map +1 -0
  228. package/dist/types/api/index.d.ts +1 -0
  229. package/dist/types/api/index.d.ts.map +1 -0
  230. package/dist/types/pineapple_fiber/DialogDetail.d.ts +1 -0
  231. package/dist/types/pineapple_fiber/DialogDetail.d.ts.map +1 -0
  232. package/dist/types/pineapple_fiber/DialogState.d.ts +1 -0
  233. package/dist/types/pineapple_fiber/DialogState.d.ts.map +1 -0
  234. package/dist/types/pineapple_fiber/DialogVariableStore.d.ts +1 -0
  235. package/dist/types/pineapple_fiber/DialogVariableStore.d.ts.map +1 -0
  236. package/dist/types/pineapple_fiber/PortraitType.d.ts +1 -0
  237. package/dist/types/pineapple_fiber/PortraitType.d.ts.map +1 -0
  238. package/dist/ui/components/FourPartCard.svelte +12 -5
  239. package/dist/ui/components/FourPartCard.svelte.d.ts +14 -9
  240. package/dist/ui/components/FourPartCard.svelte.d.ts.map +1 -0
  241. package/dist/ui/components/MeltToaster/MeltToaster.svelte +101 -0
  242. package/dist/ui/components/MeltToaster/MeltToaster.svelte.d.ts +65 -0
  243. package/dist/ui/components/MeltToaster/MeltToaster.svelte.d.ts.map +1 -0
  244. package/dist/ui/{templates/SeaweedLayout → components/MeltToaster}/ToastSettings.d.ts +1 -1
  245. package/dist/ui/components/MeltToaster/ToastSettings.d.ts.map +1 -0
  246. package/dist/ui/components/MeltToaster/ToastSettings.js +1 -0
  247. package/dist/ui/components/ModalBase.svelte.d.ts +14 -7
  248. package/dist/ui/components/ModalBase.svelte.d.ts.map +1 -0
  249. package/dist/ui/components/SocialSection.svelte +58 -27
  250. package/dist/ui/components/SocialSection.svelte.d.ts +15 -9
  251. package/dist/ui/components/SocialSection.svelte.d.ts.map +1 -0
  252. package/dist/ui/components/accordion/PinyaAccordion.svelte +54 -12
  253. package/dist/ui/components/accordion/PinyaAccordion.svelte.d.ts +14 -7
  254. package/dist/ui/components/accordion/PinyaAccordion.svelte.d.ts.map +1 -0
  255. package/dist/ui/components/accordion/PinyaAccordionItem.svelte +117 -18
  256. package/dist/ui/components/accordion/PinyaAccordionItem.svelte.d.ts +14 -8
  257. package/dist/ui/components/accordion/PinyaAccordionItem.svelte.d.ts.map +1 -0
  258. package/dist/ui/components/accordion/accordionContext.d.ts +5 -0
  259. package/dist/ui/components/accordion/accordionContext.d.ts.map +1 -0
  260. package/dist/ui/components/accordion/accordionContext.js +2 -0
  261. package/dist/ui/components/accordion/index.d.ts +1 -0
  262. package/dist/ui/components/accordion/index.d.ts.map +1 -0
  263. package/dist/ui/components/index.d.ts +1 -0
  264. package/dist/ui/components/index.d.ts.map +1 -0
  265. package/dist/ui/components/randomized-background/RandomizedBackground.svelte +3 -1
  266. package/dist/ui/components/randomized-background/RandomizedBackground.svelte.d.ts +14 -5
  267. package/dist/ui/components/randomized-background/RandomizedBackground.svelte.d.ts.map +1 -0
  268. package/dist/ui/components/randomized-background/RandomizedImage.svelte +3 -2
  269. package/dist/ui/components/randomized-background/RandomizedImage.svelte.d.ts +14 -6
  270. package/dist/ui/components/randomized-background/RandomizedImage.svelte.d.ts.map +1 -0
  271. package/dist/ui/components/randomized-background/getSocialSection.remote.d.ts +3 -0
  272. package/dist/ui/components/randomized-background/getSocialSection.remote.d.ts.map +1 -0
  273. package/dist/ui/components/randomized-background/getSocialSection.remote.js +7 -0
  274. package/dist/ui/components/socialSectionRemote.remote.d.ts +3 -0
  275. package/dist/ui/components/socialSectionRemote.remote.d.ts.map +1 -0
  276. package/dist/ui/components/socialSectionRemote.remote.js +3 -0
  277. package/dist/ui/elements/CodeBlock/CodeBlock.svelte +1 -1
  278. package/dist/ui/elements/CodeBlock/CodeBlock.svelte.d.ts +15 -4
  279. package/dist/ui/elements/CodeBlock/CodeBlock.svelte.d.ts.map +1 -0
  280. package/dist/ui/elements/CodeBlock/CodeBlockProps.d.ts +1 -0
  281. package/dist/ui/elements/CodeBlock/CodeBlockProps.d.ts.map +1 -0
  282. package/dist/ui/elements/CodeBlock/index.d.ts +1 -0
  283. package/dist/ui/elements/CodeBlock/index.d.ts.map +1 -0
  284. package/dist/ui/elements/ColorScheme.d.ts +9 -8
  285. package/dist/ui/elements/ColorScheme.d.ts.map +1 -0
  286. package/dist/ui/elements/ColorScheme.js +8 -8
  287. package/dist/ui/elements/ElementVisibilityDetector.svelte +24 -19
  288. package/dist/ui/elements/ElementVisibilityDetector.svelte.d.ts +14 -7
  289. package/dist/ui/elements/ElementVisibilityDetector.svelte.d.ts.map +1 -0
  290. package/dist/ui/elements/GeneralUIProps.d.ts +1 -0
  291. package/dist/ui/elements/GeneralUIProps.d.ts.map +1 -0
  292. package/dist/ui/elements/ImageIcon.svelte +5 -1
  293. package/dist/ui/elements/ImageIcon.svelte.d.ts +19 -6
  294. package/dist/ui/elements/ImageIcon.svelte.d.ts.map +1 -0
  295. package/dist/ui/elements/OnBackground.d.ts +1 -0
  296. package/dist/ui/elements/OnBackground.d.ts.map +1 -0
  297. package/dist/ui/elements/PineappleSwitch.svelte +76 -11
  298. package/dist/ui/elements/PineappleSwitch.svelte.d.ts +14 -9
  299. package/dist/ui/elements/PineappleSwitch.svelte.d.ts.map +1 -0
  300. package/dist/ui/elements/PinyaAnchorButton/PinyaAnchorButton.svelte +6 -2
  301. package/dist/ui/elements/PinyaAnchorButton/PinyaAnchorButton.svelte.d.ts +19 -4
  302. package/dist/ui/elements/PinyaAnchorButton/PinyaAnchorButton.svelte.d.ts.map +1 -0
  303. package/dist/ui/elements/PinyaAnchorButton/PinyaAnchorButtonProps.d.ts +1 -0
  304. package/dist/ui/elements/PinyaAnchorButton/PinyaAnchorButtonProps.d.ts.map +1 -0
  305. package/dist/ui/elements/PinyaAnchorButton/index.d.ts +1 -0
  306. package/dist/ui/elements/PinyaAnchorButton/index.d.ts.map +1 -0
  307. package/dist/ui/elements/PinyaButton/PinyaButton.svelte +2 -2
  308. package/dist/ui/elements/PinyaButton/PinyaButton.svelte.d.ts +15 -4
  309. package/dist/ui/elements/PinyaButton/PinyaButton.svelte.d.ts.map +1 -0
  310. package/dist/ui/elements/PinyaButton/PinyaButtonProps.d.ts +1 -0
  311. package/dist/ui/elements/PinyaButton/PinyaButtonProps.d.ts.map +1 -0
  312. package/dist/ui/elements/PinyaButton/index.d.ts +1 -0
  313. package/dist/ui/elements/PinyaButton/index.d.ts.map +1 -0
  314. package/dist/ui/elements/PinyaButtonCommon/ButtonVariant.d.ts +4 -3
  315. package/dist/ui/elements/PinyaButtonCommon/ButtonVariant.d.ts.map +1 -0
  316. package/dist/ui/elements/PinyaButtonCommon/ButtonVariant.js +3 -3
  317. package/dist/ui/elements/PinyaButtonCommon/PinyaButtonCommonProps.d.ts +4 -0
  318. package/dist/ui/elements/PinyaButtonCommon/PinyaButtonCommonProps.d.ts.map +1 -0
  319. package/dist/ui/elements/PinyaButtonCommon/createButtonClass.d.ts +1 -0
  320. package/dist/ui/elements/PinyaButtonCommon/createButtonClass.d.ts.map +1 -0
  321. package/dist/ui/elements/PinyaButtonCommon/createButtonClass.js +4 -22
  322. package/dist/ui/elements/PinyaButtonCommon/index.d.ts +1 -0
  323. package/dist/ui/elements/PinyaButtonCommon/index.d.ts.map +1 -0
  324. package/dist/ui/elements/PinyaCard/PinyaCard.svelte +66 -24
  325. package/dist/ui/elements/PinyaCard/PinyaCard.svelte.d.ts +16 -4
  326. package/dist/ui/elements/PinyaCard/PinyaCard.svelte.d.ts.map +1 -0
  327. package/dist/ui/elements/PinyaCard/PinyaCardProps.d.ts +12 -3
  328. package/dist/ui/elements/PinyaCard/PinyaCardProps.d.ts.map +1 -0
  329. package/dist/ui/elements/PinyaCard/index.d.ts +1 -0
  330. package/dist/ui/elements/PinyaCard/index.d.ts.map +1 -0
  331. package/dist/ui/elements/Placeholder.svelte +4 -0
  332. package/dist/ui/elements/Placeholder.svelte.d.ts +18 -6
  333. package/dist/ui/elements/Placeholder.svelte.d.ts.map +1 -0
  334. package/dist/ui/elements/TextChip/TextChip.svelte +5 -1
  335. package/dist/ui/elements/TextChip/TextChip.svelte.d.ts +19 -4
  336. package/dist/ui/elements/TextChip/TextChip.svelte.d.ts.map +1 -0
  337. package/dist/ui/elements/TextChip/TextChipProps.d.ts +1 -0
  338. package/dist/ui/elements/TextChip/TextChipProps.d.ts.map +1 -0
  339. package/dist/ui/elements/TextChip/index.d.ts +1 -0
  340. package/dist/ui/elements/TextChip/index.d.ts.map +1 -0
  341. package/dist/ui/elements/TextLink.svelte +10 -5
  342. package/dist/ui/elements/TextLink.svelte.d.ts +18 -7
  343. package/dist/ui/elements/TextLink.svelte.d.ts.map +1 -0
  344. package/dist/ui/elements/WrapperProps.d.ts +1 -0
  345. package/dist/ui/elements/WrapperProps.d.ts.map +1 -0
  346. package/dist/ui/elements/index.d.ts +1 -0
  347. package/dist/ui/elements/index.d.ts.map +1 -0
  348. package/dist/ui/elements/pinya-combobox/PinyaCombobox.svelte +118 -24
  349. package/dist/ui/elements/pinya-combobox/PinyaCombobox.svelte.d.ts +17 -22
  350. package/dist/ui/elements/pinya-combobox/PinyaCombobox.svelte.d.ts.map +1 -0
  351. package/dist/ui/elements/pinya-combobox/PinyaComboboxProps.d.ts +9 -7
  352. package/dist/ui/elements/pinya-combobox/PinyaComboboxProps.d.ts.map +1 -0
  353. package/dist/ui/modules/NavigationMenu/NavigationControl.svelte.d.ts +14 -7
  354. package/dist/ui/modules/NavigationMenu/NavigationControl.svelte.d.ts.map +1 -0
  355. package/dist/ui/modules/NavigationMenu/NavigationMenu.svelte +5 -5
  356. package/dist/ui/modules/NavigationMenu/NavigationMenu.svelte.d.ts +14 -21
  357. package/dist/ui/modules/NavigationMenu/NavigationMenu.svelte.d.ts.map +1 -0
  358. package/dist/ui/modules/NavigationMenu/PageMeta.d.ts +1 -0
  359. package/dist/ui/modules/NavigationMenu/PageMeta.d.ts.map +1 -0
  360. package/dist/ui/modules/NavigationMenu/index.d.ts +1 -0
  361. package/dist/ui/modules/NavigationMenu/index.d.ts.map +1 -0
  362. package/dist/ui/modules/index.d.ts +2 -1
  363. package/dist/ui/modules/index.d.ts.map +1 -0
  364. package/dist/ui/modules/index.js +1 -1
  365. package/dist/ui/modules/modals/general-settings/GeneralSettingsModal.svelte +19 -41
  366. package/dist/ui/modules/modals/general-settings/GeneralSettingsModal.svelte.d.ts +15 -4
  367. package/dist/ui/modules/modals/general-settings/GeneralSettingsModal.svelte.d.ts.map +1 -0
  368. package/dist/ui/modules/modals/general-settings/LanguagePicker.svelte +8 -10
  369. package/dist/ui/modules/modals/general-settings/LanguagePicker.svelte.d.ts +15 -3
  370. package/dist/ui/modules/modals/general-settings/LanguagePicker.svelte.d.ts.map +1 -0
  371. package/dist/ui/modules/projects/Hepcat.svelte +1 -1
  372. package/dist/ui/modules/projects/Hepcat.svelte.d.ts +12 -16
  373. package/dist/ui/modules/projects/Hepcat.svelte.d.ts.map +1 -0
  374. package/dist/ui/modules/projects/Pengi.svelte +1 -1
  375. package/dist/ui/modules/projects/Pengi.svelte.d.ts +12 -16
  376. package/dist/ui/modules/projects/Pengi.svelte.d.ts.map +1 -0
  377. package/dist/ui/modules/projects/Soulwork.svelte.d.ts +12 -16
  378. package/dist/ui/modules/projects/Soulwork.svelte.d.ts.map +1 -0
  379. package/dist/ui/modules/projects/ThisWebpage.svelte.d.ts +12 -16
  380. package/dist/ui/modules/projects/ThisWebpage.svelte.d.ts.map +1 -0
  381. package/dist/ui/modules/projects/index.d.ts +1 -0
  382. package/dist/ui/modules/projects/index.d.ts.map +1 -0
  383. package/dist/ui/modules/universal-overlay/DialogPanel.svelte +37 -0
  384. package/dist/ui/modules/universal-overlay/DialogPanel.svelte.d.ts +16 -0
  385. package/dist/ui/modules/universal-overlay/DialogPanel.svelte.d.ts.map +1 -0
  386. package/dist/ui/modules/universal-overlay/SettingsPanel.svelte +152 -0
  387. package/dist/ui/modules/universal-overlay/SettingsPanel.svelte.d.ts +20 -0
  388. package/dist/ui/modules/universal-overlay/SettingsPanel.svelte.d.ts.map +1 -0
  389. package/dist/ui/modules/universal-overlay/UniversalOverlay.svelte +302 -0
  390. package/dist/ui/modules/universal-overlay/UniversalOverlay.svelte.d.ts +23 -0
  391. package/dist/ui/modules/universal-overlay/UniversalOverlay.svelte.d.ts.map +1 -0
  392. package/dist/ui/templates/PinyaPageLayout/PinyaPageLayout.svelte +6 -6
  393. package/dist/ui/templates/PinyaPageLayout/PinyaPageLayout.svelte.d.ts +14 -8
  394. package/dist/ui/templates/PinyaPageLayout/PinyaPageLayout.svelte.d.ts.map +1 -0
  395. package/dist/ui/templates/PinyaPageLayout/index.d.ts +2 -1
  396. package/dist/ui/templates/PinyaPageLayout/index.d.ts.map +1 -0
  397. package/dist/ui/templates/PinyaPageLayout/index.js +1 -1
  398. package/dist/ui/templates/PinyaPageLayout/{runes.svelte.d.ts → pinyaPageLayoutRunes.svelte.d.ts} +1 -0
  399. package/dist/ui/templates/PinyaPageLayout/pinyaPageLayoutRunes.svelte.d.ts.map +1 -0
  400. package/dist/ui/templates/SeaweedLayout/ChumBucket.svelte +1 -1
  401. package/dist/ui/templates/SeaweedLayout/ChumBucket.svelte.d.ts +15 -3
  402. package/dist/ui/templates/SeaweedLayout/ChumBucket.svelte.d.ts.map +1 -0
  403. package/dist/ui/templates/SeaweedLayout/CreateUrlForm.svelte +10 -12
  404. package/dist/ui/templates/SeaweedLayout/CreateUrlForm.svelte.d.ts +14 -8
  405. package/dist/ui/templates/SeaweedLayout/CreateUrlForm.svelte.d.ts.map +1 -0
  406. package/dist/ui/templates/SeaweedLayout/EntryGroup.svelte +9 -8
  407. package/dist/ui/templates/SeaweedLayout/EntryGroup.svelte.d.ts +15 -4
  408. package/dist/ui/templates/SeaweedLayout/EntryGroup.svelte.d.ts.map +1 -0
  409. package/dist/ui/templates/SeaweedLayout/EntryOrderConfig.svelte.d.ts +14 -8
  410. package/dist/ui/templates/SeaweedLayout/EntryOrderConfig.svelte.d.ts.map +1 -0
  411. package/dist/ui/templates/SeaweedLayout/ProjectComponentProps.d.ts +1 -0
  412. package/dist/ui/templates/SeaweedLayout/ProjectComponentProps.d.ts.map +1 -0
  413. package/dist/ui/templates/SeaweedLayout/ProjectGroupConfig.svelte +22 -12
  414. package/dist/ui/templates/SeaweedLayout/ProjectGroupConfig.svelte.d.ts +14 -13
  415. package/dist/ui/templates/SeaweedLayout/ProjectGroupConfig.svelte.d.ts.map +1 -0
  416. package/dist/ui/templates/SeaweedLayout/SeaweedLayout.svelte +5 -0
  417. package/dist/ui/templates/SeaweedLayout/SeaweedLayout.svelte.d.ts +15 -4
  418. package/dist/ui/templates/SeaweedLayout/SeaweedLayout.svelte.d.ts.map +1 -0
  419. package/dist/ui/templates/SeaweedLayout/index.d.ts +1 -0
  420. package/dist/ui/templates/SeaweedLayout/index.d.ts.map +1 -0
  421. package/dist/ui/templates/SeaweedLayout/props.d.ts +1 -0
  422. package/dist/ui/templates/SeaweedLayout/props.d.ts.map +1 -0
  423. package/dist/ui/templates/blog_template/BlogTemplate.svelte +9 -6
  424. package/dist/ui/templates/blog_template/BlogTemplate.svelte.d.ts +14 -11
  425. package/dist/ui/templates/blog_template/BlogTemplate.svelte.d.ts.map +1 -0
  426. package/dist/ui/templates/blog_template/BlogTemplateInner.svelte +2 -2
  427. package/dist/ui/templates/blog_template/BlogTemplateInner.svelte.d.ts +14 -7
  428. package/dist/ui/templates/blog_template/BlogTemplateInner.svelte.d.ts.map +1 -0
  429. package/dist/ui/templates/confirmation-modal/component.svelte +1 -1
  430. package/dist/ui/templates/confirmation-modal/component.svelte.d.ts +15 -4
  431. package/dist/ui/templates/confirmation-modal/component.svelte.d.ts.map +1 -0
  432. package/dist/ui/templates/confirmation-modal/index.d.ts +1 -0
  433. package/dist/ui/templates/confirmation-modal/index.d.ts.map +1 -0
  434. package/dist/ui/templates/confirmation-modal/props.d.ts +1 -0
  435. package/dist/ui/templates/confirmation-modal/props.d.ts.map +1 -0
  436. package/dist/ui/templates/index.d.ts +2 -1
  437. package/dist/ui/templates/index.d.ts.map +1 -0
  438. package/dist/ui/templates/index.js +1 -1
  439. package/dist/ui/templates/{PinyaBase.svelte → pinya-base/PinyaBase.svelte} +42 -31
  440. package/dist/ui/templates/pinya-base/PinyaBase.svelte.d.ts +17 -0
  441. package/dist/ui/templates/pinya-base/PinyaBase.svelte.d.ts.map +1 -0
  442. package/dist/ui/templates/{runes.svelte.d.ts → pinya-base/pinyaBaseRunes.svelte.d.ts} +1 -0
  443. package/dist/ui/templates/pinya-base/pinyaBaseRunes.svelte.d.ts.map +1 -0
  444. package/dist/ui/templates/{runes.svelte.js → pinya-base/pinyaBaseRunes.svelte.js} +1 -1
  445. package/dist/util/context/PineappleBaseContext.svelte +52 -0
  446. package/dist/util/context/PineappleBaseContext.svelte.d.ts +15 -0
  447. package/dist/util/context/PineappleBaseContext.svelte.d.ts.map +1 -0
  448. package/dist/util/context/pineappleBaseContextDefinitions.d.ts +7 -0
  449. package/dist/util/context/pineappleBaseContextDefinitions.d.ts.map +1 -0
  450. package/dist/util/context/pineappleBaseContextDefinitions.js +6 -0
  451. package/dist/util/env-getter.d.ts +1 -0
  452. package/dist/util/env-getter.d.ts.map +1 -0
  453. package/dist/util/env-getter.js +5 -2
  454. package/dist/util/localStore.svelte.d.ts +17 -0
  455. package/dist/util/localStore.svelte.d.ts.map +1 -0
  456. package/dist/util/localStore.svelte.js +76 -0
  457. package/dist/util/util.d.ts +1 -0
  458. package/dist/util/util.d.ts.map +1 -0
  459. package/package.json +42 -41
  460. package/src/lib/styles/app.css +61 -21
  461. package/dist/ui/modules/dialog_overlay/DialogOverlay.svelte +0 -239
  462. package/dist/ui/modules/dialog_overlay/DialogOverlay.svelte.d.ts +0 -3
  463. package/dist/ui/templates/PinyaBase.svelte.d.ts +0 -7
  464. /package/dist/{ui/templates/SeaweedLayout/ToastSettings.js → components/reveal-info/RevealInfoCollection.js} +0 -0
  465. /package/dist/ui/templates/PinyaPageLayout/{runes.svelte.js → pinyaPageLayoutRunes.svelte.js} +0 -0
@@ -0,0 +1,1406 @@
1
+ /* eslint-disable */
2
+
3
+ /** @type {any} */
4
+ const URLPattern = {}
5
+
6
+ /**
7
+ * The project's base locale.
8
+ *
9
+ * @example
10
+ * if (locale === baseLocale) {
11
+ * // do something
12
+ * }
13
+ */
14
+ export const baseLocale = "en";
15
+ /**
16
+ * The project's locales that have been specified in the settings.
17
+ *
18
+ * @example
19
+ * if (locales.includes(userSelectedLocale) === false) {
20
+ * throw new Error('Locale is not available');
21
+ * }
22
+ */
23
+ export const locales = /** @type {const} */ (["en", "fr", "tl"]);
24
+ /** @type {string} */
25
+ export const cookieName = "PARAGLIDE_LOCALE";
26
+ /** @type {number} */
27
+ export const cookieMaxAge = 34560000;
28
+ /** @type {string} */
29
+ export const cookieDomain = "";
30
+ /** @type {string} */
31
+ export const localStorageKey = "PARAGLIDE_LOCALE";
32
+ /**
33
+ * @type {Array<"cookie" | "baseLocale" | "globalVariable" | "url" | "preferredLanguage" | "localStorage" | `custom-${string}`>}
34
+ */
35
+ export const strategy = [
36
+ "url",
37
+ "cookie",
38
+ "baseLocale"
39
+ ];
40
+ /**
41
+ * The used URL patterns.
42
+ *
43
+ * @type {Array<{ pattern: string, localized: Array<[Locale, string]> }> }
44
+ */
45
+ export const urlPatterns = [
46
+ {
47
+ "pattern": ":protocol://:domain(.*)::port?/:path(.*)?",
48
+ "localized": [
49
+ [
50
+ "fr",
51
+ ":protocol://:domain(.*)::port?/fr/:path(.*)?"
52
+ ],
53
+ [
54
+ "tl",
55
+ ":protocol://:domain(.*)::port?/tl/:path(.*)?"
56
+ ],
57
+ [
58
+ "en",
59
+ ":protocol://:domain(.*)::port?/:path(.*)?"
60
+ ]
61
+ ]
62
+ }
63
+ ];
64
+ /**
65
+ * @typedef {{
66
+ * getStore(): {
67
+ * locale?: Locale,
68
+ * origin?: string,
69
+ * messageCalls?: Set<string>
70
+ * } | undefined,
71
+ * run: (store: { locale?: Locale, origin?: string, messageCalls?: Set<string>},
72
+ * cb: any) => any
73
+ * }} ParaglideAsyncLocalStorage
74
+ */
75
+ /**
76
+ * Server side async local storage that is set by `serverMiddleware()`.
77
+ *
78
+ * The variable is used to retrieve the locale and origin in a server-side
79
+ * rendering context without effecting other requests.
80
+ *
81
+ * @type {ParaglideAsyncLocalStorage | undefined}
82
+ */
83
+ export let serverAsyncLocalStorage = undefined;
84
+ export const disableAsyncLocalStorage = false;
85
+ export const experimentalMiddlewareLocaleSplitting = false;
86
+ export const isServer = import.meta.env?.SSR ?? typeof window === 'undefined';
87
+ /**
88
+ * Sets the server side async local storage.
89
+ *
90
+ * The function is needed because the `runtime.js` file
91
+ * must define the `serverAsyncLocalStorage` variable to
92
+ * avoid a circular import between `runtime.js` and
93
+ * `server.js` files.
94
+ *
95
+ * @param {ParaglideAsyncLocalStorage | undefined} value
96
+ */
97
+ export function overwriteServerAsyncLocalStorage(value) {
98
+ serverAsyncLocalStorage = value;
99
+ }
100
+ const TREE_SHAKE_COOKIE_STRATEGY_USED = true;
101
+ const TREE_SHAKE_URL_STRATEGY_USED = true;
102
+ const TREE_SHAKE_GLOBAL_VARIABLE_STRATEGY_USED = false;
103
+ const TREE_SHAKE_PREFERRED_LANGUAGE_STRATEGY_USED = false;
104
+ const TREE_SHAKE_DEFAULT_URL_PATTERN_USED = true;
105
+ const TREE_SHAKE_LOCAL_STORAGE_STRATEGY_USED = false;
106
+
107
+ globalThis.__paraglide = {}
108
+
109
+ /**
110
+ * This is a fallback to get started with a custom
111
+ * strategy and avoid type errors.
112
+ *
113
+ * The implementation is overwritten
114
+ * by \`overwriteGetLocale()\` and \`defineSetLocale()\`.
115
+ *
116
+ * @type {Locale|undefined}
117
+ */
118
+ let _locale;
119
+ let localeInitiallySet = false;
120
+ /**
121
+ * Get the current locale.
122
+ *
123
+ * @example
124
+ * if (getLocale() === 'de') {
125
+ * console.log('Germany 🇩🇪');
126
+ * } else if (getLocale() === 'nl') {
127
+ * console.log('Netherlands 🇳🇱');
128
+ * }
129
+ *
130
+ * @type {() => Locale}
131
+ */
132
+ export let getLocale = () => {
133
+ /** @type {string | undefined} */
134
+ let locale;
135
+ // if running in a server-side rendering context
136
+ // retrieve the locale from the async local storage
137
+ if (serverAsyncLocalStorage) {
138
+ const locale = serverAsyncLocalStorage?.getStore()?.locale;
139
+ if (locale) {
140
+ return locale;
141
+ }
142
+ }
143
+ for (const strat of strategy) {
144
+ if (TREE_SHAKE_COOKIE_STRATEGY_USED && strat === "cookie") {
145
+ locale = extractLocaleFromCookie();
146
+ }
147
+ else if (strat === "baseLocale") {
148
+ locale = baseLocale;
149
+ }
150
+ else if (TREE_SHAKE_URL_STRATEGY_USED &&
151
+ strat === "url" &&
152
+ !isServer &&
153
+ typeof window !== "undefined") {
154
+ locale = extractLocaleFromUrl(window.location.href);
155
+ }
156
+ else if (TREE_SHAKE_GLOBAL_VARIABLE_STRATEGY_USED &&
157
+ strat === "globalVariable" &&
158
+ _locale !== undefined) {
159
+ locale = _locale;
160
+ }
161
+ else if (TREE_SHAKE_PREFERRED_LANGUAGE_STRATEGY_USED &&
162
+ strat === "preferredLanguage" &&
163
+ !isServer) {
164
+ locale = extractLocaleFromNavigator();
165
+ }
166
+ else if (TREE_SHAKE_LOCAL_STORAGE_STRATEGY_USED &&
167
+ strat === "localStorage" &&
168
+ !isServer) {
169
+ locale = localStorage.getItem(localStorageKey) ?? undefined;
170
+ }
171
+ else if (isCustomStrategy(strat) && customClientStrategies.has(strat)) {
172
+ const handler = customClientStrategies.get(strat);
173
+ if (handler) {
174
+ const result = handler.getLocale();
175
+ // Handle both sync and async results - skip async in sync getLocale
176
+ if (result instanceof Promise) {
177
+ // Can't await in sync function, skip async strategies
178
+ continue;
179
+ }
180
+ locale = result;
181
+ }
182
+ }
183
+ // check if match, else continue loop
184
+ if (locale !== undefined) {
185
+ const asserted = assertIsLocale(locale);
186
+ if (!localeInitiallySet) {
187
+ _locale = asserted;
188
+ // https://github.com/opral/inlang-paraglide-js/issues/455
189
+ localeInitiallySet = true;
190
+ setLocale(asserted, { reload: false });
191
+ }
192
+ return asserted;
193
+ }
194
+ }
195
+ throw new Error("No locale found. Read the docs https://inlang.com/m/gerre34r/library-inlang-paraglideJs/errors#no-locale-found");
196
+ };
197
+ /**
198
+ * Overwrite the \`getLocale()\` function.
199
+ *
200
+ * Use this function to overwrite how the locale is resolved. For example,
201
+ * you can resolve the locale from the browser's preferred language,
202
+ * a cookie, env variable, or a user's preference.
203
+ *
204
+ * @example
205
+ * overwriteGetLocale(() => {
206
+ * // resolve the locale from a cookie. fallback to the base locale.
207
+ * return Cookies.get('locale') ?? baseLocale
208
+ * }
209
+ *
210
+ * @type {(fn: () => Locale) => void}
211
+ */
212
+ export const overwriteGetLocale = (fn) => {
213
+ getLocale = fn;
214
+ };
215
+
216
+ /**
217
+ * Navigates to the localized URL, or reloads the current page
218
+ *
219
+ * @param {string} [newLocation] The new location
220
+ * @return {undefined}
221
+ */
222
+ const navigateOrReload = (newLocation) => {
223
+ if (newLocation) {
224
+ // reload the page by navigating to the new url
225
+ window.location.href = newLocation;
226
+ }
227
+ else {
228
+ // reload the page to reflect the new locale
229
+ window.location.reload();
230
+ }
231
+ };
232
+ /**
233
+ * @typedef {(newLocale: Locale, options?: { reload?: boolean }) => void | Promise<void>} SetLocaleFn
234
+ */
235
+ /**
236
+ * Set the locale.
237
+ *
238
+ * Set locale reloads the site by default on the client. Reloading
239
+ * can be disabled by passing \`reload: false\` as an option. If
240
+ * reloading is disabled, you need to ensure that the UI is updated
241
+ * to reflect the new locale.
242
+ *
243
+ * If any custom strategy's \`setLocale\` function is async, then this
244
+ * function will become async as well.
245
+ *
246
+ * @example
247
+ * setLocale('en');
248
+ *
249
+ * @example
250
+ * setLocale('en', { reload: false });
251
+ *
252
+ * @type {SetLocaleFn}
253
+ */
254
+ export let setLocale = (newLocale, options) => {
255
+ const optionsWithDefaults = {
256
+ reload: true,
257
+ ...options,
258
+ };
259
+ // locale is already set
260
+ // https://github.com/opral/inlang-paraglide-js/issues/430
261
+ /** @type {Locale | undefined} */
262
+ let currentLocale;
263
+ try {
264
+ currentLocale = getLocale();
265
+ }
266
+ catch {
267
+ // do nothing, no locale has been set yet.
268
+ }
269
+ /** @type {Array<Promise<any>>} */
270
+ const customSetLocalePromises = [];
271
+ /** @type {string | undefined} */
272
+ let newLocation = undefined;
273
+ for (const strat of strategy) {
274
+ if (TREE_SHAKE_GLOBAL_VARIABLE_STRATEGY_USED &&
275
+ strat === "globalVariable") {
276
+ // a default for a custom strategy to get started quickly
277
+ // is likely overwritten by `defineSetLocale()`
278
+ _locale = newLocale;
279
+ }
280
+ else if (TREE_SHAKE_COOKIE_STRATEGY_USED && strat === "cookie") {
281
+ if (isServer ||
282
+ typeof document === "undefined" ||
283
+ typeof window === "undefined") {
284
+ continue;
285
+ }
286
+ // set the cookie
287
+ const cookieString = `${cookieName}=${newLocale}; path=/; max-age=${cookieMaxAge}`;
288
+ document.cookie = cookieDomain
289
+ ? `${cookieString}; domain=${cookieDomain}`
290
+ : cookieString;
291
+ }
292
+ else if (strat === "baseLocale") {
293
+ // nothing to be set here. baseLocale is only a fallback
294
+ continue;
295
+ }
296
+ else if (TREE_SHAKE_URL_STRATEGY_USED &&
297
+ strat === "url" &&
298
+ typeof window !== "undefined") {
299
+ // route to the new url
300
+ //
301
+ // this triggers a page reload but a user rarely
302
+ // switches locales, so this should be fine.
303
+ //
304
+ // if the behavior is not desired, the implementation
305
+ // can be overwritten by `defineSetLocale()` to avoid
306
+ // a full page reload.
307
+ newLocation = localizeUrl(window.location.href, {
308
+ locale: newLocale,
309
+ }).href;
310
+ }
311
+ else if (TREE_SHAKE_LOCAL_STORAGE_STRATEGY_USED &&
312
+ strat === "localStorage" &&
313
+ typeof window !== "undefined") {
314
+ // set the localStorage
315
+ localStorage.setItem(localStorageKey, newLocale);
316
+ }
317
+ else if (isCustomStrategy(strat) && customClientStrategies.has(strat)) {
318
+ const handler = customClientStrategies.get(strat);
319
+ if (handler) {
320
+ let result = handler.setLocale(newLocale);
321
+ // Handle async setLocale
322
+ if (result instanceof Promise) {
323
+ result = result.catch((error) => {
324
+ throw new Error(`Custom strategy "${strat}" setLocale failed.`, {
325
+ cause: error,
326
+ });
327
+ });
328
+ customSetLocalePromises.push(result);
329
+ }
330
+ }
331
+ }
332
+ }
333
+ const runReload = () => {
334
+ if (!isServer &&
335
+ optionsWithDefaults.reload &&
336
+ window.location &&
337
+ newLocale !== currentLocale) {
338
+ navigateOrReload(newLocation);
339
+ }
340
+ };
341
+ if (customSetLocalePromises.length) {
342
+ return Promise.all(customSetLocalePromises).then(() => {
343
+ runReload();
344
+ });
345
+ }
346
+ runReload();
347
+ return;
348
+ };
349
+ /**
350
+ * Overwrite the \`setLocale()\` function.
351
+ *
352
+ * Use this function to overwrite how the locale is set. For example,
353
+ * modify a cookie, env variable, or a user's preference.
354
+ *
355
+ * @example
356
+ * overwriteSetLocale((newLocale) => {
357
+ * // set the locale in a cookie
358
+ * return Cookies.set('locale', newLocale)
359
+ * });
360
+ *
361
+ * @param {SetLocaleFn} fn
362
+ */
363
+ export const overwriteSetLocale = (fn) => {
364
+ setLocale = /** @type {SetLocaleFn} */ (fn);
365
+ };
366
+
367
+ /**
368
+ * The origin of the current URL.
369
+ *
370
+ * Defaults to "http://y.com" in non-browser environments. If this
371
+ * behavior is not desired, the implementation can be overwritten
372
+ * by `overwriteGetUrlOrigin()`.
373
+ *
374
+ * @type {() => string}
375
+ */
376
+ export let getUrlOrigin = () => {
377
+ if (serverAsyncLocalStorage) {
378
+ return serverAsyncLocalStorage.getStore()?.origin ?? "http://fallback.com";
379
+ }
380
+ else if (typeof window !== "undefined") {
381
+ return window.location.origin;
382
+ }
383
+ return "http://fallback.com";
384
+ };
385
+ /**
386
+ * Overwrite the getUrlOrigin function.
387
+ *
388
+ * Use this function in server environments to
389
+ * define how the URL origin is resolved.
390
+ *
391
+ * @type {(fn: () => string) => void}
392
+ */
393
+ export let overwriteGetUrlOrigin = (fn) => {
394
+ getUrlOrigin = fn;
395
+ };
396
+
397
+ /**
398
+ * Check if something is an available locale.
399
+ *
400
+ * @example
401
+ * if (isLocale(params.locale)) {
402
+ * setLocale(params.locale);
403
+ * } else {
404
+ * setLocale('en');
405
+ * }
406
+ *
407
+ * @param {any} locale
408
+ * @returns {locale is Locale}
409
+ */
410
+ export function isLocale(locale) {
411
+ return !locale ? false : locales.includes(locale);
412
+ }
413
+
414
+ /**
415
+ * Asserts that the input is a locale.
416
+ *
417
+ * @param {any} input - The input to check.
418
+ * @returns {Locale} The input if it is a locale.
419
+ * @throws {Error} If the input is not a locale.
420
+ */
421
+ export function assertIsLocale(input) {
422
+ if (isLocale(input) === false) {
423
+ throw new Error(`Invalid locale: ${input}. Expected one of: ${locales.join(", ")}`);
424
+ }
425
+ return input;
426
+ }
427
+
428
+ /**
429
+ * Extracts a locale from a request.
430
+ *
431
+ * Use the function on the server to extract the locale
432
+ * from a request.
433
+ *
434
+ * The function goes through the strategies in the order
435
+ * they are defined. If a strategy returns an invalid locale,
436
+ * it will fall back to the next strategy.
437
+ *
438
+ * Note: Custom server strategies are not supported in this synchronous version.
439
+ * Use `extractLocaleFromRequestAsync` if you need custom server strategies with async getLocale methods.
440
+ *
441
+ * @example
442
+ * const locale = extractLocaleFromRequest(request);
443
+ *
444
+ * @type {(request: Request) => Locale}
445
+ */
446
+ export const extractLocaleFromRequest = (request) => {
447
+ /** @type {string|undefined} */
448
+ let locale;
449
+ for (const strat of strategy) {
450
+ if (TREE_SHAKE_COOKIE_STRATEGY_USED && strat === "cookie") {
451
+ locale = request.headers
452
+ .get("cookie")
453
+ ?.split("; ")
454
+ .find((c) => c.startsWith(cookieName + "="))
455
+ ?.split("=")[1];
456
+ }
457
+ else if (TREE_SHAKE_URL_STRATEGY_USED && strat === "url") {
458
+ locale = extractLocaleFromUrl(request.url);
459
+ }
460
+ else if (TREE_SHAKE_PREFERRED_LANGUAGE_STRATEGY_USED &&
461
+ strat === "preferredLanguage") {
462
+ locale = extractLocaleFromHeader(request);
463
+ }
464
+ else if (strat === "globalVariable") {
465
+ locale = _locale;
466
+ }
467
+ else if (strat === "baseLocale") {
468
+ return baseLocale;
469
+ }
470
+ else if (strat === "localStorage") {
471
+ continue;
472
+ }
473
+ else if (isCustomStrategy(strat)) {
474
+ // Custom strategies are not supported in sync version
475
+ // Use extractLocaleFromRequestAsync for custom server strategies
476
+ continue;
477
+ }
478
+ if (locale !== undefined) {
479
+ if (!isLocale(locale)) {
480
+ locale = undefined;
481
+ }
482
+ else {
483
+ return assertIsLocale(locale);
484
+ }
485
+ }
486
+ }
487
+ throw new Error("No locale found. There is an error in your strategy. Try adding 'baseLocale' as the very last strategy. Read more here https://inlang.com/m/gerre34r/library-inlang-paraglideJs/errors#no-locale-found");
488
+ };
489
+
490
+ /**
491
+ * Asynchronously extracts a locale from a request.
492
+ *
493
+ * This function supports async custom server strategies, unlike the synchronous
494
+ * `extractLocaleFromRequest`. Use this function when you have custom server strategies
495
+ * that need to perform asynchronous operations (like database calls) in their getLocale method.
496
+ *
497
+ * The function first processes any custom server strategies asynchronously, then falls back
498
+ * to the synchronous `extractLocaleFromRequest` for all other strategies.
499
+ *
500
+ * @see {@link https://github.com/opral/inlang-paraglide-js/issues/527#issuecomment-2978151022}
501
+ *
502
+ * @example
503
+ * // Basic usage
504
+ * const locale = await extractLocaleFromRequestAsync(request);
505
+ *
506
+ * @example
507
+ * // With custom async server strategy
508
+ * defineCustomServerStrategy("custom-database", {
509
+ * getLocale: async (request) => {
510
+ * const userId = extractUserIdFromRequest(request);
511
+ * return await getUserLocaleFromDatabase(userId);
512
+ * }
513
+ * });
514
+ *
515
+ * const locale = await extractLocaleFromRequestAsync(request);
516
+ *
517
+ * @type {(request: Request) => Promise<Locale>}
518
+ */
519
+ export const extractLocaleFromRequestAsync = async (request) => {
520
+ /** @type {string|undefined} */
521
+ let locale;
522
+ // Process custom strategies first, in order
523
+ for (const strat of strategy) {
524
+ if (isCustomStrategy(strat) && customServerStrategies.has(strat)) {
525
+ const handler = customServerStrategies.get(strat);
526
+ if (handler) {
527
+ /** @type {string|undefined} */
528
+ locale = await handler.getLocale(request);
529
+ }
530
+ // If we got a valid locale from this custom strategy, use it
531
+ if (locale !== undefined && isLocale(locale)) {
532
+ return assertIsLocale(locale);
533
+ }
534
+ }
535
+ }
536
+ // If no custom strategy provided a valid locale, fall back to sync version
537
+ locale = extractLocaleFromRequest(request);
538
+ return assertIsLocale(locale);
539
+ };
540
+
541
+ /**
542
+ * Extracts a cookie from the document.
543
+ *
544
+ * Will return undefined if the document is not available or if the cookie is not set.
545
+ * The `document` object is not available in server-side rendering, so this function should not be called in that context.
546
+ *
547
+ * @returns {string | undefined}
548
+ */
549
+ export function extractLocaleFromCookie() {
550
+ if (typeof document === "undefined" || !document.cookie) {
551
+ return;
552
+ }
553
+ const match = document.cookie.match(new RegExp(`(^| )${cookieName}=([^;]+)`));
554
+ const locale = match?.[2];
555
+ if (isLocale(locale)) {
556
+ return locale;
557
+ }
558
+ return undefined;
559
+ }
560
+
561
+ /**
562
+ * Extracts a locale from the accept-language header.
563
+ *
564
+ * Use the function on the server to extract the locale
565
+ * from the accept-language header that is sent by the client.
566
+ *
567
+ * @example
568
+ * const locale = extractLocaleFromHeader(request);
569
+ *
570
+ * @type {(request: Request) => Locale}
571
+ * @param {Request} request - The request object to extract the locale from.
572
+ * @returns {string|undefined} The negotiated preferred language.
573
+ */
574
+ export function extractLocaleFromHeader(request) {
575
+ const acceptLanguageHeader = request.headers.get("accept-language");
576
+ if (acceptLanguageHeader) {
577
+ // Parse language preferences with their q-values and base language codes
578
+ const languages = acceptLanguageHeader
579
+ .split(",")
580
+ .map((lang) => {
581
+ const [tag, q = "1"] = lang.trim().split(";q=");
582
+ // Get both the full tag and base language code
583
+ const baseTag = tag?.split("-")[0]?.toLowerCase();
584
+ return {
585
+ fullTag: tag?.toLowerCase(),
586
+ baseTag,
587
+ q: Number(q),
588
+ };
589
+ })
590
+ .sort((a, b) => b.q - a.q);
591
+ for (const lang of languages) {
592
+ if (isLocale(lang.fullTag)) {
593
+ return lang.fullTag;
594
+ }
595
+ else if (isLocale(lang.baseTag)) {
596
+ return lang.baseTag;
597
+ }
598
+ }
599
+ return undefined;
600
+ }
601
+ return undefined;
602
+ }
603
+
604
+ /**
605
+ * Negotiates a preferred language from navigator.languages.
606
+ *
607
+ * Use the function on the client to extract the locale
608
+ * from the navigator.languages array.
609
+ *
610
+ * @example
611
+ * const locale = extractLocaleFromNavigator();
612
+ *
613
+ * @type {() => Locale | undefined}
614
+ * @returns {string | undefined}
615
+ */
616
+ export function extractLocaleFromNavigator() {
617
+ if (!navigator?.languages?.length) {
618
+ return undefined;
619
+ }
620
+ const languages = navigator.languages.map((lang) => ({
621
+ fullTag: lang.toLowerCase(),
622
+ baseTag: lang.split("-")[0]?.toLowerCase(),
623
+ }));
624
+ for (const lang of languages) {
625
+ if (isLocale(lang.fullTag)) {
626
+ return lang.fullTag;
627
+ }
628
+ else if (isLocale(lang.baseTag)) {
629
+ return lang.baseTag;
630
+ }
631
+ }
632
+ return undefined;
633
+ }
634
+
635
+ /**
636
+ * If extractLocaleFromUrl is called many times on the same page and the URL
637
+ * hasn't changed, we don't need to recompute it every time which can get expensive.
638
+ * We might use a LRU cache if needed, but for now storing only the last result is enough.
639
+ * https://github.com/opral/monorepo/pull/3575#discussion_r2066731243
640
+ */
641
+ /** @type {string|undefined} */
642
+ let cachedUrl;
643
+ /** @type {Locale|undefined} */
644
+ let cachedLocale;
645
+ /**
646
+ * Extracts the locale from a given URL using native URLPattern.
647
+ *
648
+ * @param {URL|string} url - The full URL from which to extract the locale.
649
+ * @returns {Locale|undefined} The extracted locale, or undefined if no locale is found.
650
+ */
651
+ export function extractLocaleFromUrl(url) {
652
+ const urlString = typeof url === "string" ? url : url.href;
653
+ if (cachedUrl === urlString) {
654
+ return cachedLocale;
655
+ }
656
+ let result;
657
+ if (TREE_SHAKE_DEFAULT_URL_PATTERN_USED) {
658
+ result = defaultUrlPatternExtractLocale(url);
659
+ }
660
+ else {
661
+ const urlObj = typeof url === "string" ? new URL(url) : url;
662
+ // Iterate over URL patterns
663
+ for (const element of urlPatterns) {
664
+ for (const [locale, localizedPattern] of element.localized) {
665
+ const match = new URLPattern(localizedPattern, urlObj.href).exec(urlObj.href);
666
+ if (!match) {
667
+ continue;
668
+ }
669
+ // Check if the locale is valid
670
+ if (assertIsLocale(locale)) {
671
+ result = locale;
672
+ break;
673
+ }
674
+ }
675
+ if (result)
676
+ break;
677
+ }
678
+ }
679
+ cachedUrl = urlString;
680
+ cachedLocale = result;
681
+ return result;
682
+ }
683
+ /**
684
+ * https://github.com/opral/inlang-paraglide-js/issues/381
685
+ *
686
+ * @param {URL|string} url - The full URL from which to extract the locale.
687
+ * @returns {Locale|undefined} The extracted locale, or undefined if no locale is found.
688
+ */
689
+ function defaultUrlPatternExtractLocale(url) {
690
+ const urlObj = new URL(url, "http://dummy.com");
691
+ const pathSegments = urlObj.pathname.split("/").filter(Boolean);
692
+ if (pathSegments.length > 0) {
693
+ const potentialLocale = pathSegments[0];
694
+ if (isLocale(potentialLocale)) {
695
+ return potentialLocale;
696
+ }
697
+ }
698
+ // everything else has to be the base locale
699
+ return baseLocale;
700
+ }
701
+
702
+ /**
703
+ * Lower-level URL localization function, primarily used in server contexts.
704
+ *
705
+ * This function is designed for server-side usage where you need precise control
706
+ * over URL localization, such as in middleware or request handlers. It works with
707
+ * URL objects and always returns absolute URLs.
708
+ *
709
+ * For client-side UI components, use `localizeHref()` instead, which provides
710
+ * a more convenient API with relative paths and automatic locale detection.
711
+ *
712
+ * @example
713
+ * ```typescript
714
+ * // Server middleware example
715
+ * app.use((req, res, next) => {
716
+ * const url = new URL(req.url, `${req.protocol}://${req.headers.host}`);
717
+ * const localized = localizeUrl(url, { locale: "de" });
718
+ *
719
+ * if (localized.href !== url.href) {
720
+ * return res.redirect(localized.href);
721
+ * }
722
+ * next();
723
+ * });
724
+ * ```
725
+ *
726
+ * @example
727
+ * ```typescript
728
+ * // Using with URL patterns
729
+ * const url = new URL("https://example.com/about");
730
+ * localizeUrl(url, { locale: "de" });
731
+ * // => URL("https://example.com/de/about")
732
+ *
733
+ * // Using with domain-based localization
734
+ * const url = new URL("https://example.com/store");
735
+ * localizeUrl(url, { locale: "de" });
736
+ * // => URL("https://de.example.com/store")
737
+ * ```
738
+ *
739
+ * @param {string | URL} url - The URL to localize. If string, must be absolute.
740
+ * @param {Object} [options] - Options for localization
741
+ * @param {string} [options.locale] - Target locale. If not provided, uses getLocale()
742
+ * @returns {URL} The localized URL, always absolute
743
+ */
744
+ export function localizeUrl(url, options) {
745
+ if (TREE_SHAKE_DEFAULT_URL_PATTERN_USED) {
746
+ return localizeUrlDefaultPattern(url, options);
747
+ }
748
+ const targetLocale = options?.locale ?? getLocale();
749
+ const urlObj = typeof url === "string" ? new URL(url) : url;
750
+ // Iterate over URL patterns
751
+ for (const element of urlPatterns) {
752
+ // match localized patterns
753
+ for (const [, localizedPattern] of element.localized) {
754
+ const match = new URLPattern(localizedPattern, urlObj.href).exec(urlObj.href);
755
+ if (!match) {
756
+ continue;
757
+ }
758
+ const targetPattern = element.localized.find(([locale]) => locale === targetLocale)?.[1];
759
+ if (!targetPattern) {
760
+ continue;
761
+ }
762
+ const localizedUrl = fillPattern(targetPattern, aggregateGroups(match), urlObj.origin);
763
+ return fillMissingUrlParts(localizedUrl, match);
764
+ }
765
+ const unlocalizedMatch = new URLPattern(element.pattern, urlObj.href).exec(urlObj.href);
766
+ if (unlocalizedMatch) {
767
+ const targetPattern = element.localized.find(([locale]) => locale === targetLocale)?.[1];
768
+ if (targetPattern) {
769
+ const localizedUrl = fillPattern(targetPattern, aggregateGroups(unlocalizedMatch), urlObj.origin);
770
+ return fillMissingUrlParts(localizedUrl, unlocalizedMatch);
771
+ }
772
+ }
773
+ }
774
+ // If no match found, return the original URL
775
+ return urlObj;
776
+ }
777
+ /**
778
+ * https://github.com/opral/inlang-paraglide-js/issues/381
779
+ *
780
+ * @param {string | URL} url
781
+ * @param {Object} [options]
782
+ * @param {string} [options.locale]
783
+ * @returns {URL}
784
+ */
785
+ function localizeUrlDefaultPattern(url, options) {
786
+ const urlObj = typeof url === "string" ? new URL(url, getUrlOrigin()) : new URL(url);
787
+ const locale = options?.locale ?? getLocale();
788
+ const currentLocale = extractLocaleFromUrl(urlObj);
789
+ // If current locale matches target locale, no change needed
790
+ if (currentLocale === locale) {
791
+ return urlObj;
792
+ }
793
+ const pathSegments = urlObj.pathname.split("/").filter(Boolean);
794
+ // If current path starts with a locale, remove it
795
+ if (pathSegments.length > 0 && isLocale(pathSegments[0])) {
796
+ pathSegments.shift();
797
+ }
798
+ // For base locale, don't add prefix
799
+ if (locale === baseLocale) {
800
+ urlObj.pathname = "/" + pathSegments.join("/");
801
+ }
802
+ else {
803
+ // For other locales, add prefix
804
+ urlObj.pathname = "/" + locale + "/" + pathSegments.join("/");
805
+ }
806
+ return urlObj;
807
+ }
808
+ /**
809
+ * Low-level URL de-localization function, primarily used in server contexts.
810
+ *
811
+ * This function is designed for server-side usage where you need precise control
812
+ * over URL de-localization, such as in middleware or request handlers. It works with
813
+ * URL objects and always returns absolute URLs.
814
+ *
815
+ * For client-side UI components, use `deLocalizeHref()` instead, which provides
816
+ * a more convenient API with relative paths.
817
+ *
818
+ * @example
819
+ * ```typescript
820
+ * // Server middleware example
821
+ * app.use((req, res, next) => {
822
+ * const url = new URL(req.url, `${req.protocol}://${req.headers.host}`);
823
+ * const baseUrl = deLocalizeUrl(url);
824
+ *
825
+ * // Store the base URL for later use
826
+ * req.baseUrl = baseUrl;
827
+ * next();
828
+ * });
829
+ * ```
830
+ *
831
+ * @example
832
+ * ```typescript
833
+ * // Using with URL patterns
834
+ * const url = new URL("https://example.com/de/about");
835
+ * deLocalizeUrl(url); // => URL("https://example.com/about")
836
+ *
837
+ * // Using with domain-based localization
838
+ * const url = new URL("https://de.example.com/store");
839
+ * deLocalizeUrl(url); // => URL("https://example.com/store")
840
+ * ```
841
+ *
842
+ * @param {string | URL} url - The URL to de-localize. If string, must be absolute.
843
+ * @returns {URL} The de-localized URL, always absolute
844
+ */
845
+ export function deLocalizeUrl(url) {
846
+ if (TREE_SHAKE_DEFAULT_URL_PATTERN_USED) {
847
+ return deLocalizeUrlDefaultPattern(url);
848
+ }
849
+ const urlObj = typeof url === "string" ? new URL(url) : url;
850
+ // Iterate over URL patterns
851
+ for (const element of urlPatterns) {
852
+ // Iterate over localized versions
853
+ for (const [, localizedPattern] of element.localized) {
854
+ const match = new URLPattern(localizedPattern, urlObj.href).exec(urlObj.href);
855
+ if (match) {
856
+ // Convert localized URL back to the base pattern
857
+ const groups = aggregateGroups(match);
858
+ const baseUrl = fillPattern(element.pattern, groups, urlObj.origin);
859
+ return fillMissingUrlParts(baseUrl, match);
860
+ }
861
+ }
862
+ // match unlocalized pattern
863
+ const unlocalizedMatch = new URLPattern(element.pattern, urlObj.href).exec(urlObj.href);
864
+ if (unlocalizedMatch) {
865
+ const baseUrl = fillPattern(element.pattern, aggregateGroups(unlocalizedMatch), urlObj.origin);
866
+ return fillMissingUrlParts(baseUrl, unlocalizedMatch);
867
+ }
868
+ }
869
+ // no match found return the original url
870
+ return urlObj;
871
+ }
872
+ /**
873
+ * De-localizes a URL using the default pattern (/:locale/*)
874
+ * @param {string|URL} url
875
+ * @returns {URL}
876
+ */
877
+ function deLocalizeUrlDefaultPattern(url) {
878
+ const urlObj = typeof url === "string" ? new URL(url, getUrlOrigin()) : new URL(url);
879
+ const pathSegments = urlObj.pathname.split("/").filter(Boolean);
880
+ // If first segment is a locale, remove it
881
+ if (pathSegments.length > 0 && isLocale(pathSegments[0])) {
882
+ urlObj.pathname = "/" + pathSegments.slice(1).join("/");
883
+ }
884
+ return urlObj;
885
+ }
886
+ /**
887
+ * Takes matches of implicit wildcards in the UrlPattern (when a part is missing
888
+ * it is equal to '*') and adds them back to the result of fillPattern.
889
+ *
890
+ * At least protocol and hostname are required to create a valid URL inside fillPattern.
891
+ *
892
+ * @param {URL} url
893
+ * @param {any} match
894
+ * @returns {URL}
895
+ */
896
+ function fillMissingUrlParts(url, match) {
897
+ if (match.protocol.groups["0"]) {
898
+ url.protocol = match.protocol.groups["0"] ?? "";
899
+ }
900
+ if (match.hostname.groups["0"]) {
901
+ url.hostname = match.hostname.groups["0"] ?? "";
902
+ }
903
+ if (match.username.groups["0"]) {
904
+ url.username = match.username.groups["0"] ?? "";
905
+ }
906
+ if (match.password.groups["0"]) {
907
+ url.password = match.password.groups["0"] ?? "";
908
+ }
909
+ if (match.port.groups["0"]) {
910
+ url.port = match.port.groups["0"] ?? "";
911
+ }
912
+ if (match.pathname.groups["0"]) {
913
+ url.pathname = match.pathname.groups["0"] ?? "";
914
+ }
915
+ if (match.search.groups["0"]) {
916
+ url.search = match.search.groups["0"] ?? "";
917
+ }
918
+ if (match.hash.groups["0"]) {
919
+ url.hash = match.hash.groups["0"] ?? "";
920
+ }
921
+ return url;
922
+ }
923
+ /**
924
+ * Fills a URL pattern with values for named groups, supporting all URLPattern-style modifiers.
925
+ *
926
+ * This function will eventually be replaced by https://github.com/whatwg/urlpattern/issues/73
927
+ *
928
+ * Matches:
929
+ * - :name -> Simple
930
+ * - :name? -> Optional
931
+ * - :name+ -> One or more
932
+ * - :name* -> Zero or more
933
+ * - :name(...) -> Regex group
934
+ * - {text} -> Group delimiter
935
+ * - {text}? -> Optional group delimiter
936
+ *
937
+ * If the value is `null`, the segment is removed.
938
+ *
939
+ * @param {string} pattern - The URL pattern containing named groups.
940
+ * @param {Record<string, string | null | undefined>} values - Object of values for named groups.
941
+ * @param {string} origin - Base URL to use for URL construction.
942
+ * @returns {URL} - The constructed URL with named groups filled.
943
+ */
944
+ function fillPattern(pattern, values, origin) {
945
+ // Pre-process the pattern to handle explicit port numbers
946
+ // This detects patterns like "http://localhost:5173" and protects the port number
947
+ // from being interpreted as a parameter
948
+ let processedPattern = pattern.replace(/(https?:\/\/[^:/]+):(\d+)(\/|$)/g, (_, protocol, port, slash) => {
949
+ // Replace ":5173" with "#PORT-5173#" to protect it from parameter replacement
950
+ return `${protocol}#PORT-${port}#${slash}`;
951
+ });
952
+ // First, handle group delimiters with curly braces
953
+ let processedGroupDelimiters = processedPattern.replace(/\{([^{}]*)\}([?+*]?)/g, (_, content, modifier) => {
954
+ // For optional group delimiters
955
+ if (modifier === "?") {
956
+ // For optional groups, we'll include the content
957
+ return content;
958
+ }
959
+ // For non-optional group delimiters, always include the content
960
+ return content;
961
+ });
962
+ // Then handle named groups
963
+ let filled = processedGroupDelimiters.replace(/(\/?):([a-zA-Z0-9_]+)(\([^)]*\))?([?+*]?)/g, (_, slash, name, __, modifier) => {
964
+ const value = values[name];
965
+ if (value === null) {
966
+ // If value is null, remove the entire segment including the preceding slash
967
+ return "";
968
+ }
969
+ if (modifier === "?") {
970
+ // Optional segment
971
+ return value !== undefined ? `${slash}${value}` : "";
972
+ }
973
+ if (modifier === "+" || modifier === "*") {
974
+ // Repeatable segments
975
+ if (value === undefined && modifier === "+") {
976
+ throw new Error(`Missing value for "${name}" (one or more required)`);
977
+ }
978
+ return value ? `${slash}${value}` : "";
979
+ }
980
+ // Simple named group (no modifier)
981
+ if (value === undefined) {
982
+ throw new Error(`Missing value for "${name}"`);
983
+ }
984
+ return `${slash}${value}`;
985
+ });
986
+ // Restore port numbers
987
+ filled = filled.replace(/#PORT-(\d+)#/g, ":$1");
988
+ return new URL(filled, origin);
989
+ }
990
+ /**
991
+ * Aggregates named groups from various parts of the URLPattern match result.
992
+ *
993
+ *
994
+ * @type {(match: any) => Record<string, string | null | undefined>}
995
+ */
996
+ export function aggregateGroups(match) {
997
+ return {
998
+ ...match.hash.groups,
999
+ ...match.hostname.groups,
1000
+ ...match.password.groups,
1001
+ ...match.pathname.groups,
1002
+ ...match.port.groups,
1003
+ ...match.protocol.groups,
1004
+ ...match.search.groups,
1005
+ ...match.username.groups,
1006
+ };
1007
+ }
1008
+
1009
+ /**
1010
+ * @typedef {object} ShouldRedirectServerInput
1011
+ * @property {Request} request
1012
+ * @property {string | URL} [url]
1013
+ * @property {ReturnType<typeof assertIsLocale>} [locale]
1014
+ *
1015
+ * @typedef {object} ShouldRedirectClientInput
1016
+ * @property {undefined} [request]
1017
+ * @property {string | URL} [url]
1018
+ * @property {ReturnType<typeof assertIsLocale>} [locale]
1019
+ *
1020
+ * @typedef {ShouldRedirectServerInput | ShouldRedirectClientInput} ShouldRedirectInput
1021
+ *
1022
+ * @typedef {object} ShouldRedirectResult
1023
+ * @property {boolean} shouldRedirect - Indicates whether the consumer should perform a redirect.
1024
+ * @property {ReturnType<typeof assertIsLocale>} locale - Locale resolved using the configured strategies.
1025
+ * @property {URL | undefined} redirectUrl - Destination URL when a redirect is required.
1026
+ */
1027
+ /**
1028
+ * Determines whether a redirect is required to align the current URL with the active locale.
1029
+ *
1030
+ * This helper mirrors the logic that powers `paraglideMiddleware`, but works in both server
1031
+ * and client environments. It evaluates the configured strategies in order, computes the
1032
+ * canonical localized URL, and reports when the current URL does not match.
1033
+ *
1034
+ * When called in the browser without arguments, the current `window.location.href` is used.
1035
+ *
1036
+ * @example
1037
+ * // Client side usage (e.g. TanStack Router beforeLoad hook)
1038
+ * async function beforeLoad({ location }) {
1039
+ * const decision = await shouldRedirect({ url: location.href });
1040
+ *
1041
+ * if (decision.shouldRedirect) {
1042
+ * throw redirect({ to: decision.redirectUrl.href });
1043
+ * }
1044
+ * }
1045
+ *
1046
+ * @example
1047
+ * // Server side usage with a Request
1048
+ * export async function handle(request) {
1049
+ * const decision = await shouldRedirect({ request });
1050
+ *
1051
+ * if (decision.shouldRedirect) {
1052
+ * return Response.redirect(decision.redirectUrl, 307);
1053
+ * }
1054
+ *
1055
+ * return render(request, decision.locale);
1056
+ * }
1057
+ *
1058
+ * @param {ShouldRedirectInput} [input]
1059
+ * @returns {Promise<ShouldRedirectResult>}
1060
+ */
1061
+ export async function shouldRedirect(input = {}) {
1062
+ const locale = /** @type {ReturnType<typeof assertIsLocale>} */ (await resolveLocale(input));
1063
+ if (!strategy.includes("url")) {
1064
+ return { shouldRedirect: false, locale, redirectUrl: undefined };
1065
+ }
1066
+ const currentUrl = resolveUrl(input);
1067
+ const localizedUrl = localizeUrl(currentUrl.href, { locale });
1068
+ const shouldRedirectToLocalizedUrl = normalizeUrl(localizedUrl.href) !== normalizeUrl(currentUrl.href);
1069
+ return {
1070
+ shouldRedirect: shouldRedirectToLocalizedUrl,
1071
+ locale,
1072
+ redirectUrl: shouldRedirectToLocalizedUrl ? localizedUrl : undefined,
1073
+ };
1074
+ }
1075
+ /**
1076
+ * Resolves the locale either from the provided input or by using the configured strategies.
1077
+ *
1078
+ * @param {ShouldRedirectInput} input
1079
+ * @returns {Promise<ReturnType<typeof assertIsLocale>>}
1080
+ */
1081
+ async function resolveLocale(input) {
1082
+ if (input.locale) {
1083
+ return assertIsLocale(input.locale);
1084
+ }
1085
+ if (input.request) {
1086
+ return extractLocaleFromRequestAsync(input.request);
1087
+ }
1088
+ return getLocale();
1089
+ }
1090
+ /**
1091
+ * Resolves the current URL from the provided input or runtime context.
1092
+ *
1093
+ * @param {ShouldRedirectInput} input
1094
+ * @returns {URL}
1095
+ */
1096
+ function resolveUrl(input) {
1097
+ if (input.request) {
1098
+ return new URL(input.request.url);
1099
+ }
1100
+ if (input.url instanceof URL) {
1101
+ return new URL(input.url.href);
1102
+ }
1103
+ if (typeof input.url === "string") {
1104
+ return new URL(input.url, getUrlOrigin());
1105
+ }
1106
+ if (typeof window !== "undefined" && window?.location?.href) {
1107
+ return new URL(window.location.href);
1108
+ }
1109
+ throw new Error("shouldRedirect() requires either a request, an absolute URL, or must run in a browser environment.");
1110
+ }
1111
+ /**
1112
+ * Normalize url for comparison by stripping the trailing slash.
1113
+ *
1114
+ * @param {string} url
1115
+ * @returns {string}
1116
+ */
1117
+ function normalizeUrl(url) {
1118
+ const urlObj = new URL(url);
1119
+ urlObj.pathname = urlObj.pathname.replace(/\/$/, "");
1120
+ return urlObj.href;
1121
+ }
1122
+
1123
+ /**
1124
+ * High-level URL localization function optimized for client-side UI usage.
1125
+ *
1126
+ * This is a convenience wrapper around `localizeUrl()` that provides features
1127
+ * needed in UI:
1128
+ *
1129
+ * - Accepts relative paths (e.g., "/about")
1130
+ * - Returns relative paths when possible
1131
+ * - Automatically detects current locale if not specified
1132
+ * - Handles string input/output instead of URL objects
1133
+ *
1134
+ * @example
1135
+ * ```typescript
1136
+ * // In a React/Vue/Svelte component
1137
+ * const NavLink = ({ href }) => {
1138
+ * // Automatically uses current locale, keeps path relative
1139
+ * return <a href={localizeHref(href)}>...</a>;
1140
+ * };
1141
+ *
1142
+ * // Examples:
1143
+ * localizeHref("/about")
1144
+ * // => "/de/about" (if current locale is "de")
1145
+ * localizeHref("/store", { locale: "fr" })
1146
+ * // => "/fr/store" (explicit locale)
1147
+ *
1148
+ * // Cross-origin links remain absolute
1149
+ * localizeHref("https://other-site.com/about")
1150
+ * // => "https://other-site.com/de/about"
1151
+ * ```
1152
+ *
1153
+ * For server-side URL localization (e.g., in middleware), use `localizeUrl()`
1154
+ * which provides more precise control over URL handling.
1155
+ *
1156
+ * @param {string} href - The href to localize (can be relative or absolute)
1157
+ * @param {Object} [options] - Options for localization
1158
+ * @param {string} [options.locale] - Target locale. If not provided, uses `getLocale()`
1159
+ * @returns {string} The localized href, relative if input was relative
1160
+ */
1161
+ export function localizeHref(href, options) {
1162
+ const currentLocale = getLocale();
1163
+ const locale = options?.locale ?? currentLocale;
1164
+ const url = new URL(href, getUrlOrigin());
1165
+ const localized = localizeUrl(url, { locale });
1166
+ // if the origin is identical and the href is relative,
1167
+ // return the relative path
1168
+ if (href.startsWith("/") && url.origin === localized.origin) {
1169
+ // check for cross origin localization in which case an absolute URL must be returned.
1170
+ if (locale !== currentLocale) {
1171
+ const localizedCurrentLocale = localizeUrl(url, {
1172
+ locale: currentLocale,
1173
+ });
1174
+ if (localizedCurrentLocale.origin !== localized.origin) {
1175
+ return localized.href;
1176
+ }
1177
+ }
1178
+ return localized.pathname + localized.search + localized.hash;
1179
+ }
1180
+ return localized.href;
1181
+ }
1182
+ /**
1183
+ * High-level URL de-localization function optimized for client-side UI usage.
1184
+ *
1185
+ * This is a convenience wrapper around `deLocalizeUrl()` that provides features
1186
+ * needed in the UI:
1187
+ *
1188
+ * - Accepts relative paths (e.g., "/de/about")
1189
+ * - Returns relative paths when possible
1190
+ * - Handles string input/output instead of URL objects
1191
+ *
1192
+ * @example
1193
+ * ```typescript
1194
+ * // In a React/Vue/Svelte component
1195
+ * const LocaleSwitcher = ({ href }) => {
1196
+ * // Remove locale prefix before switching
1197
+ * const baseHref = deLocalizeHref(href);
1198
+ * return locales.map(locale =>
1199
+ * <a href={localizeHref(baseHref, { locale })}>
1200
+ * Switch to {locale}
1201
+ * </a>
1202
+ * );
1203
+ * };
1204
+ *
1205
+ * // Examples:
1206
+ * deLocalizeHref("/de/about") // => "/about"
1207
+ * deLocalizeHref("/fr/store") // => "/store"
1208
+ *
1209
+ * // Cross-origin links remain absolute
1210
+ * deLocalizeHref("https://example.com/de/about")
1211
+ * // => "https://example.com/about"
1212
+ * ```
1213
+ *
1214
+ * For server-side URL de-localization (e.g., in middleware), use `deLocalizeUrl()`
1215
+ * which provides more precise control over URL handling.
1216
+ *
1217
+ * @param {string} href - The href to de-localize (can be relative or absolute)
1218
+ * @returns {string} The de-localized href, relative if input was relative
1219
+ * @see deLocalizeUrl - For low-level URL de-localization in server contexts
1220
+ */
1221
+ export function deLocalizeHref(href) {
1222
+ const url = new URL(href, getUrlOrigin());
1223
+ const deLocalized = deLocalizeUrl(url);
1224
+ // If the origin is identical and the href is relative,
1225
+ // return the relative path instead of the full URL.
1226
+ if (href.startsWith("/") && url.origin === deLocalized.origin) {
1227
+ return deLocalized.pathname + deLocalized.search + deLocalized.hash;
1228
+ }
1229
+ return deLocalized.href;
1230
+ }
1231
+
1232
+ /**
1233
+ * @param {string} safeModuleId
1234
+ * @param {Locale} locale
1235
+ */
1236
+ export function trackMessageCall(safeModuleId, locale) {
1237
+ if (isServer === false)
1238
+ return;
1239
+ const store = serverAsyncLocalStorage?.getStore();
1240
+ if (store) {
1241
+ store.messageCalls?.add(`${safeModuleId}:${locale}`);
1242
+ }
1243
+ }
1244
+
1245
+ /**
1246
+ * Generates a list of localized URLs for all provided URLs.
1247
+ *
1248
+ * This is useful for SSG (Static Site Generation) and sitemap generation.
1249
+ * NextJS and other frameworks use this function for SSG.
1250
+ *
1251
+ * @example
1252
+ * ```typescript
1253
+ * const urls = generateStaticLocalizedUrls([
1254
+ * "https://example.com/about",
1255
+ * "https://example.com/blog",
1256
+ * ]);
1257
+ * urls[0].href // => "https://example.com/about"
1258
+ * urls[1].href // => "https://example.com/blog"
1259
+ * urls[2].href // => "https://example.com/de/about"
1260
+ * urls[3].href // => "https://example.com/de/blog"
1261
+ * ...
1262
+ * ```
1263
+ *
1264
+ * @param {(string | URL)[]} urls - List of URLs to generate localized versions for. Can be absolute URLs or paths.
1265
+ * @returns {URL[]} List of localized URLs as URL objects
1266
+ */
1267
+ export function generateStaticLocalizedUrls(urls) {
1268
+ const localizedUrls = new Set();
1269
+ // For default URL pattern, we can optimize the generation
1270
+ if (TREE_SHAKE_DEFAULT_URL_PATTERN_USED) {
1271
+ for (const urlInput of urls) {
1272
+ const url = urlInput instanceof URL
1273
+ ? urlInput
1274
+ : new URL(urlInput, "http://localhost");
1275
+ // Base locale doesn't get a prefix
1276
+ localizedUrls.add(url);
1277
+ // Other locales get their code as prefix
1278
+ for (const locale of locales) {
1279
+ if (locale !== baseLocale) {
1280
+ const localizedPath = `/${locale}${url.pathname}${url.search}${url.hash}`;
1281
+ const localizedUrl = new URL(localizedPath, url.origin);
1282
+ localizedUrls.add(localizedUrl);
1283
+ }
1284
+ }
1285
+ }
1286
+ return Array.from(localizedUrls);
1287
+ }
1288
+ // For custom URL patterns, we need to use localizeUrl for each URL and locale
1289
+ for (const urlInput of urls) {
1290
+ const url = urlInput instanceof URL
1291
+ ? urlInput
1292
+ : new URL(urlInput, "http://localhost");
1293
+ // Try each URL pattern to find one that matches
1294
+ let patternFound = false;
1295
+ for (const pattern of urlPatterns) {
1296
+ try {
1297
+ // Try to match the unlocalized pattern
1298
+ const unlocalizedMatch = new URLPattern(pattern.pattern, url.href).exec(url.href);
1299
+ if (!unlocalizedMatch)
1300
+ continue;
1301
+ patternFound = true;
1302
+ // Track unique localized URLs to avoid duplicates when patterns are the same
1303
+ const seenUrls = new Set();
1304
+ // Generate localized URL for each locale
1305
+ for (const [locale] of pattern.localized) {
1306
+ try {
1307
+ const localizedUrl = localizeUrl(url, { locale });
1308
+ const urlString = localizedUrl.href;
1309
+ // Only add if we haven't seen this exact URL before
1310
+ if (!seenUrls.has(urlString)) {
1311
+ seenUrls.add(urlString);
1312
+ localizedUrls.add(localizedUrl);
1313
+ }
1314
+ }
1315
+ catch {
1316
+ // Skip if localization fails for this locale
1317
+ continue;
1318
+ }
1319
+ }
1320
+ break;
1321
+ }
1322
+ catch {
1323
+ // Skip if pattern matching fails
1324
+ continue;
1325
+ }
1326
+ }
1327
+ // If no pattern matched, use the URL as is
1328
+ if (!patternFound) {
1329
+ localizedUrls.add(url);
1330
+ }
1331
+ }
1332
+ return Array.from(localizedUrls);
1333
+ }
1334
+
1335
+ /**
1336
+ * @typedef {"cookie" | "baseLocale" | "globalVariable" | "url" | "preferredLanguage" | "localStorage"} BuiltInStrategy
1337
+ */
1338
+ /**
1339
+ * @typedef {`custom_${string}`} CustomStrategy
1340
+ */
1341
+ /**
1342
+ * @typedef {BuiltInStrategy | CustomStrategy} Strategy
1343
+ */
1344
+ /**
1345
+ * @typedef {Array<Strategy>} Strategies
1346
+ */
1347
+ /**
1348
+ * @typedef {{ getLocale: (request?: Request) => Promise<string | undefined> | (string | undefined) }} CustomServerStrategyHandler
1349
+ */
1350
+ /**
1351
+ * @typedef {{ getLocale: () => Promise<string|undefined> | (string | undefined), setLocale: (locale: string) => Promise<void> | void }} CustomClientStrategyHandler
1352
+ */
1353
+ /** @type {Map<string, CustomServerStrategyHandler>} */
1354
+ export const customServerStrategies = new Map();
1355
+ /** @type {Map<string, CustomClientStrategyHandler>} */
1356
+ export const customClientStrategies = new Map();
1357
+ /**
1358
+ * Checks if the given strategy is a custom strategy.
1359
+ *
1360
+ * @param {any} strategy The name of the custom strategy to validate.
1361
+ * Must be a string that starts with "custom-" followed by alphanumeric characters, hyphens, or underscores.
1362
+ * @returns {boolean} Returns true if it is a custom strategy, false otherwise.
1363
+ */
1364
+ export function isCustomStrategy(strategy) {
1365
+ return (typeof strategy === "string" && /^custom-[A-Za-z0-9_-]+$/.test(strategy));
1366
+ }
1367
+ /**
1368
+ * Defines a custom strategy that is executed on the server.
1369
+ *
1370
+ * @param {any} strategy The name of the custom strategy to define. Must follow the pattern custom-name with alphanumeric characters, hyphens, or underscores.
1371
+ * @param {CustomServerStrategyHandler} handler The handler for the custom strategy, which should implement
1372
+ * the method getLocale.
1373
+ * @returns {void}
1374
+ */
1375
+ export function defineCustomServerStrategy(strategy, handler) {
1376
+ if (!isCustomStrategy(strategy)) {
1377
+ throw new Error(`Invalid custom strategy: "${strategy}". Must be a custom strategy following the pattern custom-name.`);
1378
+ }
1379
+ customServerStrategies.set(strategy, handler);
1380
+ }
1381
+ /**
1382
+ * Defines a custom strategy that is executed on the client.
1383
+ *
1384
+ * @param {any} strategy The name of the custom strategy to define. Must follow the pattern custom-name with alphanumeric characters, hyphens, or underscores.
1385
+ * @param {CustomClientStrategyHandler} handler The handler for the custom strategy, which should implement the
1386
+ * methods getLocale and setLocale.
1387
+ * @returns {void}
1388
+ */
1389
+ export function defineCustomClientStrategy(strategy, handler) {
1390
+ if (!isCustomStrategy(strategy)) {
1391
+ throw new Error(`Invalid custom strategy: "${strategy}". Must be a custom strategy following the pattern custom-name.`);
1392
+ }
1393
+ customClientStrategies.set(strategy, handler);
1394
+ }
1395
+
1396
+ // ------ TYPES ------
1397
+
1398
+ /**
1399
+ * A locale that is available in the project.
1400
+ *
1401
+ * @example
1402
+ * setLocale(request.locale as Locale)
1403
+ *
1404
+ * @typedef {(typeof locales)[number]} Locale
1405
+ */
1406
+