tera-system-ui 0.1.64 → 0.1.67

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 (361) hide show
  1. package/dist/COMPONENT_API.md +2 -539
  2. package/dist/components/accordion/Accordion.d.ts +24 -0
  3. package/dist/components/accordion/Accordion.js +4 -0
  4. package/dist/components/accordion/components/Accordion.svelte +2 -8
  5. package/dist/components/accordion/components/AccordionContent.svelte +5 -12
  6. package/dist/components/accordion/components/AccordionItem.svelte +3 -9
  7. package/dist/components/accordion/components/AccordionTrigger.svelte +5 -15
  8. package/dist/components/ai/ChatBubble.svelte +35 -0
  9. package/dist/components/ai/ChatBubble.svelte.d.ts +12 -0
  10. package/dist/components/ai/PromptInput.svelte +58 -0
  11. package/dist/components/ai/PromptInput.svelte.d.ts +13 -0
  12. package/dist/components/ai/StreamText.svelte +41 -0
  13. package/dist/components/ai/StreamText.svelte.d.ts +11 -0
  14. package/dist/components/ai/SuggestionChips.svelte +34 -0
  15. package/dist/components/ai/SuggestionChips.svelte.d.ts +10 -0
  16. package/dist/components/ai/ThinkingLoader.svelte +34 -0
  17. package/dist/components/ai/ThinkingLoader.svelte.d.ts +11 -0
  18. package/dist/components/ai/index.d.ts +5 -0
  19. package/dist/components/ai/index.js +5 -0
  20. package/dist/components/alert/Alert.svelte +47 -0
  21. package/dist/components/alert/Alert.svelte.d.ts +15 -0
  22. package/dist/components/alert/index.d.ts +1 -0
  23. package/dist/components/alert/index.js +1 -0
  24. package/dist/components/avatar/Avatar.svelte +9 -25
  25. package/dist/components/badge/Badge.d.ts +52 -0
  26. package/dist/components/badge/Badge.js +22 -0
  27. package/dist/components/badge/Badge.svelte +22 -0
  28. package/dist/components/badge/Badge.svelte.d.ts +4 -0
  29. package/dist/components/badge/index.d.ts +2 -0
  30. package/dist/components/badge/index.js +1 -0
  31. package/dist/components/brand-logo/BrandLogo.svelte +12 -10
  32. package/dist/components/button/Button.d.ts +2 -2
  33. package/dist/components/button/Button.js +12 -12
  34. package/dist/components/button/Button.svelte +7 -34
  35. package/dist/components/card/Card.d.ts +68 -0
  36. package/dist/components/card/Card.js +28 -0
  37. package/dist/components/card/Card.svelte +33 -0
  38. package/dist/components/card/Card.svelte.d.ts +4 -0
  39. package/dist/components/card/index.d.ts +2 -0
  40. package/dist/components/card/index.js +1 -0
  41. package/dist/components/checkbox/Checkbox.d.ts +25 -4
  42. package/dist/components/checkbox/Checkbox.js +4 -0
  43. package/dist/components/checkbox/Checkbox.svelte +13 -16
  44. package/dist/components/checkbox/Checkbox.svelte.d.ts +2 -2
  45. package/dist/components/combobox/Combobox.d.ts +45 -9
  46. package/dist/components/combobox/Combobox.js +5 -7
  47. package/dist/components/combobox/Combobox.svelte +226 -8
  48. package/dist/components/combobox/Combobox.svelte.d.ts +2 -2
  49. package/dist/components/combobox/index.d.ts +1 -1
  50. package/dist/components/command/components/command-empty.svelte +3 -8
  51. package/dist/components/command/components/command-group.svelte +3 -13
  52. package/dist/components/command/components/command-input.svelte +5 -13
  53. package/dist/components/command/components/command-item.svelte +3 -9
  54. package/dist/components/command/components/command-link-item.svelte +3 -8
  55. package/dist/components/command/components/command-list.svelte +3 -8
  56. package/dist/components/command/components/command-separator.svelte +3 -8
  57. package/dist/components/command/components/command-shortcut.svelte +2 -10
  58. package/dist/components/command/components/command.svelte +29 -42
  59. package/dist/components/date-range-picker/DateRangePicker.svelte +490 -0
  60. package/dist/components/date-range-picker/DateRangePicker.svelte.d.ts +4 -0
  61. package/dist/components/date-range-picker/DateRangePicker.types.d.ts +38 -0
  62. package/dist/components/date-range-picker/DateRangePicker.types.js +1 -0
  63. package/dist/components/date-range-picker/index.d.ts +2 -0
  64. package/dist/components/date-range-picker/index.js +1 -0
  65. package/dist/components/dialog/Dialog.d.ts +43 -121
  66. package/dist/components/dialog/Dialog.js +1 -39
  67. package/dist/components/dialog/Dialog.svelte +103 -113
  68. package/dist/components/dialog/Dialog.svelte.d.ts +1 -2
  69. package/dist/components/dialog/dialog.scss +21 -24
  70. package/dist/components/drawer/Drawer.svelte +63 -0
  71. package/dist/components/drawer/Drawer.svelte.d.ts +16 -0
  72. package/dist/components/drawer/index.d.ts +1 -0
  73. package/dist/components/drawer/index.js +1 -0
  74. package/dist/components/dropdown-menu/DropdownMenu.d.ts +51 -24
  75. package/dist/components/dropdown-menu/DropdownMenu.js +1 -15
  76. package/dist/components/dropdown-menu/components/DropdownMenu.svelte +36 -34
  77. package/dist/components/dropdown-menu/components/DropdownMenu.svelte.d.ts +1 -1
  78. package/dist/components/dropdown-menu/components/DropdownMenuGroup.svelte +8 -12
  79. package/dist/components/dropdown-menu/components/DropdownMenuGroup.svelte.d.ts +2 -4
  80. package/dist/components/dropdown-menu/components/DropdownMenuHeader.svelte +11 -12
  81. package/dist/components/dropdown-menu/components/DropdownMenuHeader.svelte.d.ts +2 -4
  82. package/dist/components/dropdown-menu/components/DropdownMenuItem.svelte +27 -30
  83. package/dist/components/dropdown-menu/components/DropdownMenuItem.svelte.d.ts +1 -1
  84. package/dist/components/dropdown-menu/components/DropdownMenuSeparator.svelte +9 -11
  85. package/dist/components/dropdown-menu/components/DropdownMenuSeparator.svelte.d.ts +2 -4
  86. package/dist/components/fonts/TeraFontMono.svelte +4 -4
  87. package/dist/components/fonts/TeraFontMono.svelte.d.ts +1 -0
  88. package/dist/components/fonts/TeraFontSansSerif.svelte +4 -4
  89. package/dist/components/fonts/TeraFontSansSerif.svelte.d.ts +1 -1
  90. package/dist/components/header/Header.svelte +6 -9
  91. package/dist/components/header/header.scss +1 -1
  92. package/dist/components/icons/IconArrowBigRightFilled.svelte +3 -7
  93. package/dist/components/icons/IconBook.svelte +3 -6
  94. package/dist/components/icons/IconBookmarkPlus.svelte +3 -6
  95. package/dist/components/icons/IconCalculator.svelte +3 -6
  96. package/dist/components/icons/IconCheck.svelte +3 -6
  97. package/dist/components/icons/IconChevronDown.svelte +3 -6
  98. package/dist/components/icons/IconCoin.svelte +3 -6
  99. package/dist/components/icons/IconCoinConvert.svelte +2 -5
  100. package/dist/components/icons/IconCopy.svelte +3 -6
  101. package/dist/components/icons/IconCopyCheckFilled.svelte +3 -6
  102. package/dist/components/icons/IconHamburger.svelte +3 -6
  103. package/dist/components/icons/IconLanguage.svelte +3 -6
  104. package/dist/components/icons/IconLoader2.svelte +3 -6
  105. package/dist/components/icons/IconLogout.svelte +3 -6
  106. package/dist/components/icons/IconMoon.svelte +3 -6
  107. package/dist/components/icons/IconPointFilled.svelte +3 -6
  108. package/dist/components/icons/IconSearch.svelte +3 -6
  109. package/dist/components/icons/IconSettings.svelte +3 -6
  110. package/dist/components/icons/IconSun.svelte +3 -6
  111. package/dist/components/icons/IconSwitchHorizontal.svelte +3 -6
  112. package/dist/components/icons/IconSwitchVertical.svelte +3 -6
  113. package/dist/components/icons/IconTransform.svelte +3 -6
  114. package/dist/components/icons/IconX.svelte +3 -6
  115. package/dist/components/input/Input.d.ts +2 -2
  116. package/dist/components/input/Input.js +10 -10
  117. package/dist/components/input/Input.svelte +10 -26
  118. package/dist/components/label/Label.d.ts +2 -2
  119. package/dist/components/label/Label.js +2 -2
  120. package/dist/components/label/Label.svelte +4 -12
  121. package/dist/components/language-picker-button/LanguagePickerButton.svelte +23 -42
  122. package/dist/components/light-dark-toggle/LightDarkToggle.svelte +21 -26
  123. package/dist/components/marketing/FeatureCard.svelte +37 -0
  124. package/dist/components/marketing/FeatureCard.svelte.d.ts +13 -0
  125. package/dist/components/marketing/PricingCard.svelte +48 -0
  126. package/dist/components/marketing/PricingCard.svelte.d.ts +15 -0
  127. package/dist/components/marketing/StatBlock.svelte +14 -0
  128. package/dist/components/marketing/StatBlock.svelte.d.ts +10 -0
  129. package/dist/components/marketing/TestimonialCard.svelte +24 -0
  130. package/dist/components/marketing/TestimonialCard.svelte.d.ts +12 -0
  131. package/dist/components/marketing/index.d.ts +4 -0
  132. package/dist/components/marketing/index.js +4 -0
  133. package/dist/components/popover/Popover.d.ts +32 -13
  134. package/dist/components/popover/Popover.js +1 -7
  135. package/dist/components/popover/Popover.svelte +40 -158
  136. package/dist/components/popover/Popover.svelte.d.ts +2 -2
  137. package/dist/components/popover-responsive/PopoverResponsive.d.ts +18 -7
  138. package/dist/components/popover-responsive/PopoverResponsive.js +1 -7
  139. package/dist/components/popover-responsive/PopoverResponsive.svelte +25 -87
  140. package/dist/components/popover-responsive/PopoverResponsive.svelte.d.ts +2 -11
  141. package/dist/components/select/Select.d.ts +60 -23
  142. package/dist/components/select/Select.js +14 -35
  143. package/dist/components/select/Select.svelte +157 -28
  144. package/dist/components/select/Select.svelte.d.ts +2 -3
  145. package/dist/components/select/index.d.ts +1 -1
  146. package/dist/components/side-navigation/SideNavigation.svelte +73 -96
  147. package/dist/components/side-navigation/SideNavigationItem.svelte +2 -2
  148. package/dist/components/side-navigation/SideNavigationLayout.svelte +3 -5
  149. package/dist/components/side-navigation/sidenav.scss +17 -13
  150. package/dist/components/skeleton/Skeleton.svelte +48 -0
  151. package/dist/components/skeleton/Skeleton.svelte.d.ts +12 -0
  152. package/dist/components/skeleton/index.d.ts +1 -0
  153. package/dist/components/skeleton/index.js +1 -0
  154. package/dist/components/slider/Slider.d.ts +25 -15
  155. package/dist/components/slider/Slider.js +1 -7
  156. package/dist/components/slider/Slider.svelte +38 -164
  157. package/dist/components/slider/Slider.svelte.d.ts +1 -1
  158. package/dist/components/spinner/Spinner.svelte +39 -0
  159. package/dist/components/spinner/Spinner.svelte.d.ts +10 -0
  160. package/dist/components/spinner/index.d.ts +1 -0
  161. package/dist/components/spinner/index.js +1 -0
  162. package/dist/components/star-rating/StarRating.svelte +33 -49
  163. package/dist/components/switch/Switch.d.ts +19 -4
  164. package/dist/components/switch/Switch.js +4 -0
  165. package/dist/components/switch/Switch.svelte +13 -17
  166. package/dist/components/switch/Switch.svelte.d.ts +2 -2
  167. package/dist/components/table/Table.svelte +68 -0
  168. package/dist/components/table/Table.svelte.d.ts +40 -0
  169. package/dist/components/table/index.d.ts +1 -0
  170. package/dist/components/table/index.js +1 -0
  171. package/dist/components/tabs/Tabs.svelte.d.ts +45 -16
  172. package/dist/components/tabs/Tabs.svelte.js +8 -18
  173. package/dist/components/tabs/components/Tabs.svelte +27 -33
  174. package/dist/components/tabs/components/Tabs.svelte.d.ts +1 -1
  175. package/dist/components/tabs/components/TabsContent.svelte +13 -36
  176. package/dist/components/tabs/components/TabsContent.svelte.d.ts +2 -5
  177. package/dist/components/tabs/components/TabsItem.svelte +43 -32
  178. package/dist/components/tabs/components/TabsItem.svelte.d.ts +2 -5
  179. package/dist/components/tabs/components/TabsList.svelte +90 -58
  180. package/dist/components/tabs/components/TabsList.svelte.d.ts +2 -4
  181. package/dist/components/tera-ui-context/TeraUiContext.svelte +13 -26
  182. package/dist/components/text-area/TextArea.d.ts +2 -2
  183. package/dist/components/text-area/TextArea.js +9 -9
  184. package/dist/components/text-area/TextArea.svelte +41 -65
  185. package/dist/components/toast/ToastContainer.svelte +50 -0
  186. package/dist/components/toast/ToastContainer.svelte.d.ts +18 -0
  187. package/dist/components/toast/index.d.ts +3 -0
  188. package/dist/components/toast/index.js +2 -0
  189. package/dist/components/toast/toast.svelte.d.ts +22 -0
  190. package/dist/components/toast/toast.svelte.js +18 -0
  191. package/dist/components/tooltip/Tooltip.d.ts +23 -0
  192. package/dist/components/tooltip/Tooltip.js +1 -0
  193. package/dist/components/tooltip/Tooltip.svelte +30 -0
  194. package/dist/components/tooltip/Tooltip.svelte.d.ts +4 -0
  195. package/dist/components/tooltip/index.d.ts +2 -0
  196. package/dist/components/tooltip/index.js +1 -0
  197. package/dist/components/user-avatar-with-menu/UserAvatarWithMenu.svelte +48 -69
  198. package/dist/index.d.ts +19 -2
  199. package/dist/index.js +12 -0
  200. package/dist/llms/accordion.md +90 -0
  201. package/dist/llms/ai.md +110 -0
  202. package/dist/llms/alert.md +29 -0
  203. package/dist/llms/avatar.md +34 -0
  204. package/dist/llms/badge.md +31 -0
  205. package/dist/llms/brand-logo.md +30 -0
  206. package/dist/llms/button.md +37 -0
  207. package/dist/llms/card.md +32 -0
  208. package/dist/llms/checkbox.md +35 -0
  209. package/dist/llms/colors.md +161 -0
  210. package/dist/llms/combobox.md +40 -0
  211. package/dist/llms/command.md +7 -0
  212. package/dist/llms/date-range-picker.md +36 -0
  213. package/dist/llms/dialog.md +45 -0
  214. package/dist/llms/drawer.md +30 -0
  215. package/dist/llms/dropdown-menu.md +112 -0
  216. package/dist/llms/fonts.md +7 -0
  217. package/dist/llms/header.md +26 -0
  218. package/dist/llms/icons.md +43 -0
  219. package/dist/llms/index.md +65 -0
  220. package/dist/llms/input.md +37 -0
  221. package/dist/llms/label.md +30 -0
  222. package/dist/llms/language-picker-button.md +30 -0
  223. package/dist/llms/light-dark-toggle.md +26 -0
  224. package/dist/llms/marketing.md +95 -0
  225. package/dist/llms/popover-responsive.md +32 -0
  226. package/dist/llms/popover.md +40 -0
  227. package/dist/llms/select.md +44 -0
  228. package/dist/llms/side-navigation.md +30 -0
  229. package/dist/llms/skeleton.md +28 -0
  230. package/dist/llms/slider.md +36 -0
  231. package/dist/llms/spinner.md +25 -0
  232. package/dist/llms/star-rating.md +31 -0
  233. package/dist/llms/switch.md +33 -0
  234. package/dist/llms/table.md +30 -0
  235. package/dist/llms/tabs.md +92 -0
  236. package/dist/llms/tera-ui-context.md +30 -0
  237. package/dist/llms/text-area.md +39 -0
  238. package/dist/llms/toast.md +7 -0
  239. package/dist/llms/tooltip.md +32 -0
  240. package/dist/llms/user-avatar-with-menu.md +28 -0
  241. package/dist/paraglide/README.md +72 -3
  242. package/dist/paraglide/messages/_index.d.ts +105 -7
  243. package/dist/paraglide/messages/_index.js +437 -7
  244. package/dist/paraglide/messages/ar.d.ts +23 -0
  245. package/dist/paraglide/messages/ar.js +38 -0
  246. package/dist/paraglide/messages/bg.d.ts +23 -0
  247. package/dist/paraglide/messages/bg.js +38 -0
  248. package/dist/paraglide/messages/bn.d.ts +23 -0
  249. package/dist/paraglide/messages/bn.js +38 -0
  250. package/dist/paraglide/messages/ca.d.ts +23 -0
  251. package/dist/paraglide/messages/ca.js +38 -0
  252. package/dist/paraglide/messages/cs.d.ts +23 -0
  253. package/dist/paraglide/messages/cs.js +38 -0
  254. package/dist/paraglide/messages/da.d.ts +23 -0
  255. package/dist/paraglide/messages/da.js +38 -0
  256. package/dist/paraglide/messages/de.d.ts +23 -0
  257. package/dist/paraglide/messages/de.js +38 -0
  258. package/dist/paraglide/messages/el.d.ts +23 -0
  259. package/dist/paraglide/messages/el.js +38 -0
  260. package/dist/paraglide/messages/en.d.ts +23 -0
  261. package/dist/paraglide/messages/en.js +38 -0
  262. package/dist/paraglide/messages/es.d.ts +23 -0
  263. package/dist/paraglide/messages/es.js +38 -0
  264. package/dist/paraglide/messages/fi.d.ts +23 -0
  265. package/dist/paraglide/messages/fi.js +38 -0
  266. package/dist/paraglide/messages/fr.d.ts +23 -0
  267. package/dist/paraglide/messages/fr.js +38 -0
  268. package/dist/paraglide/messages/he.d.ts +23 -0
  269. package/dist/paraglide/messages/he.js +38 -0
  270. package/dist/paraglide/messages/hi.d.ts +23 -0
  271. package/dist/paraglide/messages/hi.js +38 -0
  272. package/dist/paraglide/messages/hu.d.ts +23 -0
  273. package/dist/paraglide/messages/hu.js +38 -0
  274. package/dist/paraglide/messages/id.d.ts +23 -0
  275. package/dist/paraglide/messages/id.js +38 -0
  276. package/dist/paraglide/messages/it.d.ts +23 -0
  277. package/dist/paraglide/messages/it.js +38 -0
  278. package/dist/paraglide/messages/ja.d.ts +23 -0
  279. package/dist/paraglide/messages/ja.js +38 -0
  280. package/dist/paraglide/messages/ko.d.ts +23 -0
  281. package/dist/paraglide/messages/ko.js +38 -0
  282. package/dist/paraglide/messages/lt.d.ts +23 -0
  283. package/dist/paraglide/messages/lt.js +38 -0
  284. package/dist/paraglide/messages/lv.d.ts +23 -0
  285. package/dist/paraglide/messages/lv.js +38 -0
  286. package/dist/paraglide/messages/ms.d.ts +23 -0
  287. package/dist/paraglide/messages/ms.js +38 -0
  288. package/dist/paraglide/messages/nl.d.ts +23 -0
  289. package/dist/paraglide/messages/nl.js +38 -0
  290. package/dist/paraglide/messages/no.d.ts +23 -0
  291. package/dist/paraglide/messages/no.js +38 -0
  292. package/dist/paraglide/messages/pl.d.ts +23 -0
  293. package/dist/paraglide/messages/pl.js +38 -0
  294. package/dist/paraglide/messages/pt.d.ts +23 -0
  295. package/dist/paraglide/messages/pt.js +38 -0
  296. package/dist/paraglide/messages/ro.d.ts +23 -0
  297. package/dist/paraglide/messages/ro.js +38 -0
  298. package/dist/paraglide/messages/ru.d.ts +23 -0
  299. package/dist/paraglide/messages/ru.js +38 -0
  300. package/dist/paraglide/messages/sk.d.ts +23 -0
  301. package/dist/paraglide/messages/sk.js +38 -0
  302. package/dist/paraglide/messages/sl.d.ts +23 -0
  303. package/dist/paraglide/messages/sl.js +38 -0
  304. package/dist/paraglide/messages/sq.d.ts +23 -0
  305. package/dist/paraglide/messages/sq.js +38 -0
  306. package/dist/paraglide/messages/sr.d.ts +23 -0
  307. package/dist/paraglide/messages/sr.js +38 -0
  308. package/dist/paraglide/messages/sv.d.ts +23 -0
  309. package/dist/paraglide/messages/sv.js +38 -0
  310. package/dist/paraglide/messages/sw.d.ts +23 -0
  311. package/dist/paraglide/messages/sw.js +38 -0
  312. package/dist/paraglide/messages/ta.d.ts +23 -0
  313. package/dist/paraglide/messages/ta.js +38 -0
  314. package/dist/paraglide/messages/te.d.ts +23 -0
  315. package/dist/paraglide/messages/te.js +38 -0
  316. package/dist/paraglide/messages/th.d.ts +23 -0
  317. package/dist/paraglide/messages/th.js +38 -0
  318. package/dist/paraglide/messages/tl.d.ts +23 -0
  319. package/dist/paraglide/messages/tl.js +38 -0
  320. package/dist/paraglide/messages/tr.d.ts +23 -0
  321. package/dist/paraglide/messages/tr.js +38 -0
  322. package/dist/paraglide/messages/uk.d.ts +23 -0
  323. package/dist/paraglide/messages/uk.js +38 -0
  324. package/dist/paraglide/messages/vi.d.ts +23 -0
  325. package/dist/paraglide/messages/vi.js +38 -0
  326. package/dist/paraglide/messages/zh-CN.d.ts +23 -0
  327. package/dist/paraglide/messages/zh-CN.js +38 -0
  328. package/dist/paraglide/messages/zh-TW.d.ts +23 -0
  329. package/dist/paraglide/messages/zh-TW.js +38 -0
  330. package/dist/paraglide/registry.d.ts +13 -0
  331. package/dist/paraglide/registry.js +15 -0
  332. package/dist/paraglide/runtime.d.ts +243 -126
  333. package/dist/paraglide/runtime.js +473 -148
  334. package/dist/paraglide/server.d.ts +13 -20
  335. package/dist/paraglide/server.js +92 -40
  336. package/dist/stories/ComponentOverview.stories.svelte +533 -0
  337. package/dist/stories/ComponentOverview.stories.svelte.d.ts +6 -0
  338. package/dist/themes/tera-ui-base.css +664 -470
  339. package/dist/themes/theme-ai.css +100 -0
  340. package/dist/themes/theme-marketing.css +91 -0
  341. package/dist/themes/theme-professional.css +41 -0
  342. package/package.json +35 -29
  343. package/dist/paraglide/messages/text_account_settings.d.ts +0 -4
  344. package/dist/paraglide/messages/text_account_settings.js +0 -239
  345. package/dist/paraglide/messages/text_calces_documentation.d.ts +0 -4
  346. package/dist/paraglide/messages/text_calces_documentation.js +0 -239
  347. package/dist/paraglide/messages/text_calces_scientific_calculator.d.ts +0 -4
  348. package/dist/paraglide/messages/text_calces_scientific_calculator.js +0 -239
  349. package/dist/paraglide/messages/text_currency_converter.d.ts +0 -4
  350. package/dist/paraglide/messages/text_currency_converter.js +0 -239
  351. package/dist/paraglide/messages/text_logout.d.ts +0 -4
  352. package/dist/paraglide/messages/text_logout.js +0 -239
  353. package/dist/paraglide/messages/text_select_language.d.ts +0 -4
  354. package/dist/paraglide/messages/text_select_language.js +0 -239
  355. package/dist/paraglide/messages/text_unit_converter.d.ts +0 -4
  356. package/dist/paraglide/messages/text_unit_converter.js +0 -239
  357. package/dist/tera-i18n/projects/tera-system-ui/project.inlang/.meta.json +0 -3
  358. package/dist/tera-i18n/projects/tera-system-ui/project.inlang/README.md +0 -103
  359. package/dist/tera-i18n/projects/tera-system-ui/project.inlang/project_id +0 -1
  360. package/dist/themes/tw-preset.cjs +0 -160
  361. package/dist/themes/tw-preset.d.cts +0 -157
@@ -20,7 +20,7 @@ export const baseLocale = "en";
20
20
  * throw new Error('Locale is not available');
21
21
  * }
22
22
  */
23
- export const locales = /** @type {const} */ (["ar", "bg", "bn", "ca", "cs", "da", "de", "el", "en", "es", "fi", "fr", "he", "hi", "hu", "id", "it", "ja", "ko", "lt", "lv", "ms", "nl", "no", "pl", "pt", "ro", "ru", "sk", "sl", "sq", "sr", "sv", "sw", "ta", "te", "th", "tl", "tr", "uk", "vi", "zh-CN", "zh-TW"]);
23
+ export const locales = /** @type {const} */ (["ar","bg","bn","ca","cs","da","de","el","en","es","fi","fr","he","hi","hu","id","it","ja","ko","lt","lv","ms","nl","no","pl","pt","ro","ru","sk","sl","sq","sr","sv","sw","ta","te","th","tl","tr","uk","vi","zh-CN","zh-TW"]);
24
24
  /** @type {string} */
25
25
  export const cookieName = "PARAGLIDE_LOCALE";
26
26
  /** @type {number} */
@@ -33,14 +33,27 @@ export const localStorageKey = "PARAGLIDE_LOCALE";
33
33
  * @type {Array<"cookie" | "baseLocale" | "globalVariable" | "url" | "preferredLanguage" | "localStorage" | `custom-${string}`>}
34
34
  */
35
35
  export const strategy = [
36
+ "url",
36
37
  "cookie",
37
- "globalVariable",
38
+ "preferredLanguage",
38
39
  "baseLocale"
39
40
  ];
41
+ /**
42
+ * Route-level strategy overrides.
43
+ *
44
+ * `match` uses URLPattern syntax.
45
+ *
46
+ * @type {Array<{
47
+ * match: string;
48
+ * strategy?: Array<"cookie" | "baseLocale" | "globalVariable" | "url" | "preferredLanguage" | "localStorage" | `custom-${string}`>;
49
+ * exclude?: boolean;
50
+ * }>}
51
+ */
52
+ export const routeStrategies = [];
40
53
  /**
41
54
  * The used URL patterns.
42
55
  *
43
- * @type {Array<{ pattern: string, localized: Array<[Locale, string]> }> }
56
+ * @type {Array<{ pattern: string, localized: Array<[Locale, string]> }>}
44
57
  */
45
58
  export const urlPatterns = [
46
59
  {
@@ -221,6 +234,62 @@ export const urlPatterns = [
221
234
  ]
222
235
  }
223
236
  ];
237
+ /** @type {string | undefined} */
238
+ let cachedRouteStrategyUrl;
239
+ /** @type {{ match: string; strategy?: typeof strategy; exclude?: boolean } | undefined} */
240
+ let cachedRouteStrategy;
241
+ /**
242
+ * @param {string | URL} url
243
+ * @returns {{ match: string; strategy?: typeof strategy; exclude?: boolean } | undefined}
244
+ */
245
+ function findMatchingRouteStrategy(url) {
246
+ if (routeStrategies.length === 0) {
247
+ return undefined;
248
+ }
249
+ const urlString = typeof url === "string" ? url : url.href;
250
+ if (cachedRouteStrategyUrl === urlString) {
251
+ return cachedRouteStrategy;
252
+ }
253
+ const urlObject = new URL(urlString, "http://dummy.com");
254
+ let match;
255
+ for (const routeStrategy of routeStrategies) {
256
+ const pattern = new URLPattern(routeStrategy.match, urlObject.href);
257
+ if (pattern.exec(urlObject.href)) {
258
+ match = routeStrategy;
259
+ break;
260
+ }
261
+ }
262
+ cachedRouteStrategyUrl = urlString;
263
+ cachedRouteStrategy = match;
264
+ return match;
265
+ }
266
+ /**
267
+ * Returns the strategy to use for a specific URL.
268
+ *
269
+ * If no route strategy matches (or the matching rule is `exclude: true`),
270
+ * the global strategy is returned.
271
+ *
272
+ * @param {string | URL} url
273
+ * @returns {typeof strategy}
274
+ */
275
+ export function getStrategyForUrl(url) {
276
+ const routeStrategy = findMatchingRouteStrategy(url);
277
+ if (routeStrategy &&
278
+ routeStrategy.exclude !== true &&
279
+ Array.isArray(routeStrategy.strategy)) {
280
+ return routeStrategy.strategy;
281
+ }
282
+ return strategy;
283
+ }
284
+ /**
285
+ * Returns whether the given URL is excluded from middleware i18n processing.
286
+ *
287
+ * @param {string | URL} url
288
+ * @returns {boolean}
289
+ */
290
+ export function isExcludedByRouteStrategy(url) {
291
+ return findMatchingRouteStrategy(url)?.exclude === true;
292
+ }
224
293
  /**
225
294
  * @typedef {{
226
295
  * getStore(): {
@@ -243,9 +312,8 @@ export const urlPatterns = [
243
312
  export let serverAsyncLocalStorage = undefined;
244
313
  export const disableAsyncLocalStorage = false;
245
314
  export const experimentalMiddlewareLocaleSplitting = false;
246
- export const isServer = typeof window === 'undefined';
315
+ export const isServer = import.meta.env?.SSR ?? typeof window === 'undefined';
247
316
  /** @type {Locale | undefined} */
248
- // @ts-ignore - injected by bundlers at compile time
249
317
  export const experimentalStaticLocale = undefined;
250
318
  /**
251
319
  * Sets the server side async local storage.
@@ -261,22 +329,25 @@ export function overwriteServerAsyncLocalStorage(value) {
261
329
  serverAsyncLocalStorage = value;
262
330
  }
263
331
  const TREE_SHAKE_COOKIE_STRATEGY_USED = true;
264
- const TREE_SHAKE_URL_STRATEGY_USED = false;
265
- const TREE_SHAKE_GLOBAL_VARIABLE_STRATEGY_USED = true;
266
- const TREE_SHAKE_PREFERRED_LANGUAGE_STRATEGY_USED = false;
332
+ const TREE_SHAKE_URL_STRATEGY_USED = true;
333
+ const TREE_SHAKE_GLOBAL_VARIABLE_STRATEGY_USED = false;
334
+ const TREE_SHAKE_PREFERRED_LANGUAGE_STRATEGY_USED = true;
267
335
  const TREE_SHAKE_DEFAULT_URL_PATTERN_USED = true;
268
336
  const TREE_SHAKE_LOCAL_STORAGE_STRATEGY_USED = false;
269
337
 
270
- globalThis.__paraglide = {}
338
+ /** @type {any} */ (globalThis).__paraglide =
339
+ /** @type {any} */ (globalThis).__paraglide ?? {};
340
+ /** @type {any} */ (globalThis).__paraglide.ssr =
341
+ /** @type {any} */ (globalThis).__paraglide.ssr ?? {};
271
342
 
272
343
  /**
273
344
  * This is a fallback to get started with a custom
274
345
  * strategy and avoid type errors.
275
346
  *
276
347
  * The implementation is overwritten
277
- * by \`overwriteGetLocale()\` and \`defineSetLocale()\`.
348
+ * by `overwriteGetLocale()` and `defineSetLocale()`.
278
349
  *
279
- * @type {Locale|undefined}
350
+ * @type {Locale | undefined}
280
351
  */
281
352
  let _locale;
282
353
  let localeInitiallySet = false;
@@ -296,14 +367,12 @@ let localeInitiallySet = false;
296
367
  * console.log('Netherlands 🇳🇱');
297
368
  * }
298
369
  *
299
- * @type {() => Locale}
370
+ * @returns {Locale} The current locale.
300
371
  */
301
372
  export let getLocale = () => {
302
373
  if (experimentalStaticLocale !== undefined) {
303
- return assertIsLocale(experimentalStaticLocale);
374
+ return experimentalStaticLocale;
304
375
  }
305
- /** @type {string | undefined} */
306
- let locale;
307
376
  // if running in a server-side rendering context
308
377
  // retrieve the locale from the async local storage
309
378
  if (serverAsyncLocalStorage) {
@@ -312,7 +381,48 @@ export let getLocale = () => {
312
381
  return locale;
313
382
  }
314
383
  }
315
- for (const strat of strategy) {
384
+ let strategyToUse = strategy;
385
+ if (!isServer && typeof window !== "undefined" && window.location?.href) {
386
+ strategyToUse = getStrategyForUrl(window.location.href);
387
+ }
388
+ const resolved = resolveLocaleWithStrategies(strategyToUse, typeof window !== "undefined" ? window.location?.href : undefined);
389
+ if (resolved) {
390
+ if (!localeInitiallySet) {
391
+ _locale = resolved;
392
+ // https://github.com/opral/inlang-paraglide-js/issues/455
393
+ localeInitiallySet = true;
394
+ setLocale(resolved, { reload: false });
395
+ }
396
+ return resolved;
397
+ }
398
+ throw new Error("No locale found. Read the docs https://inlang.com/m/gerre34r/library-inlang-paraglideJs/errors#no-locale-found");
399
+ };
400
+ /**
401
+ * Resolve locale for a given URL using route-aware strategies.
402
+ *
403
+ * @param {string | URL} url
404
+ * @returns {Locale}
405
+ */
406
+ export function getLocaleForUrl(url) {
407
+ if (experimentalStaticLocale !== undefined) {
408
+ return experimentalStaticLocale;
409
+ }
410
+ const strategyToUse = getStrategyForUrl(url);
411
+ const resolved = resolveLocaleWithStrategies(strategyToUse, typeof url === "string" ? url : url.href);
412
+ if (resolved) {
413
+ return resolved;
414
+ }
415
+ throw new Error("No locale found. Read the docs https://inlang.com/m/gerre34r/library-inlang-paraglideJs/errors#no-locale-found");
416
+ }
417
+ /**
418
+ * @param {typeof strategy} strategyToUse
419
+ * @param {string | undefined} urlForUrlStrategy
420
+ * @returns {Locale | undefined}
421
+ */
422
+ function resolveLocaleWithStrategies(strategyToUse, urlForUrlStrategy) {
423
+ /** @type {string | undefined} */
424
+ let locale;
425
+ for (const strat of strategyToUse) {
316
426
  if (TREE_SHAKE_COOKIE_STRATEGY_USED && strat === "cookie") {
317
427
  locale = extractLocaleFromCookie();
318
428
  }
@@ -322,8 +432,8 @@ export let getLocale = () => {
322
432
  else if (TREE_SHAKE_URL_STRATEGY_USED &&
323
433
  strat === "url" &&
324
434
  !isServer &&
325
- typeof window !== "undefined") {
326
- locale = extractLocaleFromUrl(window.location.href);
435
+ typeof urlForUrlStrategy === "string") {
436
+ locale = extractLocaleFromUrl(urlForUrlStrategy);
327
437
  }
328
438
  else if (TREE_SHAKE_GLOBAL_VARIABLE_STRATEGY_USED &&
329
439
  strat === "globalVariable" &&
@@ -349,23 +459,18 @@ export let getLocale = () => {
349
459
  // Can't await in sync function, skip async strategies
350
460
  continue;
351
461
  }
352
- locale = result;
462
+ if (result !== undefined) {
463
+ return assertIsLocale(result);
464
+ }
353
465
  }
354
466
  }
355
- // check if match, else continue loop
356
- if (locale !== undefined) {
357
- const asserted = assertIsLocale(locale);
358
- if (!localeInitiallySet) {
359
- _locale = asserted;
360
- // https://github.com/opral/inlang-paraglide-js/issues/455
361
- localeInitiallySet = true;
362
- setLocale(asserted, { reload: false });
363
- }
364
- return asserted;
467
+ const matchedLocale = toLocale(locale);
468
+ if (matchedLocale) {
469
+ return matchedLocale;
365
470
  }
366
471
  }
367
- throw new Error("No locale found. Read the docs https://inlang.com/m/gerre34r/library-inlang-paraglideJs/errors#no-locale-found");
368
- };
472
+ return undefined;
473
+ }
369
474
  /**
370
475
  * Overwrite the `getLocale()` function.
371
476
  *
@@ -379,17 +484,61 @@ export let getLocale = () => {
379
484
  * return Cookies.get('locale') ?? baseLocale
380
485
  * });
381
486
  *
382
- * @type {(fn: () => Locale) => void}
487
+ * @param {() => Locale} fn - The new implementation for `getLocale()`.
383
488
  */
384
489
  export const overwriteGetLocale = (fn) => {
385
490
  getLocale = fn;
386
491
  };
387
492
 
493
+ const rtlLanguages = new Set([
494
+ "ar",
495
+ "dv",
496
+ "fa",
497
+ "he",
498
+ "ks",
499
+ "ku",
500
+ "ps",
501
+ "sd",
502
+ "ug",
503
+ "ur",
504
+ "yi",
505
+ ]);
506
+ /**
507
+ * Get writing direction for a locale.
508
+ *
509
+ * Uses `Intl.Locale` text info when available and falls back to a
510
+ * language-based RTL check for runtimes without `getTextInfo()`.
511
+ *
512
+ * @example
513
+ * getTextDirection(); // "ltr" or "rtl" for current locale
514
+ * getTextDirection("ar"); // "rtl"
515
+ * getTextDirection("en"); // "ltr"
516
+ *
517
+ * @param {string} [locale] - Target locale. If not provided, uses `getLocale()`
518
+ * @returns {"ltr" | "rtl"}
519
+ */
520
+ export function getTextDirection(locale = getLocale()) {
521
+ try {
522
+ const intlLocale = /** @type {Intl.Locale & {
523
+ getTextInfo?: () => { direction?: string };
524
+ textInfo?: { direction?: string };
525
+ }} */ (new Intl.Locale(locale));
526
+ const direction = intlLocale.getTextInfo?.().direction ?? intlLocale.textInfo?.direction;
527
+ if (direction === "ltr" || direction === "rtl") {
528
+ return direction;
529
+ }
530
+ }
531
+ catch {
532
+ // Ignore Intl.Locale parsing/runtime errors and use fallback below.
533
+ }
534
+ const language = locale.split("-")[0]?.toLowerCase();
535
+ return rtlLanguages.has(language ?? "") ? "rtl" : "ltr";
536
+ }
537
+
388
538
  /**
389
539
  * Navigates to the localized URL, or reloads the current page
390
540
  *
391
541
  * @param {string} [newLocation] The new location
392
- * @return {undefined}
393
542
  */
394
543
  const navigateOrReload = (newLocation) => {
395
544
  if (newLocation) {
@@ -440,11 +589,15 @@ export let setLocale = (newLocale, options) => {
440
589
  catch {
441
590
  // do nothing, no locale has been set yet.
442
591
  }
443
- /** @type {Array<Promise<any>>} */
592
+ /** @type {Array<Promise<void>>} */
444
593
  const customSetLocalePromises = [];
445
594
  /** @type {string | undefined} */
446
595
  let newLocation = undefined;
447
- for (const strat of strategy) {
596
+ let strategyToUse = strategy;
597
+ if (!isServer && typeof window !== "undefined" && window.location?.href) {
598
+ strategyToUse = getStrategyForUrl(window.location.href);
599
+ }
600
+ for (const strat of strategyToUse) {
448
601
  if (TREE_SHAKE_GLOBAL_VARIABLE_STRATEGY_USED &&
449
602
  strat === "globalVariable") {
450
603
  // a default for a custom strategy to get started quickly
@@ -521,7 +674,7 @@ export let setLocale = (newLocale, options) => {
521
674
  return;
522
675
  };
523
676
  /**
524
- * Overwrite the \`setLocale()\` function.
677
+ * Overwrite the `setLocale()` function.
525
678
  *
526
679
  * Use this function to overwrite how the locale is set. For example,
527
680
  * modify a cookie, env variable, or a user's preference.
@@ -535,7 +688,7 @@ export let setLocale = (newLocale, options) => {
535
688
  * @param {SetLocaleFn} fn
536
689
  */
537
690
  export const overwriteSetLocale = (fn) => {
538
- setLocale = /** @type {SetLocaleFn} */ (fn);
691
+ setLocale = fn;
539
692
  };
540
693
 
541
694
  /**
@@ -562,14 +715,32 @@ export let getUrlOrigin = () => {
562
715
  * Use this function in server environments to
563
716
  * define how the URL origin is resolved.
564
717
  *
565
- * @type {(fn: () => string) => void}
718
+ * @param {() => string} fn - The new implementation for `getUrlOrigin()`.
566
719
  */
567
720
  export let overwriteGetUrlOrigin = (fn) => {
568
721
  getUrlOrigin = fn;
569
722
  };
570
723
 
571
724
  /**
572
- * Check if something is an available locale.
725
+ * Coerces a locale-like string to the canonical locale value used by the runtime.
726
+ *
727
+ * @param {unknown} value
728
+ * @returns {Locale | undefined}
729
+ */
730
+ export function toLocale(value) {
731
+ if (typeof value !== "string") {
732
+ return undefined;
733
+ }
734
+ const lowerValue = value.toLowerCase();
735
+ for (const locale of locales) {
736
+ if (locale.toLowerCase() === lowerValue) {
737
+ return locale;
738
+ }
739
+ }
740
+ return undefined;
741
+ }
742
+ /**
743
+ * Check if something is an available locale with the canonical project casing.
573
744
  *
574
745
  * @example
575
746
  * if (isLocale(params.locale)) {
@@ -578,36 +749,32 @@ export let overwriteGetUrlOrigin = (fn) => {
578
749
  * setLocale('en');
579
750
  * }
580
751
  *
581
- * @param {any} locale
752
+ * Use `toLocale()` when you want case-insensitive matching and canonicalization.
753
+ *
754
+ * @param {unknown} locale
582
755
  * @returns {locale is Locale}
583
756
  */
584
757
  export function isLocale(locale) {
585
- if (typeof locale !== "string")
586
- return false;
587
- return !locale
588
- ? false
589
- : locales.some((item) => item.toLowerCase() === locale.toLowerCase());
758
+ return !!locale && locales.some((item) => item === locale);
590
759
  }
591
-
592
760
  /**
593
- * Asserts that the input is a locale.
761
+ * Asserts that the input can be normalized to a locale.
594
762
  *
595
- * @param {any} input - The input to check.
596
- * @returns {Locale} The input if it is a locale.
763
+ * @param {unknown} input - The input to check.
764
+ * @returns {Locale} The input normalized to a Locale.
597
765
  * @throws {Error} If the input is not a locale.
598
766
  */
599
767
  export function assertIsLocale(input) {
600
- if (typeof input !== "string") {
601
- throw new Error(`Invalid locale: ${input}. Expected a string.`);
602
- }
603
- const lowerInput = input.toLowerCase();
604
- const matchedLocale = locales.find((item) => item.toLowerCase() === lowerInput);
605
- if (!matchedLocale) {
606
- throw new Error(`Invalid locale: ${input}. Expected one of: ${locales.join(", ")}`);
607
- }
608
- return matchedLocale;
768
+ const locale = toLocale(input);
769
+ if (locale)
770
+ return locale;
771
+ throw new Error(`Invalid locale: ${input}. Expected one of: ${locales.join(", ")}`);
609
772
  }
610
773
 
774
+ /**
775
+ * @typedef {object} ExtractLocaleFromRequestOptions
776
+ * @property {string | URL} [effectiveRequestUrl] - Effective request URL to use for route matching and locale detection with the URL strategy.
777
+ */
611
778
  /**
612
779
  * Extracts a locale from a request.
613
780
  *
@@ -624,12 +791,27 @@ export function assertIsLocale(input) {
624
791
  * @example
625
792
  * const locale = extractLocaleFromRequest(request);
626
793
  *
627
- * @type {(request: Request) => Locale}
794
+ * @param {Request} request
795
+ * @param {ExtractLocaleFromRequestOptions} [options]
796
+ * @returns {Locale}
797
+ */
798
+ export const extractLocaleFromRequest = (request, options = {}) => {
799
+ const effectiveRequestUrl = resolveEffectiveRequestUrl(request, options.effectiveRequestUrl);
800
+ return extractLocaleFromRequestWithStrategies(request, getStrategyForUrl(effectiveRequestUrl), effectiveRequestUrl);
801
+ };
802
+ /**
803
+ * Extracts a locale from a request using the provided strategy order.
804
+ *
805
+ * @param {Request} request
806
+ * @param {typeof strategy} strategies
807
+ * @param {string | URL} [url]
808
+ * @returns {Locale}
628
809
  */
629
- export const extractLocaleFromRequest = (request) => {
810
+ export const extractLocaleFromRequestWithStrategies = (request, strategies, url = request.url) => {
811
+ const effectiveRequestUrl = resolveEffectiveRequestUrl(request, url);
630
812
  /** @type {string|undefined} */
631
813
  let locale;
632
- for (const strat of strategy) {
814
+ for (const strat of strategies) {
633
815
  if (TREE_SHAKE_COOKIE_STRATEGY_USED && strat === "cookie") {
634
816
  locale = request.headers
635
817
  .get("cookie")
@@ -638,7 +820,7 @@ export const extractLocaleFromRequest = (request) => {
638
820
  ?.split("=")[1];
639
821
  }
640
822
  else if (TREE_SHAKE_URL_STRATEGY_USED && strat === "url") {
641
- locale = extractLocaleFromUrl(request.url);
823
+ locale = extractLocaleFromUrl(effectiveRequestUrl);
642
824
  }
643
825
  else if (TREE_SHAKE_PREFERRED_LANGUAGE_STRATEGY_USED &&
644
826
  strat === "preferredLanguage") {
@@ -658,17 +840,24 @@ export const extractLocaleFromRequest = (request) => {
658
840
  // Use extractLocaleFromRequestAsync for custom server strategies
659
841
  continue;
660
842
  }
661
- if (locale !== undefined) {
662
- if (!isLocale(locale)) {
663
- locale = undefined;
664
- }
665
- else {
666
- return assertIsLocale(locale);
667
- }
843
+ const matchedLocale = toLocale(locale);
844
+ if (matchedLocale) {
845
+ return matchedLocale;
668
846
  }
669
847
  }
670
848
  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");
671
849
  };
850
+ /**
851
+ * @param {Request} request
852
+ * @param {string | URL | undefined} effectiveRequestUrl
853
+ * @returns {URL}
854
+ */
855
+ function resolveEffectiveRequestUrl(request, effectiveRequestUrl = request.url) {
856
+ if (effectiveRequestUrl instanceof URL) {
857
+ return new URL(effectiveRequestUrl.href);
858
+ }
859
+ return new URL(effectiveRequestUrl, request.url);
860
+ }
672
861
 
673
862
  /**
674
863
  * Asynchronously extracts a locale from a request.
@@ -697,11 +886,15 @@ export const extractLocaleFromRequest = (request) => {
697
886
  *
698
887
  * const locale = await extractLocaleFromRequestAsync(request);
699
888
  *
700
- * @type {(request: Request) => Promise<Locale>}
889
+ * @param {Request} request - The request object to extract the locale from.
890
+ * @param {{ effectiveRequestUrl?: string | URL }} [options] - Effective request URL to use for route matching and locale detection with the URL strategy.
891
+ * @returns {Promise<Locale>} The extracted locale.
701
892
  */
702
- export const extractLocaleFromRequestAsync = async (request) => {
893
+ export const extractLocaleFromRequestAsync = async (request, options = {}) => {
703
894
  /** @type {string|undefined} */
704
895
  let locale;
896
+ const effectiveRequestUrl = resolveEffectiveRequestUrlFromRequestAsync(request, options.effectiveRequestUrl);
897
+ const strategy = getStrategyForUrl(effectiveRequestUrl);
705
898
  // Process custom strategies first, in order
706
899
  for (const strat of strategy) {
707
900
  if (isCustomStrategy(strat) && customServerStrategies.has(strat)) {
@@ -711,15 +904,26 @@ export const extractLocaleFromRequestAsync = async (request) => {
711
904
  locale = await handler.getLocale(request);
712
905
  }
713
906
  // If we got a valid locale from this custom strategy, use it
714
- if (locale !== undefined && isLocale(locale)) {
715
- return assertIsLocale(locale);
907
+ const matchedLocale = toLocale(locale);
908
+ if (matchedLocale) {
909
+ return matchedLocale;
716
910
  }
717
911
  }
718
912
  }
719
913
  // If no custom strategy provided a valid locale, fall back to sync version
720
- locale = extractLocaleFromRequest(request);
721
- return assertIsLocale(locale);
914
+ return extractLocaleFromRequestWithStrategies(request, strategy, effectiveRequestUrl);
722
915
  };
916
+ /**
917
+ * @param {Request} request
918
+ * @param {string | URL | undefined} effectiveRequestUrl
919
+ * @returns {URL}
920
+ */
921
+ function resolveEffectiveRequestUrlFromRequestAsync(request, effectiveRequestUrl = request.url) {
922
+ if (effectiveRequestUrl instanceof URL) {
923
+ return new URL(effectiveRequestUrl.href);
924
+ }
925
+ return new URL(effectiveRequestUrl, request.url);
926
+ }
723
927
 
724
928
  /**
725
929
  * Extracts a cookie from the document.
@@ -727,7 +931,7 @@ export const extractLocaleFromRequestAsync = async (request) => {
727
931
  * Will return undefined if the document is not available or if the cookie is not set.
728
932
  * The `document` object is not available in server-side rendering, so this function should not be called in that context.
729
933
  *
730
- * @returns {string | undefined}
934
+ * @returns {Locale | undefined}
731
935
  */
732
936
  export function extractLocaleFromCookie() {
733
937
  if (typeof document === "undefined" || !document.cookie) {
@@ -735,10 +939,7 @@ export function extractLocaleFromCookie() {
735
939
  }
736
940
  const match = document.cookie.match(new RegExp(`(^| )${cookieName}=([^;]+)`));
737
941
  const locale = match?.[2];
738
- if (isLocale(locale)) {
739
- return locale;
740
- }
741
- return undefined;
942
+ return toLocale(locale);
742
943
  }
743
944
 
744
945
  /**
@@ -750,9 +951,8 @@ export function extractLocaleFromCookie() {
750
951
  * @example
751
952
  * const locale = extractLocaleFromHeader(request);
752
953
  *
753
- * @type {(request: Request) => Locale}
754
954
  * @param {Request} request - The request object to extract the locale from.
755
- * @returns {string|undefined} The negotiated preferred language.
955
+ * @returns {Locale | undefined} The negotiated preferred language.
756
956
  */
757
957
  export function extractLocaleFromHeader(request) {
758
958
  const acceptLanguageHeader = request.headers.get("accept-language");
@@ -763,20 +963,22 @@ export function extractLocaleFromHeader(request) {
763
963
  .map((lang) => {
764
964
  const [tag, q = "1"] = lang.trim().split(";q=");
765
965
  // Get both the full tag and base language code
766
- const baseTag = tag?.split("-")[0]?.toLowerCase();
966
+ const baseTag = tag?.split("-")[0];
767
967
  return {
768
- fullTag: tag?.toLowerCase(),
968
+ fullTag: tag,
769
969
  baseTag,
770
970
  q: Number(q),
771
971
  };
772
972
  })
773
973
  .sort((a, b) => b.q - a.q);
774
974
  for (const lang of languages) {
775
- if (isLocale(lang.fullTag)) {
776
- return lang.fullTag;
975
+ const fullLocale = toLocale(lang.fullTag);
976
+ if (fullLocale) {
977
+ return fullLocale;
777
978
  }
778
- else if (isLocale(lang.baseTag)) {
779
- return lang.baseTag;
979
+ const baseLocale = toLocale(lang.baseTag);
980
+ if (baseLocale) {
981
+ return baseLocale;
780
982
  }
781
983
  }
782
984
  return undefined;
@@ -793,23 +995,24 @@ export function extractLocaleFromHeader(request) {
793
995
  * @example
794
996
  * const locale = extractLocaleFromNavigator();
795
997
  *
796
- * @type {() => Locale | undefined}
797
- * @returns {string | undefined}
998
+ * @returns {Locale | undefined}
798
999
  */
799
1000
  export function extractLocaleFromNavigator() {
800
1001
  if (!navigator?.languages?.length) {
801
1002
  return undefined;
802
1003
  }
803
1004
  const languages = navigator.languages.map((lang) => ({
804
- fullTag: lang.toLowerCase(),
805
- baseTag: lang.split("-")[0]?.toLowerCase(),
1005
+ fullTag: lang,
1006
+ baseTag: lang.split("-")[0],
806
1007
  }));
807
1008
  for (const lang of languages) {
808
- if (isLocale(lang.fullTag)) {
809
- return lang.fullTag;
1009
+ const fullLocale = toLocale(lang.fullTag);
1010
+ if (fullLocale) {
1011
+ return fullLocale;
810
1012
  }
811
- else if (isLocale(lang.baseTag)) {
812
- return lang.baseTag;
1013
+ const baseLocale = toLocale(lang.baseTag);
1014
+ if (baseLocale) {
1015
+ return baseLocale;
813
1016
  }
814
1017
  }
815
1018
  return undefined;
@@ -828,6 +1031,10 @@ let cachedLocale;
828
1031
  /**
829
1032
  * Extracts the locale from a given URL using native URLPattern.
830
1033
  *
1034
+ * The built-in default `/:locale/...` routing is case-insensitive because it
1035
+ * canonicalizes the first path segment with `toLocale()`. Custom `urlPatterns`
1036
+ * keep URLPattern's normal exact matching semantics for path segments.
1037
+ *
831
1038
  * @param {URL|string} url - The full URL from which to extract the locale.
832
1039
  * @returns {Locale|undefined} The extracted locale, or undefined if no locale is found.
833
1040
  */
@@ -836,6 +1043,7 @@ export function extractLocaleFromUrl(url) {
836
1043
  if (cachedUrl === urlString) {
837
1044
  return cachedLocale;
838
1045
  }
1046
+ /** @type {Locale | undefined} */
839
1047
  let result;
840
1048
  if (TREE_SHAKE_DEFAULT_URL_PATTERN_USED) {
841
1049
  result = defaultUrlPatternExtractLocale(url);
@@ -846,11 +1054,7 @@ export function extractLocaleFromUrl(url) {
846
1054
  for (const element of urlPatterns) {
847
1055
  for (const [locale, localizedPattern] of element.localized) {
848
1056
  const match = new URLPattern(localizedPattern, urlObj.href).exec(urlObj.href);
849
- if (!match) {
850
- continue;
851
- }
852
- // Check if the locale is valid
853
- if (assertIsLocale(locale)) {
1057
+ if (match) {
854
1058
  result = locale;
855
1059
  break;
856
1060
  }
@@ -866,20 +1070,13 @@ export function extractLocaleFromUrl(url) {
866
1070
  /**
867
1071
  * https://github.com/opral/inlang-paraglide-js/issues/381
868
1072
  *
869
- * @param {URL|string} url - The full URL from which to extract the locale.
870
- * @returns {Locale|undefined} The extracted locale, or undefined if no locale is found.
1073
+ * @param {URL | string} url - The full URL from which to extract the locale.
1074
+ * @returns {Locale | undefined} The extracted locale, or undefined if no locale is found.
871
1075
  */
872
1076
  function defaultUrlPatternExtractLocale(url) {
873
1077
  const urlObj = new URL(url, "http://dummy.com");
874
1078
  const pathSegments = urlObj.pathname.split("/").filter(Boolean);
875
- if (pathSegments.length > 0) {
876
- const potentialLocale = pathSegments[0];
877
- if (isLocale(potentialLocale)) {
878
- return potentialLocale;
879
- }
880
- }
881
- // everything else has to be the base locale
882
- return baseLocale;
1079
+ return toLocale(pathSegments[0]) || baseLocale;
883
1080
  }
884
1081
 
885
1082
  /**
@@ -922,15 +1119,17 @@ function defaultUrlPatternExtractLocale(url) {
922
1119
  * ```
923
1120
  *
924
1121
  * @param {string | URL} url - The URL to localize. If string, must be absolute.
925
- * @param {Object} [options] - Options for localization
926
- * @param {string} [options.locale] - Target locale. If not provided, uses getLocale()
1122
+ * @param {object} [options] - Options for localization
1123
+ * @param {Locale} [options.locale] - Target locale. If not provided, uses getLocale()
927
1124
  * @returns {URL} The localized URL, always absolute
928
1125
  */
929
1126
  export function localizeUrl(url, options) {
1127
+ const targetLocale = options?.locale
1128
+ ? assertIsLocale(options?.locale)
1129
+ : getLocale();
930
1130
  if (TREE_SHAKE_DEFAULT_URL_PATTERN_USED) {
931
- return localizeUrlDefaultPattern(url, options);
1131
+ return localizeUrlDefaultPattern(url, targetLocale);
932
1132
  }
933
- const targetLocale = options?.locale ?? getLocale();
934
1133
  const urlObj = typeof url === "string" ? new URL(url) : url;
935
1134
  // Iterate over URL patterns
936
1135
  for (const element of urlPatterns) {
@@ -963,13 +1162,11 @@ export function localizeUrl(url, options) {
963
1162
  * https://github.com/opral/inlang-paraglide-js/issues/381
964
1163
  *
965
1164
  * @param {string | URL} url
966
- * @param {Object} [options]
967
- * @param {string} [options.locale]
1165
+ * @param {Locale} locale
968
1166
  * @returns {URL}
969
1167
  */
970
- function localizeUrlDefaultPattern(url, options) {
1168
+ function localizeUrlDefaultPattern(url, locale) {
971
1169
  const urlObj = typeof url === "string" ? new URL(url, getUrlOrigin()) : new URL(url);
972
- const locale = options?.locale ?? getLocale();
973
1170
  const currentLocale = extractLocaleFromUrl(urlObj);
974
1171
  // If current locale matches target locale, no change needed
975
1172
  if (currentLocale === locale) {
@@ -977,7 +1174,7 @@ function localizeUrlDefaultPattern(url, options) {
977
1174
  }
978
1175
  const pathSegments = urlObj.pathname.split("/").filter(Boolean);
979
1176
  // If current path starts with a locale, remove it
980
- if (pathSegments.length > 0 && isLocale(pathSegments[0])) {
1177
+ if (pathSegments.length > 0 && toLocale(pathSegments[0])) {
981
1178
  pathSegments.shift();
982
1179
  }
983
1180
  // For base locale, don't add prefix
@@ -1065,7 +1262,7 @@ function deLocalizeUrlDefaultPattern(url) {
1065
1262
  const urlObj = typeof url === "string" ? new URL(url, getUrlOrigin()) : new URL(url);
1066
1263
  const pathSegments = urlObj.pathname.split("/").filter(Boolean);
1067
1264
  // If first segment is a locale, remove it
1068
- if (pathSegments.length > 0 && isLocale(pathSegments[0])) {
1265
+ if (pathSegments.length > 0 && toLocale(pathSegments[0])) {
1069
1266
  urlObj.pathname = "/" + pathSegments.slice(1).join("/");
1070
1267
  }
1071
1268
  return urlObj;
@@ -1178,7 +1375,8 @@ function fillPattern(pattern, values, origin) {
1178
1375
  * Aggregates named groups from various parts of the URLPattern match result.
1179
1376
  *
1180
1377
  *
1181
- * @type {(match: any) => Record<string, string | null | undefined>}
1378
+ * @param {any} match - The URLPattern match result object.
1379
+ * @returns {Record<string, string | null | undefined>} An object containing all named groups from the match.
1182
1380
  */
1183
1381
  export function aggregateGroups(match) {
1184
1382
  return {
@@ -1196,19 +1394,19 @@ export function aggregateGroups(match) {
1196
1394
  /**
1197
1395
  * @typedef {object} ShouldRedirectServerInput
1198
1396
  * @property {Request} request
1199
- * @property {string | URL} [url]
1200
- * @property {ReturnType<typeof assertIsLocale>} [locale]
1397
+ * @property {string | URL} [effectiveRequestUrl] - Effective request URL to use for route matching, locale detection with the URL strategy, and redirect targets.
1398
+ * @property {Locale} [locale]
1201
1399
  *
1202
1400
  * @typedef {object} ShouldRedirectClientInput
1203
1401
  * @property {undefined} [request]
1204
1402
  * @property {string | URL} [url]
1205
- * @property {ReturnType<typeof assertIsLocale>} [locale]
1403
+ * @property {Locale} [locale]
1206
1404
  *
1207
1405
  * @typedef {ShouldRedirectServerInput | ShouldRedirectClientInput} ShouldRedirectInput
1208
1406
  *
1209
1407
  * @typedef {object} ShouldRedirectResult
1210
1408
  * @property {boolean} shouldRedirect - Indicates whether the consumer should perform a redirect.
1211
- * @property {ReturnType<typeof assertIsLocale>} locale - Locale resolved using the configured strategies.
1409
+ * @property {Locale} locale - Locale resolved using the configured strategies.
1212
1410
  * @property {URL | undefined} redirectUrl - Destination URL when a redirect is required.
1213
1411
  */
1214
1412
  /**
@@ -1244,15 +1442,33 @@ export function aggregateGroups(match) {
1244
1442
  * return render(request, decision.locale);
1245
1443
  * }
1246
1444
  *
1445
+ * @example
1446
+ * // Server side usage behind a proxy where request.url is not public-facing
1447
+ * export async function handle(request) {
1448
+ * const effectiveRequestUrl = new URL(request.url);
1449
+ * effectiveRequestUrl.protocol = "https:";
1450
+ * effectiveRequestUrl.host = "example.com";
1451
+ *
1452
+ * const decision = await shouldRedirect({
1453
+ * request,
1454
+ * effectiveRequestUrl,
1455
+ * });
1456
+ *
1457
+ * if (decision.shouldRedirect) {
1458
+ * return Response.redirect(decision.redirectUrl, 307);
1459
+ * }
1460
+ * }
1461
+ *
1247
1462
  * @param {ShouldRedirectInput} [input]
1248
1463
  * @returns {Promise<ShouldRedirectResult>}
1249
1464
  */
1250
1465
  export async function shouldRedirect(input = {}) {
1251
- const locale = /** @type {ReturnType<typeof assertIsLocale>} */ (await resolveLocale(input));
1252
- if (!strategy.includes("url")) {
1466
+ const currentUrl = resolveUrl(input);
1467
+ const locale = await resolveLocale(input, currentUrl);
1468
+ const strategy = getStrategyForUrl(currentUrl.href);
1469
+ if (isExcludedByRouteStrategy(currentUrl.href) || !strategy.includes("url")) {
1253
1470
  return { shouldRedirect: false, locale, redirectUrl: undefined };
1254
1471
  }
1255
- const currentUrl = resolveUrl(input);
1256
1472
  const localizedUrl = localizeUrl(currentUrl.href, { locale });
1257
1473
  const shouldRedirectToLocalizedUrl = normalizeUrl(localizedUrl.href) !== normalizeUrl(currentUrl.href);
1258
1474
  return {
@@ -1265,14 +1481,21 @@ export async function shouldRedirect(input = {}) {
1265
1481
  * Resolves the locale either from the provided input or by using the configured strategies.
1266
1482
  *
1267
1483
  * @param {ShouldRedirectInput} input
1268
- * @returns {Promise<ReturnType<typeof assertIsLocale>>}
1484
+ * @param {URL} currentUrl
1485
+ * @returns {Promise<Locale>}
1269
1486
  */
1270
- async function resolveLocale(input) {
1271
- if (input.locale) {
1272
- return assertIsLocale(input.locale);
1487
+ async function resolveLocale(input, currentUrl) {
1488
+ const locale = toLocale(input.locale);
1489
+ if (locale) {
1490
+ return locale;
1273
1491
  }
1274
1492
  if (input.request) {
1275
- return extractLocaleFromRequestAsync(input.request);
1493
+ return extractLocaleFromRequestAsync(input.request, {
1494
+ effectiveRequestUrl: currentUrl,
1495
+ });
1496
+ }
1497
+ if ("url" in input && typeof input.url !== "undefined") {
1498
+ return getLocaleForUrl(currentUrl.href);
1276
1499
  }
1277
1500
  return getLocale();
1278
1501
  }
@@ -1283,13 +1506,19 @@ async function resolveLocale(input) {
1283
1506
  * @returns {URL}
1284
1507
  */
1285
1508
  function resolveUrl(input) {
1509
+ if ("effectiveRequestUrl" in input && input.effectiveRequestUrl instanceof URL) {
1510
+ return new URL(input.effectiveRequestUrl.href);
1511
+ }
1512
+ if ("effectiveRequestUrl" in input && typeof input.effectiveRequestUrl === "string") {
1513
+ return new URL(input.effectiveRequestUrl, input.request ? input.request.url : getUrlOrigin());
1514
+ }
1286
1515
  if (input.request) {
1287
1516
  return new URL(input.request.url);
1288
1517
  }
1289
- if (input.url instanceof URL) {
1518
+ if ("url" in input && input.url instanceof URL) {
1290
1519
  return new URL(input.url.href);
1291
1520
  }
1292
- if (typeof input.url === "string") {
1521
+ if ("url" in input && typeof input.url === "string") {
1293
1522
  return new URL(input.url, getUrlOrigin());
1294
1523
  }
1295
1524
  if (typeof window !== "undefined" && window?.location?.href) {
@@ -1345,8 +1574,8 @@ function normalizeUrl(url) {
1345
1574
  * which provides more precise control over URL handling.
1346
1575
  *
1347
1576
  * @param {string} href - The href to localize (can be relative or absolute)
1348
- * @param {Object} [options] - Options for localization
1349
- * @param {string} [options.locale] - Target locale. If not provided, uses `getLocale()`
1577
+ * @param {object} [options] - Options for localization
1578
+ * @param {Locale} [options.locale] - Target locale. If not provided, uses `getLocale()`
1350
1579
  * @returns {string} The localized href, relative if input was relative
1351
1580
  */
1352
1581
  export function localizeHref(href, options) {
@@ -1478,6 +1707,7 @@ export function trackMessageCall(safeModuleId, locale) {
1478
1707
  * The order follows each input URL with all its locale variants before moving to the next URL.
1479
1708
  */
1480
1709
  export function generateStaticLocalizedUrls(urls) {
1710
+ /** @type {Set<URL>} */
1481
1711
  const localizedUrls = new Set();
1482
1712
  // For default URL pattern, we can optimize the generation
1483
1713
  if (TREE_SHAKE_DEFAULT_URL_PATTERN_USED) {
@@ -1570,7 +1800,7 @@ export const customClientStrategies = new Map();
1570
1800
  /**
1571
1801
  * Checks if the given strategy is a custom strategy.
1572
1802
  *
1573
- * @param {any} strategy The name of the custom strategy to validate.
1803
+ * @param {unknown} strategy The name of the custom strategy to validate.
1574
1804
  * Must be a string that starts with "custom-" followed by alphanumeric characters, hyphens, or underscores.
1575
1805
  * @returns {boolean} Returns true if it is a custom strategy, false otherwise.
1576
1806
  */
@@ -1582,7 +1812,7 @@ export function isCustomStrategy(strategy) {
1582
1812
  *
1583
1813
  * @see https://inlang.com/m/gerre34r/library-inlang-paraglideJs/strategy#write-your-own-strategy
1584
1814
  *
1585
- * @param {any} strategy The name of the custom strategy to define. Must follow the pattern custom-name with alphanumeric characters, hyphens, or underscores.
1815
+ * @param {string} strategy The name of the custom strategy to define. Must follow the pattern custom-name with alphanumeric characters, hyphens, or underscores.
1586
1816
  * @param {CustomServerStrategyHandler} handler The handler for the custom strategy, which should implement
1587
1817
  * the method getLocale.
1588
1818
  * @returns {void}
@@ -1598,7 +1828,7 @@ export function defineCustomServerStrategy(strategy, handler) {
1598
1828
  *
1599
1829
  * @see https://inlang.com/m/gerre34r/library-inlang-paraglideJs/strategy#write-your-own-strategy
1600
1830
  *
1601
- * @param {any} strategy The name of the custom strategy to define. Must follow the pattern custom-name with alphanumeric characters, hyphens, or underscores.
1831
+ * @param {string} strategy The name of the custom strategy to define. Must follow the pattern custom-name with alphanumeric characters, hyphens, or underscores.
1602
1832
  * @param {CustomClientStrategyHandler} handler The handler for the custom strategy, which should implement the
1603
1833
  * methods getLocale and setLocale.
1604
1834
  * @returns {void}
@@ -1611,26 +1841,25 @@ export function defineCustomClientStrategy(strategy, handler) {
1611
1841
  }
1612
1842
 
1613
1843
  // ------ TYPES ------
1614
-
1844
+ export {};
1615
1845
  /**
1616
1846
  * A locale that is available in the project.
1617
1847
  *
1618
1848
  * @example
1619
1849
  * setLocale(request.locale as Locale)
1620
1850
  *
1621
- * @typedef {(typeof locales)[number]} Locale
1851
+ * @typedef {typeof locales[number]} Locale
1622
1852
  */
1623
-
1624
1853
  /**
1625
1854
  * A branded type representing a localized string.
1626
1855
  *
1627
- * Message functions return this type instead of `string`, enabling TypeScript
1856
+ * Message functions return this type instead of \`string\`, enabling TypeScript
1628
1857
  * to distinguish translated strings from regular strings at compile time.
1629
1858
  * This allows you to enforce that only properly localized content is used
1630
1859
  * in your UI components.
1631
1860
  *
1632
- * Since `LocalizedString` is a branded subtype of `string`, it remains fully
1633
- * backward compatible—you can pass it anywhere a `string` is expected.
1861
+ * Since \`LocalizedString\` is a branded subtype of \`string\`, it remains fully
1862
+ * backward compatible—you can pass it anywhere a \`string\` is expected.
1634
1863
  *
1635
1864
  * @example
1636
1865
  * // Enforce localized strings in your components
@@ -1662,4 +1891,100 @@ export function defineCustomClientStrategy(strategy, handler) {
1662
1891
  *
1663
1892
  * @typedef {string & { readonly __brand: 'LocalizedString' }} LocalizedString
1664
1893
  */
1665
-
1894
+ /**
1895
+ * A single markup option passed to a tag instance.
1896
+ *
1897
+ * @typedef {{
1898
+ * name: string;
1899
+ * value: unknown;
1900
+ * }} MessageMarkupOption
1901
+ */
1902
+ /**
1903
+ * A single static markup attribute attached to a tag instance.
1904
+ *
1905
+ * @typedef {{
1906
+ * name: string;
1907
+ * value: string | true;
1908
+ * }} MessageMarkupAttribute
1909
+ */
1910
+ /**
1911
+ * Record of markup options for a tag instance.
1912
+ *
1913
+ * @typedef {Record<string, unknown>} MessageMarkupOptions
1914
+ */
1915
+ /**
1916
+ * Record of markup attributes for a tag instance.
1917
+ *
1918
+ * @typedef {Record<string, string | true>} MessageMarkupAttributes
1919
+ */
1920
+ /**
1921
+ * Type-level schema for a single markup tag.
1922
+ *
1923
+ * @typedef {{
1924
+ * options: MessageMarkupOptions;
1925
+ * attributes: MessageMarkupAttributes;
1926
+ * children: boolean;
1927
+ * }} MessageMarkupTag
1928
+ */
1929
+ /**
1930
+ * Type-level schema for all markup tags in a message.
1931
+ *
1932
+ * @typedef {Record<string, MessageMarkupTag>} MessageMarkupSchema
1933
+ */
1934
+ /**
1935
+ * Type-only metadata attached to compiled message functions.
1936
+ *
1937
+ * @template Inputs
1938
+ * @template Options
1939
+ * @template {MessageMarkupSchema} [Markup = MessageMarkupSchema]
1940
+ * @typedef {{
1941
+ * readonly __paraglide?: {
1942
+ * inputs: Inputs;
1943
+ * options: Options;
1944
+ * markup: Markup;
1945
+ * };
1946
+ * }} MessageMetadata
1947
+ */
1948
+ /**
1949
+ * A compiled, framework-neutral message part.
1950
+ *
1951
+ * @typedef {{
1952
+ * type: "text";
1953
+ * value: string;
1954
+ * } | {
1955
+ * type: "markup-start";
1956
+ * name: string;
1957
+ * options: MessageMarkupOptions;
1958
+ * attributes: MessageMarkupAttributes;
1959
+ * } | {
1960
+ * type: "markup-end";
1961
+ * name: string;
1962
+ * options: MessageMarkupOptions;
1963
+ * attributes: MessageMarkupAttributes;
1964
+ * } | {
1965
+ * type: "markup-standalone";
1966
+ * name: string;
1967
+ * options: MessageMarkupOptions;
1968
+ * attributes: MessageMarkupAttributes;
1969
+ * }} MessagePart
1970
+ */
1971
+ /**
1972
+ * A message function is a message for a specific locale.
1973
+ *
1974
+ * @example
1975
+ * m.hello({ name: 'world' })
1976
+ *
1977
+ * @typedef {(inputs?: Record<string, never>) => LocalizedString} MessageFunction
1978
+ */
1979
+ /**
1980
+ * A message bundle function that selects the message to be returned.
1981
+ *
1982
+ * Uses `getLocale()` under the hood to determine the locale with an option.
1983
+ *
1984
+ * @template {string} T
1985
+ *
1986
+ * @example
1987
+ * * m.hello({ name: 'world' }, { locale: "en" })
1988
+ *
1989
+ * @typedef {(params: Record<string, never>, options: { locale: T }) => LocalizedString} MessageBundleFunction
1990
+ */