@manafishrov/ui 1.5.13 → 1.5.14

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.
@@ -44,8 +44,7 @@ export type FieldSeparatorProps = ComponentProps<'div'> & {
44
44
  };
45
45
  export declare const FieldSeparator: Component<FieldSeparatorProps>;
46
46
  export type FieldErrorProps = PrimitiveField.ErrorTextProps & {
47
- errors?: ({
48
- message?: string;
49
- } | string | undefined)[];
47
+ /** Display strings or objects with a string message; ignore other validator values. */
48
+ errors?: readonly unknown[];
50
49
  };
51
50
  export declare const FieldError: Component<FieldErrorProps>;
@@ -2,12 +2,13 @@ import { cn as e, tv as t } from "../node_modules/.bun/tailwind-variants@3.3.1_a
2
2
  import { Separator as n } from "./Separator.js";
3
3
  import { fieldset_exports as r, useFieldset as i } from "../node_modules/.bun/@ark-ui_solid@5.39.2_da52f1d607d95169/node_modules/@ark-ui/solid/dist/chunk/CKRLVLGC.js";
4
4
  import { field_exports as a } from "../node_modules/.bun/@ark-ui_solid@5.39.2_da52f1d607d95169/node_modules/@ark-ui/solid/dist/chunk/KFEQNGMX.js";
5
- import { createComponent as o, insert as s, mergeProps as c, spread as l, template as u } from "solid-js/web";
6
- import { For as d, Show as f, createMemo as p, splitProps as m } from "solid-js";
5
+ import { fieldErrorMessages as o } from "../primitives/fieldErrors.js";
6
+ import { createComponent as s, insert as c, mergeProps as l, spread as u, template as d } from "solid-js/web";
7
+ import { For as f, Show as p, createMemo as m, splitProps as h } from "solid-js";
7
8
  //#region src/components/Field.tsx
8
- var h = /*#__PURE__*/ u("<div data-slot=field-group>"), g = /*#__PURE__*/ u("<div data-slot=field-content>"), _ = /*#__PURE__*/ u("<div data-slot=field-label>"), v = /*#__PURE__*/ u("<span class=\"px-2 relative mx-auto block w-fit bg-background text-muted-foreground\"data-slot=field-separator-content>"), y = /*#__PURE__*/ u("<div data-slot=field-separator>"), b = /*#__PURE__*/ u("<div class=\"mt-[3px] flex min-h-[0.875rem] flex-col justify-start\">"), x = /*#__PURE__*/ u("<ul class=\"ml-4 gap-1 flex list-disc flex-col\">"), S = /*#__PURE__*/ u("<li>"), C = a.Context, w = (t) => {
9
- let [n, i] = m(t, ["class", "children"]);
10
- return o(r.Root, c({
9
+ var g = /*#__PURE__*/ d("<div data-slot=field-group>"), _ = /*#__PURE__*/ d("<div data-slot=field-content>"), v = /*#__PURE__*/ d("<div data-slot=field-label>"), y = /*#__PURE__*/ d("<span class=\"px-2 relative mx-auto block w-fit bg-background text-muted-foreground\"data-slot=field-separator-content>"), b = /*#__PURE__*/ d("<div data-slot=field-separator>"), x = /*#__PURE__*/ d("<div class=\"mt-[3px] flex min-h-[0.875rem] flex-col justify-start\">"), S = /*#__PURE__*/ d("<ul class=\"ml-4 gap-1 flex list-disc flex-col\">"), C = /*#__PURE__*/ d("<li>"), w = a.Context, T = (t) => {
10
+ let [n, i] = h(t, ["class", "children"]);
11
+ return s(r.Root, l({
11
12
  "data-slot": "field-set",
12
13
  get class() {
13
14
  return e("gap-4 has-data-[slot=checkbox-group]:gap-3 has-data-[slot=radio-group]:gap-3 flex flex-col", n.class);
@@ -15,13 +16,13 @@ var h = /*#__PURE__*/ u("<div data-slot=field-group>"), g = /*#__PURE__*/ u("<di
15
16
  }, i, { get children() {
16
17
  return n.children;
17
18
  } }));
18
- }, T = (t) => {
19
- let [n, i] = m(t, [
19
+ }, E = (t) => {
20
+ let [n, i] = h(t, [
20
21
  "class",
21
22
  "variant",
22
23
  "children"
23
24
  ]);
24
- return o(r.Legend, c({
25
+ return s(r.Legend, l({
25
26
  "data-slot": "field-legend",
26
27
  get "data-variant"() {
27
28
  return n.variant ?? "legend";
@@ -32,15 +33,15 @@ var h = /*#__PURE__*/ u("<div data-slot=field-group>"), g = /*#__PURE__*/ u("<di
32
33
  }, i, { get children() {
33
34
  return n.children;
34
35
  } }));
35
- }, E = (t) => {
36
- let [n, r] = m(t, ["class"]);
36
+ }, D = (t) => {
37
+ let [n, r] = h(t, ["class"]);
37
38
  return (() => {
38
- var t = h();
39
- return l(t, c({ get class() {
39
+ var t = g();
40
+ return u(t, l({ get class() {
40
41
  return e("gap-5 data-[slot=checkbox-group]:gap-3 *:data-[slot=field-group]:gap-4 group/field-group @container/field-group flex w-full flex-col", n.class);
41
42
  } }, r), !1, !1), t;
42
43
  })();
43
- }, D = t({
44
+ }, O = t({
44
45
  base: "group/field flex w-full transition-colors data-[invalid=true]:text-destructive",
45
46
  variants: { orientation: {
46
47
  vertical: "flex-col [&>*]:w-full [&>.sr-only]:w-auto",
@@ -48,20 +49,20 @@ var h = /*#__PURE__*/ u("<div data-slot=field-group>"), g = /*#__PURE__*/ u("<di
48
49
  responsive: "@md/field-group:gap-4 @md/field-group:flex-row @md/field-group:items-center @md/field-group:[&>*]:w-auto @md/field-group:[&>[data-slot=field-label]]:flex-auto @md/field-group:has-data-[slot=field-content]:items-start @md/field-group:has-data-[slot=field-content]:[&>[role=checkbox],[role=radio]]:mt-px flex-col [&>*]:w-full [&>.sr-only]:w-auto"
49
50
  } },
50
51
  defaultVariants: { orientation: "vertical" }
51
- }), O = (e) => {
52
- let [t, n] = m(e, [
52
+ }), k = (e) => {
53
+ let [t, n] = h(e, [
53
54
  "class",
54
55
  "orientation",
55
56
  "children"
56
57
  ]);
57
- return o(a.Root, c({
58
+ return s(a.Root, l({
58
59
  role: "group",
59
60
  "data-slot": "field",
60
61
  get "data-orientation"() {
61
62
  return t.orientation ?? "vertical";
62
63
  },
63
64
  get class() {
64
- return D({
65
+ return O({
65
66
  orientation: t.orientation,
66
67
  class: t.class
67
68
  });
@@ -69,45 +70,45 @@ var h = /*#__PURE__*/ u("<div data-slot=field-group>"), g = /*#__PURE__*/ u("<di
69
70
  }, n, { get children() {
70
71
  return t.children;
71
72
  } }));
72
- }, k = (t) => {
73
- let [n, r] = m(t, ["class"]);
73
+ }, A = (t) => {
74
+ let [n, r] = h(t, ["class"]);
74
75
  return (() => {
75
- var t = g();
76
- return l(t, c({ get class() {
76
+ var t = _();
77
+ return u(t, l({ get class() {
77
78
  return e("group/field-content leading-snug relative flex flex-1 flex-col", n.class);
78
79
  } }, r), !1, !1), t;
79
80
  })();
80
- }, A = (t) => {
81
- let [n, r] = m(t, ["class"]);
82
- return o(a.Input, c({
81
+ }, j = (t) => {
82
+ let [n, r] = h(t, ["class"]);
83
+ return s(a.Input, l({
83
84
  "data-slot": "field-input",
84
85
  get class() {
85
86
  return e("min-w-0 text-base md:text-sm h-8 px-2.5 py-1 flex w-full rounded-lg border border-input bg-transparent transition-colors outline-none placeholder:text-muted-foreground focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 disabled:pointer-events-none disabled:cursor-not-allowed disabled:bg-input/50 disabled:opacity-50 data-[invalid=true]:border-destructive data-[invalid=true]:ring-[3px] data-[invalid=true]:ring-destructive/20 data-[readonly=true]:cursor-default data-[readonly=true]:focus-visible:border-input data-[readonly=true]:focus-visible:ring-0 dark:bg-input/30 dark:disabled:bg-input/80 dark:data-[invalid=true]:border-destructive/50 dark:data-[invalid=true]:ring-destructive/40", n.class);
86
87
  }
87
88
  }, r));
88
- }, j = (t) => {
89
- let [n, r] = m(t, ["class"]);
90
- return o(a.Textarea, c({
89
+ }, M = (t) => {
90
+ let [n, r] = h(t, ["class"]);
91
+ return s(a.Textarea, l({
91
92
  "data-slot": "field-textarea",
92
93
  get class() {
93
94
  return e("min-w-0 text-base md:text-sm px-2.5 py-2 flex min-h-[80px] w-full rounded-lg border border-input bg-transparent transition-colors outline-none placeholder:text-muted-foreground focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 disabled:pointer-events-none disabled:cursor-not-allowed disabled:bg-input/50 disabled:opacity-50 data-[invalid=true]:border-destructive data-[invalid=true]:ring-[3px] data-[invalid=true]:ring-destructive/20 data-[readonly=true]:cursor-default data-[readonly=true]:focus-visible:border-input data-[readonly=true]:focus-visible:ring-0 dark:bg-input/30 dark:disabled:bg-input/80 dark:data-[invalid=true]:border-destructive/50 dark:data-[invalid=true]:ring-destructive/40", n.class);
94
95
  }
95
96
  }, r));
96
- }, M = (t) => {
97
- let [n, r] = m(t, ["class"]);
98
- return o(a.Select, c({
97
+ }, N = (t) => {
98
+ let [n, r] = h(t, ["class"]);
99
+ return s(a.Select, l({
99
100
  "data-slot": "field-select",
100
101
  get class() {
101
102
  return e("min-w-0 text-base md:text-sm h-8 px-2.5 py-1 flex w-full rounded-lg border border-input bg-transparent transition-colors outline-none placeholder:text-muted-foreground focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 disabled:pointer-events-none disabled:cursor-not-allowed disabled:bg-input/50 disabled:opacity-50 data-[invalid=true]:border-destructive data-[invalid=true]:ring-[3px] data-[invalid=true]:ring-destructive/20 data-[readonly=true]:cursor-default data-[readonly=true]:focus-visible:border-input data-[readonly=true]:focus-visible:ring-0 dark:bg-input/30 dark:disabled:bg-input/80 dark:data-[invalid=true]:border-destructive/50 dark:data-[invalid=true]:ring-destructive/40", n.class);
102
103
  }
103
104
  }, r));
104
- }, N = (t) => {
105
- let [n, r] = m(t, [
105
+ }, P = (t) => {
106
+ let [n, r] = h(t, [
106
107
  "class",
107
108
  "fallback",
108
109
  "children"
109
110
  ]);
110
- return o(a.RequiredIndicator, c({
111
+ return s(a.RequiredIndicator, l({
111
112
  get fallback() {
112
113
  return n.fallback ?? "*";
113
114
  },
@@ -117,9 +118,9 @@ var h = /*#__PURE__*/ u("<div data-slot=field-group>"), g = /*#__PURE__*/ u("<di
117
118
  }, r, { get children() {
118
119
  return n.children;
119
120
  } }));
120
- }, P = (t) => {
121
- let [n, r] = m(t, ["class", "children"]);
122
- return o(a.Label, c({
121
+ }, F = (t) => {
122
+ let [n, r] = h(t, ["class", "children"]);
123
+ return s(a.Label, l({
123
124
  "data-slot": "field-label",
124
125
  get class() {
125
126
  return e("group-data-[orientation=vertical]/field:mb-1.5", "gap-2 text-sm font-medium flex items-center leading-none select-none group-data-disabled:pointer-events-none group-data-[disabled=true]:opacity-50 peer-disabled:cursor-not-allowed peer-disabled:opacity-50", "*:data-[slot=field]:p-2.5 group/field-label peer/field-label leading-snug flex w-fit group-data-disabled/field:opacity-50 has-data-[slot=field]:rounded-lg has-data-[slot=field]:border has-[[data-state=checked]]:border-primary/30 has-[[data-state=checked]]:bg-primary/5 dark:has-[[data-state=checked]]:border-primary/20 dark:has-[[data-state=checked]]:bg-primary/10", "has-data-[slot=field]:w-full has-data-[slot=field]:flex-col", n.class);
@@ -127,17 +128,17 @@ var h = /*#__PURE__*/ u("<div data-slot=field-group>"), g = /*#__PURE__*/ u("<di
127
128
  }, r, { get children() {
128
129
  return n.children;
129
130
  } }));
130
- }, F = (t) => {
131
- let [n, r] = m(t, ["class", "children"]);
131
+ }, I = (t) => {
132
+ let [n, r] = h(t, ["class", "children"]);
132
133
  return (() => {
133
- var t = _();
134
- return l(t, c({ get class() {
134
+ var t = v();
135
+ return u(t, l({ get class() {
135
136
  return e("group-data-[orientation=vertical]/field:mb-1.5", "gap-2 text-sm font-medium leading-snug flex w-fit items-center group-data-disabled/field:opacity-50", n.class);
136
- } }, r), !1, !0), s(t, () => n.children), t;
137
+ } }, r), !1, !0), c(t, () => n.children), t;
137
138
  })();
138
- }, I = (t) => {
139
- let [n, r] = m(t, ["class", "children"]);
140
- return o(a.HelperText, c({
139
+ }, L = (t) => {
140
+ let [n, r] = h(t, ["class", "children"]);
141
+ return s(a.HelperText, l({
141
142
  "data-slot": "field-description",
142
143
  get class() {
143
144
  return e("text-sm [[data-variant=legend]+&]:-mt-1.5 leading-normal font-normal text-left text-muted-foreground group-has-data-[orientation=horizontal]/field:text-balance", "[&>a]:underline [&>a]:underline-offset-4 [&>a:hover]:text-primary", n.class);
@@ -145,58 +146,52 @@ var h = /*#__PURE__*/ u("<div data-slot=field-group>"), g = /*#__PURE__*/ u("<di
145
146
  }, r, { get children() {
146
147
  return n.children;
147
148
  } }));
148
- }, L = (t) => {
149
- let [r, i] = m(t, ["children", "class"]);
149
+ }, R = (t) => {
150
+ let [r, i] = h(t, ["children", "class"]);
150
151
  return (() => {
151
- var t = y();
152
- return l(t, c({
152
+ var t = b();
153
+ return u(t, l({
153
154
  get "data-content"() {
154
155
  return !!r.children;
155
156
  },
156
157
  get class() {
157
158
  return e("-my-2 h-5 text-sm group-data-[variant=outline]/field-group:-mb-2 relative", r.class);
158
159
  }
159
- }, i), !1, !0), s(t, o(n, { class: "inset-0 absolute top-1/2" }), null), s(t, o(f, {
160
+ }, i), !1, !0), c(t, s(n, { class: "inset-0 absolute top-1/2" }), null), c(t, s(p, {
160
161
  get when() {
161
162
  return r.children;
162
163
  },
163
164
  get children() {
164
- var e = v();
165
- return s(e, () => r.children), e;
165
+ var e = y();
166
+ return c(e, () => r.children), e;
166
167
  }
167
168
  }), null), t;
168
169
  })();
169
- }, R = (t) => {
170
- let [n, r] = m(t, [
170
+ }, z = (t) => {
171
+ let [n, r] = h(t, [
171
172
  "class",
172
173
  "children",
173
174
  "errors"
174
- ]), i = p(() => {
175
- let { errors: e } = n;
176
- if (!e || e.length === 0) return [];
177
- let t = [];
178
- for (let n of e) typeof n == "string" ? t.push(n) : n && typeof n == "object" && typeof n.message == "string" && t.push(n.message);
179
- return [...new Set(t)];
180
- });
175
+ ]), i = m(() => o(n.errors));
181
176
  return (() => {
182
- var t = b();
183
- return s(t, o(a.ErrorText, c({
177
+ var t = x();
178
+ return c(t, s(a.ErrorText, l({
184
179
  "data-slot": "field-error",
185
180
  get class() {
186
181
  return e("font-medium text-[0.8rem] leading-[0.875rem] text-destructive", n.class);
187
182
  }
188
183
  }, r, { get children() {
189
- return o(f, {
184
+ return s(p, {
190
185
  get when() {
191
186
  return n.children;
192
187
  },
193
188
  get fallback() {
194
- return o(f, {
189
+ return s(p, {
195
190
  get when() {
196
191
  return i().length > 0;
197
192
  },
198
193
  get children() {
199
- return o(f, {
194
+ return s(p, {
200
195
  get when() {
201
196
  return i().length > 1;
202
197
  },
@@ -204,14 +199,14 @@ var h = /*#__PURE__*/ u("<div data-slot=field-group>"), g = /*#__PURE__*/ u("<di
204
199
  return i().at(0);
205
200
  },
206
201
  get children() {
207
- var e = x();
208
- return s(e, o(d, {
202
+ var e = S();
203
+ return c(e, s(f, {
209
204
  get each() {
210
205
  return i();
211
206
  },
212
207
  children: (e) => (() => {
213
- var t = S();
214
- return s(t, e), t;
208
+ var t = C();
209
+ return c(t, e), t;
215
210
  })()
216
211
  })), e;
217
212
  }
@@ -227,6 +222,6 @@ var h = /*#__PURE__*/ u("<div data-slot=field-group>"), g = /*#__PURE__*/ u("<di
227
222
  })();
228
223
  };
229
224
  //#endregion
230
- export { O as Field, k as FieldContent, C as FieldContext, I as FieldDescription, R as FieldError, E as FieldGroup, A as FieldInput, P as FieldLabel, T as FieldLegend, N as FieldRequiredIndicator, M as FieldSelect, L as FieldSeparator, j as FieldTextarea, F as FieldTitle, w as Fieldset, D as fieldVariants, i as useFieldset };
225
+ export { k as Field, A as FieldContent, w as FieldContext, L as FieldDescription, z as FieldError, D as FieldGroup, j as FieldInput, F as FieldLabel, E as FieldLegend, P as FieldRequiredIndicator, N as FieldSelect, R as FieldSeparator, M as FieldTextarea, I as FieldTitle, T as Fieldset, O as fieldVariants, i as useFieldset };
231
226
 
232
227
  //# sourceMappingURL=Field.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"Field.js","names":["Field","PrimitiveField","Fieldset","PrimitiveFieldset","Component","ComponentProps","createMemo","For","JSXElement","Show","splitProps","VariantProps","tv","cn","Separator","useFieldset","FieldContext","Context","RootProps","props","local","others","_$createComponent","Root","_$mergeProps","class","children","FieldLegendProps","LegendProps","variant","FieldLegend","Legend","data-variant","FieldGroup","_el$","_tmpl$","_$spread","fieldVariants","base","variants","orientation","vertical","horizontal","responsive","defaultVariants","FieldProps","role","data-orientation","FieldContent","_el$2","_tmpl$2","FieldInput","InputProps","Input","FieldTextarea","TextareaProps","Textarea","FieldSelect","SelectProps","Select","FieldRequiredIndicator","RequiredIndicatorProps","RequiredIndicator","fallback","FieldLabel","LabelProps","Label","FieldTitle","_el$3","_tmpl$3","_$insert","FieldDescription","HelperTextProps","HelperText","FieldSeparatorProps","FieldSeparator","_el$4","_tmpl$5","data-content","Boolean","when","_el$5","_tmpl$4","FieldErrorProps","ErrorTextProps","errors","message","FieldError","uniqueErrors","length","messages","error","push","Set","_el$6","_tmpl$6","ErrorText","at","_el$7","_tmpl$7","each","_el$8","_tmpl$8"],"sources":["../../src/components/Field.tsx"],"sourcesContent":["import { Field as PrimitiveField } from '@ark-ui/solid/field';\nimport { Fieldset as PrimitiveFieldset } from '@ark-ui/solid/fieldset';\nimport {\n type Component,\n type ComponentProps,\n createMemo,\n For,\n type JSXElement,\n Show,\n splitProps,\n} from 'solid-js';\nimport { type VariantProps, tv, cn } from 'tailwind-variants';\n\nimport { Separator } from '@/components/Separator';\n\nexport { useFieldset } from '@ark-ui/solid/fieldset';\nexport const FieldContext = PrimitiveField.Context;\n\nexport const Fieldset: Component<PrimitiveFieldset.RootProps> = (props) => {\n const [local, others] = splitProps(props, ['class', 'children']);\n return (\n <PrimitiveFieldset.Root\n data-slot='field-set'\n class={cn(\n 'gap-4 has-data-[slot=checkbox-group]:gap-3 has-data-[slot=radio-group]:gap-3 flex flex-col',\n local.class,\n )}\n {...others}\n >\n {local.children}\n </PrimitiveFieldset.Root>\n );\n};\n\nexport type FieldLegendProps = PrimitiveFieldset.LegendProps & {\n variant?: 'legend' | 'label';\n};\n\nexport const FieldLegend: Component<FieldLegendProps> = (props) => {\n const [local, others] = splitProps(props, ['class', 'variant', 'children']);\n return (\n <PrimitiveFieldset.Legend\n data-slot='field-legend'\n data-variant={local.variant ?? 'legend'}\n class={cn(\n 'mb-1.5 font-medium data-[variant=label]:text-sm data-[variant=legend]:text-base',\n local.class,\n )}\n {...others}\n >\n {local.children}\n </PrimitiveFieldset.Legend>\n );\n};\n\nexport const FieldGroup: Component<ComponentProps<'div'>> = (props) => {\n const [local, others] = splitProps(props, ['class']);\n return (\n <div\n data-slot='field-group'\n class={cn(\n 'gap-5 data-[slot=checkbox-group]:gap-3 *:data-[slot=field-group]:gap-4 group/field-group @container/field-group flex w-full flex-col',\n local.class,\n )}\n {...others}\n />\n );\n};\n\nexport const fieldVariants = tv({\n base: 'group/field flex w-full transition-colors data-[invalid=true]:text-destructive',\n variants: {\n orientation: {\n vertical: 'flex-col [&>*]:w-full [&>.sr-only]:w-auto',\n horizontal:\n 'gap-4 flex-row items-center has-data-[slot=field-content]:items-start [&>[data-slot=field-label]]:flex-auto has-data-[slot=field-content]:[&>[role=checkbox],[role=radio]]:mt-px',\n responsive:\n '@md/field-group:gap-4 @md/field-group:flex-row @md/field-group:items-center @md/field-group:[&>*]:w-auto @md/field-group:[&>[data-slot=field-label]]:flex-auto @md/field-group:has-data-[slot=field-content]:items-start @md/field-group:has-data-[slot=field-content]:[&>[role=checkbox],[role=radio]]:mt-px flex-col [&>*]:w-full [&>.sr-only]:w-auto',\n },\n },\n defaultVariants: {\n orientation: 'vertical',\n },\n});\n\nexport type FieldProps = PrimitiveField.RootProps & VariantProps<typeof fieldVariants>;\n\nexport const Field: Component<FieldProps> = (props) => {\n const [local, others] = splitProps(props, ['class', 'orientation', 'children']);\n return (\n <PrimitiveField.Root\n role='group'\n data-slot='field'\n data-orientation={local.orientation ?? 'vertical'}\n class={fieldVariants({ orientation: local.orientation, class: local.class })}\n {...others}\n >\n {local.children}\n </PrimitiveField.Root>\n );\n};\n\nexport const FieldContent: Component<ComponentProps<'div'>> = (props) => {\n const [local, others] = splitProps(props, ['class']);\n return (\n <div\n data-slot='field-content'\n class={cn('group/field-content leading-snug relative flex flex-1 flex-col', local.class)}\n {...others}\n />\n );\n};\nexport const FieldInput: Component<PrimitiveField.InputProps> = (props) => {\n const [local, others] = splitProps(props, ['class']);\n return (\n <PrimitiveField.Input\n data-slot='field-input'\n class={cn(\n 'min-w-0 text-base md:text-sm h-8 px-2.5 py-1 flex w-full rounded-lg border border-input bg-transparent transition-colors outline-none placeholder:text-muted-foreground focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 disabled:pointer-events-none disabled:cursor-not-allowed disabled:bg-input/50 disabled:opacity-50 data-[invalid=true]:border-destructive data-[invalid=true]:ring-[3px] data-[invalid=true]:ring-destructive/20 data-[readonly=true]:cursor-default data-[readonly=true]:focus-visible:border-input data-[readonly=true]:focus-visible:ring-0 dark:bg-input/30 dark:disabled:bg-input/80 dark:data-[invalid=true]:border-destructive/50 dark:data-[invalid=true]:ring-destructive/40',\n local.class,\n )}\n {...others}\n />\n );\n};\n\nexport const FieldTextarea: Component<PrimitiveField.TextareaProps> = (props) => {\n const [local, others] = splitProps(props, ['class']);\n return (\n <PrimitiveField.Textarea\n data-slot='field-textarea'\n class={cn(\n 'min-w-0 text-base md:text-sm px-2.5 py-2 flex min-h-[80px] w-full rounded-lg border border-input bg-transparent transition-colors outline-none placeholder:text-muted-foreground focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 disabled:pointer-events-none disabled:cursor-not-allowed disabled:bg-input/50 disabled:opacity-50 data-[invalid=true]:border-destructive data-[invalid=true]:ring-[3px] data-[invalid=true]:ring-destructive/20 data-[readonly=true]:cursor-default data-[readonly=true]:focus-visible:border-input data-[readonly=true]:focus-visible:ring-0 dark:bg-input/30 dark:disabled:bg-input/80 dark:data-[invalid=true]:border-destructive/50 dark:data-[invalid=true]:ring-destructive/40',\n local.class,\n )}\n {...others}\n />\n );\n};\n\nexport const FieldSelect: Component<PrimitiveField.SelectProps> = (props) => {\n const [local, others] = splitProps(props, ['class']);\n return (\n <PrimitiveField.Select\n data-slot='field-select'\n class={cn(\n 'min-w-0 text-base md:text-sm h-8 px-2.5 py-1 flex w-full rounded-lg border border-input bg-transparent transition-colors outline-none placeholder:text-muted-foreground focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 disabled:pointer-events-none disabled:cursor-not-allowed disabled:bg-input/50 disabled:opacity-50 data-[invalid=true]:border-destructive data-[invalid=true]:ring-[3px] data-[invalid=true]:ring-destructive/20 data-[readonly=true]:cursor-default data-[readonly=true]:focus-visible:border-input data-[readonly=true]:focus-visible:ring-0 dark:bg-input/30 dark:disabled:bg-input/80 dark:data-[invalid=true]:border-destructive/50 dark:data-[invalid=true]:ring-destructive/40',\n local.class,\n )}\n {...others}\n />\n );\n};\n\nexport const FieldRequiredIndicator: Component<PrimitiveField.RequiredIndicatorProps> = (props) => {\n const [local, others] = splitProps(props, ['class', 'fallback', 'children']);\n return (\n <PrimitiveField.RequiredIndicator\n fallback={local.fallback ?? '*'}\n class={cn('text-sm font-medium leading-none text-destructive', local.class)}\n {...others}\n >\n {local.children}\n </PrimitiveField.RequiredIndicator>\n );\n};\n\nexport const FieldLabel: Component<PrimitiveField.LabelProps> = (props) => {\n const [local, others] = splitProps(props, ['class', 'children']);\n return (\n <PrimitiveField.Label\n data-slot='field-label'\n class={cn(\n 'group-data-[orientation=vertical]/field:mb-1.5',\n 'gap-2 text-sm font-medium flex items-center leading-none select-none group-data-disabled:pointer-events-none group-data-[disabled=true]:opacity-50 peer-disabled:cursor-not-allowed peer-disabled:opacity-50',\n '*:data-[slot=field]:p-2.5 group/field-label peer/field-label leading-snug flex w-fit group-data-disabled/field:opacity-50 has-data-[slot=field]:rounded-lg has-data-[slot=field]:border has-[[data-state=checked]]:border-primary/30 has-[[data-state=checked]]:bg-primary/5 dark:has-[[data-state=checked]]:border-primary/20 dark:has-[[data-state=checked]]:bg-primary/10',\n 'has-data-[slot=field]:w-full has-data-[slot=field]:flex-col',\n local.class,\n )}\n {...others}\n >\n {local.children}\n </PrimitiveField.Label>\n );\n};\n\nexport const FieldTitle: Component<ComponentProps<'div'>> = (props) => {\n const [local, others] = splitProps(props, ['class', 'children']);\n return (\n <div\n data-slot='field-label'\n class={cn(\n 'group-data-[orientation=vertical]/field:mb-1.5',\n 'gap-2 text-sm font-medium leading-snug flex w-fit items-center group-data-disabled/field:opacity-50',\n local.class,\n )}\n {...others}\n >\n {local.children}\n </div>\n );\n};\n\nexport const FieldDescription: Component<PrimitiveField.HelperTextProps> = (props) => {\n const [local, others] = splitProps(props, ['class', 'children']);\n return (\n <PrimitiveField.HelperText\n data-slot='field-description'\n class={cn(\n 'text-sm [[data-variant=legend]+&]:-mt-1.5 leading-normal font-normal text-left text-muted-foreground group-has-data-[orientation=horizontal]/field:text-balance',\n '[&>a]:underline [&>a]:underline-offset-4 [&>a:hover]:text-primary',\n local.class,\n )}\n {...others}\n >\n {local.children}\n </PrimitiveField.HelperText>\n );\n};\n\nexport type FieldSeparatorProps = ComponentProps<'div'> & {\n children?: JSXElement;\n};\n\nexport const FieldSeparator: Component<FieldSeparatorProps> = (props) => {\n const [local, others] = splitProps(props, ['children', 'class']);\n return (\n <div\n data-slot='field-separator'\n data-content={Boolean(local.children)}\n class={cn(\n '-my-2 h-5 text-sm group-data-[variant=outline]/field-group:-mb-2 relative',\n local.class,\n )}\n {...others}\n >\n <Separator class='inset-0 absolute top-1/2' />\n <Show when={local.children}>\n <span\n class='px-2 relative mx-auto block w-fit bg-background text-muted-foreground'\n data-slot='field-separator-content'\n >\n {local.children}\n </span>\n </Show>\n </div>\n );\n};\n\nexport type FieldErrorProps = PrimitiveField.ErrorTextProps & {\n errors?: ({ message?: string } | string | undefined)[];\n};\n\nexport const FieldError: Component<FieldErrorProps> = (props) => {\n const [local, others] = splitProps(props, ['class', 'children', 'errors']);\n\n const uniqueErrors = createMemo(() => {\n const { errors } = local;\n if (!errors || errors.length === 0) {\n return [];\n }\n\n const messages: string[] = [];\n for (const error of errors) {\n if (typeof error === 'string') {\n messages.push(error);\n } else if (error && typeof error === 'object' && typeof error.message === 'string') {\n messages.push(error.message);\n }\n }\n\n return [...new Set(messages)];\n });\n\n return (\n <div class='mt-[3px] flex min-h-[0.875rem] flex-col justify-start'>\n <PrimitiveField.ErrorText\n data-slot='field-error'\n class={cn('font-medium text-[0.8rem] leading-[0.875rem] text-destructive', local.class)}\n {...others}\n >\n <Show\n when={local.children}\n fallback={\n <Show when={uniqueErrors().length > 0}>\n <Show when={uniqueErrors().length > 1} fallback={uniqueErrors().at(0)}>\n <ul class='ml-4 gap-1 flex list-disc flex-col'>\n <For each={uniqueErrors()}>{(error) => <li>{error}</li>}</For>\n </ul>\n </Show>\n </Show>\n }\n >\n {local.children}\n </Show>\n </PrimitiveField.ErrorText>\n </div>\n );\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"Field.js","names":["Field","PrimitiveField","Fieldset","PrimitiveFieldset","Component","ComponentProps","createMemo","For","JSXElement","Show","splitProps","VariantProps","tv","cn","Separator","fieldErrorMessages","useFieldset","FieldContext","Context","RootProps","props","local","others","_$createComponent","Root","_$mergeProps","class","children","FieldLegendProps","LegendProps","variant","FieldLegend","Legend","data-variant","FieldGroup","_el$","_tmpl$","_$spread","fieldVariants","base","variants","orientation","vertical","horizontal","responsive","defaultVariants","FieldProps","role","data-orientation","FieldContent","_el$2","_tmpl$2","FieldInput","InputProps","Input","FieldTextarea","TextareaProps","Textarea","FieldSelect","SelectProps","Select","FieldRequiredIndicator","RequiredIndicatorProps","RequiredIndicator","fallback","FieldLabel","LabelProps","Label","FieldTitle","_el$3","_tmpl$3","_$insert","FieldDescription","HelperTextProps","HelperText","FieldSeparatorProps","FieldSeparator","_el$4","_tmpl$5","data-content","Boolean","when","_el$5","_tmpl$4","FieldErrorProps","ErrorTextProps","errors","FieldError","uniqueErrors","_el$6","_tmpl$6","ErrorText","length","at","_el$7","_tmpl$7","each","error","_el$8","_tmpl$8"],"sources":["../../src/components/Field.tsx"],"sourcesContent":["import { Field as PrimitiveField } from '@ark-ui/solid/field';\nimport { Fieldset as PrimitiveFieldset } from '@ark-ui/solid/fieldset';\nimport {\n type Component,\n type ComponentProps,\n createMemo,\n For,\n type JSXElement,\n Show,\n splitProps,\n} from 'solid-js';\nimport { type VariantProps, tv, cn } from 'tailwind-variants';\n\nimport { Separator } from '@/components/Separator';\nimport { fieldErrorMessages } from '@/primitives/fieldErrors';\n\nexport { useFieldset } from '@ark-ui/solid/fieldset';\nexport const FieldContext = PrimitiveField.Context;\n\nexport const Fieldset: Component<PrimitiveFieldset.RootProps> = (props) => {\n const [local, others] = splitProps(props, ['class', 'children']);\n return (\n <PrimitiveFieldset.Root\n data-slot='field-set'\n class={cn(\n 'gap-4 has-data-[slot=checkbox-group]:gap-3 has-data-[slot=radio-group]:gap-3 flex flex-col',\n local.class,\n )}\n {...others}\n >\n {local.children}\n </PrimitiveFieldset.Root>\n );\n};\n\nexport type FieldLegendProps = PrimitiveFieldset.LegendProps & {\n variant?: 'legend' | 'label';\n};\n\nexport const FieldLegend: Component<FieldLegendProps> = (props) => {\n const [local, others] = splitProps(props, ['class', 'variant', 'children']);\n return (\n <PrimitiveFieldset.Legend\n data-slot='field-legend'\n data-variant={local.variant ?? 'legend'}\n class={cn(\n 'mb-1.5 font-medium data-[variant=label]:text-sm data-[variant=legend]:text-base',\n local.class,\n )}\n {...others}\n >\n {local.children}\n </PrimitiveFieldset.Legend>\n );\n};\n\nexport const FieldGroup: Component<ComponentProps<'div'>> = (props) => {\n const [local, others] = splitProps(props, ['class']);\n return (\n <div\n data-slot='field-group'\n class={cn(\n 'gap-5 data-[slot=checkbox-group]:gap-3 *:data-[slot=field-group]:gap-4 group/field-group @container/field-group flex w-full flex-col',\n local.class,\n )}\n {...others}\n />\n );\n};\n\nexport const fieldVariants = tv({\n base: 'group/field flex w-full transition-colors data-[invalid=true]:text-destructive',\n variants: {\n orientation: {\n vertical: 'flex-col [&>*]:w-full [&>.sr-only]:w-auto',\n horizontal:\n 'gap-4 flex-row items-center has-data-[slot=field-content]:items-start [&>[data-slot=field-label]]:flex-auto has-data-[slot=field-content]:[&>[role=checkbox],[role=radio]]:mt-px',\n responsive:\n '@md/field-group:gap-4 @md/field-group:flex-row @md/field-group:items-center @md/field-group:[&>*]:w-auto @md/field-group:[&>[data-slot=field-label]]:flex-auto @md/field-group:has-data-[slot=field-content]:items-start @md/field-group:has-data-[slot=field-content]:[&>[role=checkbox],[role=radio]]:mt-px flex-col [&>*]:w-full [&>.sr-only]:w-auto',\n },\n },\n defaultVariants: {\n orientation: 'vertical',\n },\n});\n\nexport type FieldProps = PrimitiveField.RootProps & VariantProps<typeof fieldVariants>;\n\nexport const Field: Component<FieldProps> = (props) => {\n const [local, others] = splitProps(props, ['class', 'orientation', 'children']);\n return (\n <PrimitiveField.Root\n role='group'\n data-slot='field'\n data-orientation={local.orientation ?? 'vertical'}\n class={fieldVariants({ orientation: local.orientation, class: local.class })}\n {...others}\n >\n {local.children}\n </PrimitiveField.Root>\n );\n};\n\nexport const FieldContent: Component<ComponentProps<'div'>> = (props) => {\n const [local, others] = splitProps(props, ['class']);\n return (\n <div\n data-slot='field-content'\n class={cn('group/field-content leading-snug relative flex flex-1 flex-col', local.class)}\n {...others}\n />\n );\n};\nexport const FieldInput: Component<PrimitiveField.InputProps> = (props) => {\n const [local, others] = splitProps(props, ['class']);\n return (\n <PrimitiveField.Input\n data-slot='field-input'\n class={cn(\n 'min-w-0 text-base md:text-sm h-8 px-2.5 py-1 flex w-full rounded-lg border border-input bg-transparent transition-colors outline-none placeholder:text-muted-foreground focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 disabled:pointer-events-none disabled:cursor-not-allowed disabled:bg-input/50 disabled:opacity-50 data-[invalid=true]:border-destructive data-[invalid=true]:ring-[3px] data-[invalid=true]:ring-destructive/20 data-[readonly=true]:cursor-default data-[readonly=true]:focus-visible:border-input data-[readonly=true]:focus-visible:ring-0 dark:bg-input/30 dark:disabled:bg-input/80 dark:data-[invalid=true]:border-destructive/50 dark:data-[invalid=true]:ring-destructive/40',\n local.class,\n )}\n {...others}\n />\n );\n};\n\nexport const FieldTextarea: Component<PrimitiveField.TextareaProps> = (props) => {\n const [local, others] = splitProps(props, ['class']);\n return (\n <PrimitiveField.Textarea\n data-slot='field-textarea'\n class={cn(\n 'min-w-0 text-base md:text-sm px-2.5 py-2 flex min-h-[80px] w-full rounded-lg border border-input bg-transparent transition-colors outline-none placeholder:text-muted-foreground focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 disabled:pointer-events-none disabled:cursor-not-allowed disabled:bg-input/50 disabled:opacity-50 data-[invalid=true]:border-destructive data-[invalid=true]:ring-[3px] data-[invalid=true]:ring-destructive/20 data-[readonly=true]:cursor-default data-[readonly=true]:focus-visible:border-input data-[readonly=true]:focus-visible:ring-0 dark:bg-input/30 dark:disabled:bg-input/80 dark:data-[invalid=true]:border-destructive/50 dark:data-[invalid=true]:ring-destructive/40',\n local.class,\n )}\n {...others}\n />\n );\n};\n\nexport const FieldSelect: Component<PrimitiveField.SelectProps> = (props) => {\n const [local, others] = splitProps(props, ['class']);\n return (\n <PrimitiveField.Select\n data-slot='field-select'\n class={cn(\n 'min-w-0 text-base md:text-sm h-8 px-2.5 py-1 flex w-full rounded-lg border border-input bg-transparent transition-colors outline-none placeholder:text-muted-foreground focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 disabled:pointer-events-none disabled:cursor-not-allowed disabled:bg-input/50 disabled:opacity-50 data-[invalid=true]:border-destructive data-[invalid=true]:ring-[3px] data-[invalid=true]:ring-destructive/20 data-[readonly=true]:cursor-default data-[readonly=true]:focus-visible:border-input data-[readonly=true]:focus-visible:ring-0 dark:bg-input/30 dark:disabled:bg-input/80 dark:data-[invalid=true]:border-destructive/50 dark:data-[invalid=true]:ring-destructive/40',\n local.class,\n )}\n {...others}\n />\n );\n};\n\nexport const FieldRequiredIndicator: Component<PrimitiveField.RequiredIndicatorProps> = (props) => {\n const [local, others] = splitProps(props, ['class', 'fallback', 'children']);\n return (\n <PrimitiveField.RequiredIndicator\n fallback={local.fallback ?? '*'}\n class={cn('text-sm font-medium leading-none text-destructive', local.class)}\n {...others}\n >\n {local.children}\n </PrimitiveField.RequiredIndicator>\n );\n};\n\nexport const FieldLabel: Component<PrimitiveField.LabelProps> = (props) => {\n const [local, others] = splitProps(props, ['class', 'children']);\n return (\n <PrimitiveField.Label\n data-slot='field-label'\n class={cn(\n 'group-data-[orientation=vertical]/field:mb-1.5',\n 'gap-2 text-sm font-medium flex items-center leading-none select-none group-data-disabled:pointer-events-none group-data-[disabled=true]:opacity-50 peer-disabled:cursor-not-allowed peer-disabled:opacity-50',\n '*:data-[slot=field]:p-2.5 group/field-label peer/field-label leading-snug flex w-fit group-data-disabled/field:opacity-50 has-data-[slot=field]:rounded-lg has-data-[slot=field]:border has-[[data-state=checked]]:border-primary/30 has-[[data-state=checked]]:bg-primary/5 dark:has-[[data-state=checked]]:border-primary/20 dark:has-[[data-state=checked]]:bg-primary/10',\n 'has-data-[slot=field]:w-full has-data-[slot=field]:flex-col',\n local.class,\n )}\n {...others}\n >\n {local.children}\n </PrimitiveField.Label>\n );\n};\n\nexport const FieldTitle: Component<ComponentProps<'div'>> = (props) => {\n const [local, others] = splitProps(props, ['class', 'children']);\n return (\n <div\n data-slot='field-label'\n class={cn(\n 'group-data-[orientation=vertical]/field:mb-1.5',\n 'gap-2 text-sm font-medium leading-snug flex w-fit items-center group-data-disabled/field:opacity-50',\n local.class,\n )}\n {...others}\n >\n {local.children}\n </div>\n );\n};\n\nexport const FieldDescription: Component<PrimitiveField.HelperTextProps> = (props) => {\n const [local, others] = splitProps(props, ['class', 'children']);\n return (\n <PrimitiveField.HelperText\n data-slot='field-description'\n class={cn(\n 'text-sm [[data-variant=legend]+&]:-mt-1.5 leading-normal font-normal text-left text-muted-foreground group-has-data-[orientation=horizontal]/field:text-balance',\n '[&>a]:underline [&>a]:underline-offset-4 [&>a:hover]:text-primary',\n local.class,\n )}\n {...others}\n >\n {local.children}\n </PrimitiveField.HelperText>\n );\n};\n\nexport type FieldSeparatorProps = ComponentProps<'div'> & {\n children?: JSXElement;\n};\n\nexport const FieldSeparator: Component<FieldSeparatorProps> = (props) => {\n const [local, others] = splitProps(props, ['children', 'class']);\n return (\n <div\n data-slot='field-separator'\n data-content={Boolean(local.children)}\n class={cn(\n '-my-2 h-5 text-sm group-data-[variant=outline]/field-group:-mb-2 relative',\n local.class,\n )}\n {...others}\n >\n <Separator class='inset-0 absolute top-1/2' />\n <Show when={local.children}>\n <span\n class='px-2 relative mx-auto block w-fit bg-background text-muted-foreground'\n data-slot='field-separator-content'\n >\n {local.children}\n </span>\n </Show>\n </div>\n );\n};\n\nexport type FieldErrorProps = PrimitiveField.ErrorTextProps & {\n /** Display strings or objects with a string message; ignore other validator values. */\n errors?: readonly unknown[];\n};\n\nexport const FieldError: Component<FieldErrorProps> = (props) => {\n const [local, others] = splitProps(props, ['class', 'children', 'errors']);\n\n const uniqueErrors = createMemo(() => fieldErrorMessages(local.errors));\n\n return (\n <div class='mt-[3px] flex min-h-[0.875rem] flex-col justify-start'>\n <PrimitiveField.ErrorText\n data-slot='field-error'\n class={cn('font-medium text-[0.8rem] leading-[0.875rem] text-destructive', local.class)}\n {...others}\n >\n <Show\n when={local.children}\n fallback={\n <Show when={uniqueErrors().length > 0}>\n <Show when={uniqueErrors().length > 1} fallback={uniqueErrors().at(0)}>\n <ul class='ml-4 gap-1 flex list-disc flex-col'>\n <For each={uniqueErrors()}>{(error) => <li>{error}</li>}</For>\n </ul>\n </Show>\n </Show>\n }\n >\n {local.children}\n </Show>\n </PrimitiveField.ErrorText>\n </div>\n );\n};\n"],"mappings":"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"}
@@ -78,7 +78,7 @@ function b(e) {
78
78
  return x(e);
79
79
  }
80
80
  function x(e) {
81
- let t = _(typeof e == "string" ? new URL(e, m()) : new URL(e)), n = t.pathname.split("/").filter(Boolean);
81
+ let t = _(typeof e == "string" ? new URL(e, m()) : new URL(e)), n = t.pathname.replace(/^\/+/, "").split("/");
82
82
  return n.length > 0 && h(n[0]) && (t.pathname = "/" + n.slice(1).join("/")), _(t);
83
83
  }
84
84
  var S, C;
@@ -1 +1 @@
1
- {"version":3,"file":"runtime.js","names":[],"sources":["../../src/paraglide/runtime.js"],"sourcesContent":["/* eslint-disable */\n\n/** @type {any} */\nconst URLPattern = {}\n\n/**\n * The project's base locale.\n *\n * @example\n * if (locale === baseLocale) {\n * // do something\n * }\n */\nexport const baseLocale = \"en-gb\";\n/**\n * The project's locales that have been specified in the settings.\n *\n * @example\n * if (locales.includes(userSelectedLocale) === false) {\n * throw new Error('Locale is not available');\n * }\n */\nexport const locales = /** @type {const} */ ([\"en-gb\",\"nb\"]);\n/** @type {string} */\nexport const cookieName = \"PARAGLIDE_LOCALE\";\n/** @type {number} */\nexport const cookieMaxAge = 34560000;\n/** @type {string} */\nexport const cookieDomain = \"\";\n/** @type {string} */\nexport const localStorageKey = \"PARAGLIDE_LOCALE\";\n/**\n * @type {Array<\"cookie\" | \"baseLocale\" | \"globalVariable\" | \"url\" | \"preferredLanguage\" | \"localStorage\" | `custom-${string}`>}\n */\nexport const strategy = [\n \"globalVariable\",\n \"baseLocale\"\n];\n/**\n * Route-level strategy overrides.\n *\n * `match` uses URLPattern syntax.\n *\n * @type {Array<{\n * match: string;\n * strategy?: Array<\"cookie\" | \"baseLocale\" | \"globalVariable\" | \"url\" | \"preferredLanguage\" | \"localStorage\" | `custom-${string}`>;\n * exclude?: boolean;\n * }>}\n */\nexport const routeStrategies = [];\n/**\n * The used URL patterns.\n *\n * @type {Array<{ pattern: string, localized: Array<[Locale, string]> }>}\n */\nexport const urlPatterns = [\n {\n \"pattern\": \":protocol://:domain(.*)::port?/:path(.*)?\",\n \"localized\": [\n [\n \"nb\",\n \":protocol://:domain(.*)::port?/nb/:path(.*)?\"\n ],\n [\n \"en-gb\",\n \":protocol://:domain(.*)::port?/:path(.*)?\"\n ]\n ]\n }\n];\n/**\n * Controls trailing slash canonicalization for localized URLs.\n *\n * @type {\"always\" | \"never\" | undefined}\n */\nexport const trailingSlash = undefined;\n/**\n * @typedef {{\n * \t\tgetStore(): {\n * \t\tlocale?: Locale,\n * \t\t\torigin?: string,\n * \t\t\tmessageCalls?: Set<string>\n * \t} | undefined,\n * \t\trun: (store: { locale?: Locale, origin?: string, messageCalls?: Set<string>},\n * cb: any) => any\n * }} ParaglideAsyncLocalStorage\n */\n/**\n * Server side async local storage that is set by `serverMiddleware()`.\n *\n * The variable is used to retrieve the locale and origin in a server-side\n * rendering context without effecting other requests.\n *\n * @type {ParaglideAsyncLocalStorage | undefined}\n */\nexport let serverAsyncLocalStorage = undefined;\n/**\n * Returns the current server-side async local storage instance.\n *\n * Accessing the mutable value through a function keeps it observable when\n * module interceptors wrap exported bindings and snapshot their initial value.\n *\n * @returns {ParaglideAsyncLocalStorage | undefined}\n */\nexport function getServerAsyncLocalStorage() {\n return serverAsyncLocalStorage;\n}\nexport const disableAsyncLocalStorage = false;\nexport const experimentalMiddlewareLocaleSplitting = false;\nexport const isServer = typeof window === 'undefined';\n/** @type {Locale | undefined} */\nexport const experimentalStaticLocale = undefined;\n/**\n * Sets the server side async local storage.\n *\n * The function is needed because the `runtime.js` file\n * must define the `serverAsyncLocalStorage` variable to\n * avoid a circular import between `runtime.js` and\n * `server.js` files.\n *\n * @param {ParaglideAsyncLocalStorage | undefined} value\n */\nexport function overwriteServerAsyncLocalStorage(value) {\n serverAsyncLocalStorage = value;\n}\nconst TREE_SHAKE_COOKIE_STRATEGY_USED = false;\nconst TREE_SHAKE_URL_STRATEGY_USED = false;\nconst TREE_SHAKE_GLOBAL_VARIABLE_STRATEGY_USED = true;\nconst TREE_SHAKE_PREFERRED_LANGUAGE_STRATEGY_USED = false;\nconst TREE_SHAKE_DEFAULT_URL_PATTERN_USED = true;\nconst TREE_SHAKE_LOCAL_STORAGE_STRATEGY_USED = false;\n\n/** @type {any} */ (globalThis).__paraglide =\n\t/** @type {any} */ (globalThis).__paraglide ?? {};\n/** @type {any} */ (globalThis).__paraglide.ssr =\n\t/** @type {any} */ (globalThis).__paraglide.ssr ?? {};\n\n/**\n * This is a fallback to get started with a custom\n * strategy and avoid type errors.\n *\n * The implementation is overwritten\n * by `overwriteGetLocale()` and `defineSetLocale()`.\n *\n * @type {Locale | undefined}\n */\nlet _locale;\nlet localeInitiallySet = false;\n/**\n * Get the current locale.\n *\n * The locale is resolved using your configured strategies (URL, cookie, localStorage, etc.)\n * in the order they are defined. In SSR contexts, the locale is retrieved from AsyncLocalStorage\n * which is set by the `paraglideMiddleware()`.\n *\n * @see https://paraglidejs.com/strategy - Configure locale detection strategies\n *\n * @example\n * if (getLocale() === 'de') {\n * console.log('Germany 🇩🇪');\n * } else if (getLocale() === 'nl') {\n * console.log('Netherlands 🇳🇱');\n * }\n *\n * @returns {Locale} The current locale.\n */\nexport let getLocale = () => {\n if (experimentalStaticLocale !== undefined) {\n return experimentalStaticLocale;\n }\n // if running in a server-side rendering context\n // retrieve the locale from the async local storage\n if (serverAsyncLocalStorage) {\n const locale = serverAsyncLocalStorage?.getStore()?.locale;\n if (locale) {\n return locale;\n }\n }\n let strategyToUse = strategy;\n if (!isServer && typeof window !== \"undefined\" && window.location?.href) {\n strategyToUse = getStrategyForUrl(window.location.href);\n }\n const resolved = resolveLocaleWithStrategies(strategyToUse, typeof window !== \"undefined\" ? window.location?.href : undefined);\n if (resolved) {\n if (!localeInitiallySet) {\n _locale = resolved;\n // https://github.com/opral/inlang-paraglide-js/issues/455\n localeInitiallySet = true;\n setLocale(resolved, { reload: false });\n }\n return resolved;\n }\n throw new Error(\"No locale found. Read the docs https://paraglidejs.com/errors#no-locale-found\");\n};\n/**\n * Resolve locale for a given URL using route-aware strategies.\n *\n * @param {string | URL} url\n * @returns {Locale}\n */\nexport function getLocaleForUrl(url) {\n if (experimentalStaticLocale !== undefined) {\n return experimentalStaticLocale;\n }\n const strategyToUse = getStrategyForUrl(url);\n const resolved = resolveLocaleWithStrategies(strategyToUse, typeof url === \"string\" ? url : url.href);\n if (resolved) {\n return resolved;\n }\n throw new Error(\"No locale found. Read the docs https://paraglidejs.com/errors#no-locale-found\");\n}\n/**\n * @param {typeof strategy} strategyToUse\n * @param {string | undefined} urlForUrlStrategy\n * @returns {Locale | undefined}\n */\nfunction resolveLocaleWithStrategies(strategyToUse, urlForUrlStrategy) {\n /** @type {string | undefined} */\n let locale;\n for (const strat of strategyToUse) {\n if (TREE_SHAKE_COOKIE_STRATEGY_USED && strat === \"cookie\") {\n locale = extractLocaleFromCookie();\n }\n else if (strat === \"baseLocale\") {\n locale = baseLocale;\n }\n else if (TREE_SHAKE_URL_STRATEGY_USED &&\n strat === \"url\" &&\n !isServer &&\n typeof urlForUrlStrategy === \"string\") {\n locale = extractLocaleFromUrl(urlForUrlStrategy);\n }\n else if (TREE_SHAKE_GLOBAL_VARIABLE_STRATEGY_USED &&\n strat === \"globalVariable\" &&\n _locale !== undefined) {\n locale = _locale;\n }\n else if (TREE_SHAKE_PREFERRED_LANGUAGE_STRATEGY_USED &&\n strat === \"preferredLanguage\" &&\n !isServer) {\n locale = extractLocaleFromNavigator();\n }\n else if (TREE_SHAKE_LOCAL_STORAGE_STRATEGY_USED &&\n strat === \"localStorage\" &&\n !isServer) {\n locale = localStorage.getItem(localStorageKey) ?? undefined;\n }\n else if (isCustomStrategy(strat) && customClientStrategies.has(strat)) {\n const handler = customClientStrategies.get(strat);\n if (handler) {\n const result = handler.getLocale();\n // Handle both sync and async results - skip async in sync getLocale\n if (result instanceof Promise) {\n // Can't await in sync function, skip async strategies\n continue;\n }\n if (result !== undefined) {\n return assertIsLocale(result);\n }\n }\n }\n const matchedLocale = toLocale(locale);\n if (matchedLocale) {\n return matchedLocale;\n }\n }\n return undefined;\n}\n/**\n * Overwrite the `getLocale()` function.\n *\n * Use this function to overwrite how the locale is resolved. This is useful\n * for custom locale resolution or advanced use cases like SSG with concurrent rendering.\n *\n * @see https://paraglidejs.com/strategy\n *\n * @example\n * overwriteGetLocale(() => {\n * return Cookies.get('locale') ?? baseLocale\n * });\n *\n * @param {() => Locale} fn - The new implementation for `getLocale()`.\n */\nexport const overwriteGetLocale = (fn) => {\n getLocale = fn;\n};\n\nconst rtlLanguages = new Set([\n \"ar\",\n \"dv\",\n \"fa\",\n \"he\",\n \"ks\",\n \"ku\",\n \"ps\",\n \"sd\",\n \"ug\",\n \"ur\",\n \"yi\",\n]);\n/**\n * Get writing direction for a locale.\n *\n * Uses `Intl.Locale` text info when available and falls back to a\n * language-based RTL check for runtimes without `getTextInfo()`.\n *\n * @example\n * getTextDirection(); // \"ltr\" or \"rtl\" for current locale\n * getTextDirection(\"ar\"); // \"rtl\"\n * getTextDirection(\"en\"); // \"ltr\"\n *\n * @param {string} [locale] - Target locale. If not provided, uses `getLocale()`\n * @returns {\"ltr\" | \"rtl\"}\n */\nexport function getTextDirection(locale = getLocale()) {\n try {\n const intlLocale = /** @type {Intl.Locale & {\n getTextInfo?: () => { direction?: string };\n textInfo?: { direction?: string };\n }} */ (new Intl.Locale(locale));\n const direction = intlLocale.getTextInfo?.().direction ?? intlLocale.textInfo?.direction;\n if (direction === \"ltr\" || direction === \"rtl\") {\n return direction;\n }\n }\n catch {\n // Ignore Intl.Locale parsing/runtime errors and use fallback below.\n }\n const language = locale.split(\"-\")[0]?.toLowerCase();\n return rtlLanguages.has(language ?? \"\") ? \"rtl\" : \"ltr\";\n}\n\n/**\n * Navigates to the localized URL, or reloads the current page\n *\n * @param {string} [newLocation] The new location\n */\nconst navigateOrReload = (newLocation) => {\n if (newLocation) {\n // reload the page by navigating to the new url\n window.location.href = newLocation;\n }\n else {\n // reload the page to reflect the new locale\n window.location.reload();\n }\n};\n/**\n * @typedef {(newLocale: Locale, options?: { reload?: boolean }) => void | Promise<void>} SetLocaleFn\n */\n/**\n * Set the locale.\n *\n * Updates the locale using your configured strategies (cookie, localStorage, URL, etc.).\n * By default, this navigates the client to the localized URL or reloads the current\n * document to reflect the new locale. `reload: false` is a narrow browser-only escape\n * hatch for a fully client-rendered, non-URL-routed surface that owns its reactive\n * updates and document state. It does not re-render the UI or update the document.\n * Do not use it for normal locale pickers, URL-routed pages, or switching an SSR,\n * SSG, or hydrated document. It is incompatible with per-locale builds.\n *\n * If any custom strategy's `setLocale` function is async, then this function\n * will become async as well.\n *\n * @see https://paraglidejs.com/strategy\n *\n * @example\n * setLocale('en');\n *\n * @example\n * setLocale('en', { reload: false });\n *\n * @type {SetLocaleFn}\n */\nexport let setLocale = (newLocale, options) => {\n const optionsWithDefaults = {\n reload: true,\n ...options,\n };\n if (experimentalStaticLocale !== undefined &&\n newLocale !== experimentalStaticLocale &&\n optionsWithDefaults.reload === false) {\n console.warn(`Paraglide: setLocale(${JSON.stringify(newLocale)}, { reload: false }) cannot switch away from the statically built locale ${JSON.stringify(experimentalStaticLocale)}. A document navigation is required; reload has been forced to true.`);\n optionsWithDefaults.reload = true;\n }\n // locale is already set\n // https://github.com/opral/inlang-paraglide-js/issues/430\n /** @type {Locale | undefined} */\n let currentLocale;\n try {\n currentLocale = getLocale();\n }\n catch {\n // do nothing, no locale has been set yet.\n }\n /** @type {Array<Promise<void>>} */\n const customSetLocalePromises = [];\n /** @type {string | undefined} */\n let newLocation = undefined;\n let strategyToUse = strategy;\n if (!isServer && typeof window !== \"undefined\" && window.location?.href) {\n strategyToUse = getStrategyForUrl(window.location.href);\n }\n for (const strat of strategyToUse) {\n if (TREE_SHAKE_GLOBAL_VARIABLE_STRATEGY_USED &&\n strat === \"globalVariable\") {\n // a default for a custom strategy to get started quickly\n // is likely overwritten by `defineSetLocale()`\n _locale = newLocale;\n }\n else if (TREE_SHAKE_COOKIE_STRATEGY_USED && strat === \"cookie\") {\n if (isServer ||\n typeof document === \"undefined\" ||\n typeof window === \"undefined\") {\n continue;\n }\n // set the cookie\n const cookieString = `${cookieName}=${newLocale}; path=/; max-age=${cookieMaxAge}`;\n document.cookie = cookieDomain\n ? `${cookieString}; domain=${cookieDomain}`\n : cookieString;\n clearLocaleCookieCache();\n }\n else if (strat === \"baseLocale\") {\n // nothing to be set here. baseLocale is only a fallback\n continue;\n }\n else if (TREE_SHAKE_URL_STRATEGY_USED &&\n strat === \"url\" &&\n typeof window !== \"undefined\") {\n // route to the new url\n //\n // this triggers a page reload but a user rarely\n // switches locales, so this should be fine.\n //\n // if the behavior is not desired, the implementation\n // can be overwritten by `defineSetLocale()` to avoid\n // a full page reload.\n newLocation = localizeUrl(window.location.href, {\n locale: newLocale,\n }).href;\n }\n else if (TREE_SHAKE_LOCAL_STORAGE_STRATEGY_USED &&\n strat === \"localStorage\" &&\n typeof window !== \"undefined\") {\n // set the localStorage\n localStorage.setItem(localStorageKey, newLocale);\n }\n else if (isCustomStrategy(strat) && customClientStrategies.has(strat)) {\n const handler = customClientStrategies.get(strat);\n if (handler) {\n let result = handler.setLocale(newLocale);\n // Handle async setLocale\n if (result instanceof Promise) {\n result = result.catch((error) => {\n throw new Error(`Custom strategy \"${strat}\" setLocale failed.`, {\n cause: error,\n });\n });\n customSetLocalePromises.push(result);\n }\n }\n }\n }\n const runReload = () => {\n if (!isServer &&\n optionsWithDefaults.reload &&\n window.location &&\n newLocale !== currentLocale) {\n navigateOrReload(newLocation);\n }\n };\n if (customSetLocalePromises.length) {\n return Promise.all(customSetLocalePromises).then(() => {\n runReload();\n });\n }\n runReload();\n return;\n};\n/**\n * Overwrite the `setLocale()` function.\n *\n * Use this function to overwrite how the locale is set. For example,\n * modify a cookie, env variable, or a user's preference.\n *\n * @example\n * overwriteSetLocale((newLocale) => {\n * // set the locale in a cookie\n * return Cookies.set('locale', newLocale)\n * });\n *\n * @param {SetLocaleFn} fn\n */\nexport const overwriteSetLocale = (fn) => {\n setLocale = fn;\n};\n\n/**\n * The origin of the current URL.\n *\n * Defaults to \"http://example.com\" in non-browser environments. If this\n * behavior is not desired, the implementation can be overwritten\n * by `overwriteGetUrlOrigin()`.\n *\n * @type {() => string}\n */\nexport let getUrlOrigin = () => {\n if (serverAsyncLocalStorage) {\n return serverAsyncLocalStorage.getStore()?.origin ?? \"http://fallback.com\";\n }\n else if (typeof window !== \"undefined\") {\n return window.location.origin;\n }\n return \"http://fallback.com\";\n};\n/**\n * Overwrite the getUrlOrigin function.\n *\n * Use this function in server environments to\n * define how the URL origin is resolved.\n *\n * @param {() => string} fn - The new implementation for `getUrlOrigin()`.\n */\nexport let overwriteGetUrlOrigin = (fn) => {\n getUrlOrigin = fn;\n};\n\n/**\n * Coerces a locale-like string to the canonical locale value used by the runtime.\n *\n * @param {unknown} value\n * @returns {Locale | undefined}\n */\nexport function toLocale(value) {\n if (typeof value !== \"string\") {\n return undefined;\n }\n const lowerValue = value.toLowerCase();\n for (const locale of locales) {\n if (locale.toLowerCase() === lowerValue) {\n return locale;\n }\n }\n return undefined;\n}\n/**\n * Check if something is an available locale with the canonical project casing.\n *\n * @example\n * if (isLocale(params.locale)) {\n * setLocale(params.locale);\n * } else {\n * setLocale('en');\n * }\n *\n * Use `toLocale()` when you want case-insensitive matching and canonicalization.\n *\n * @param {unknown} locale\n * @returns {locale is Locale}\n */\nexport function isLocale(locale) {\n return !!locale && locales.some((item) => item === locale);\n}\n/**\n * Asserts that the input can be normalized to a locale.\n *\n * @param {unknown} input - The input to check.\n * @returns {Locale} The input normalized to a Locale.\n * @throws {Error} If the input is not a locale.\n */\nexport function assertIsLocale(input) {\n const locale = toLocale(input);\n if (locale)\n return locale;\n throw new Error(`Invalid locale: ${input}. Expected one of: ${locales.join(\", \")}`);\n}\n\n/**\n * Applies the configured trailing slash policy to a URL.\n *\n * The root pathname always remains `/`. Query parameters and hashes are not\n * modified.\n *\n * @param {URL} url\n * @returns {URL}\n */\nfunction normalizeTrailingSlash(url) {\n if (trailingSlash === undefined || url.pathname === \"/\") {\n return url;\n }\n if (trailingSlash === \"never\") {\n url.pathname = url.pathname.replace(/\\/+$/, \"\") || \"/\";\n }\n else if (trailingSlash === \"always\") {\n url.pathname = url.pathname.replace(/\\/+$/, \"\") + \"/\";\n }\n return url;\n}\n\n/**\n * Matches a canonical URL while allowing configured patterns to retain their\n * existing trailing slash style.\n *\n * @param {URLPattern} pattern\n * @param {URL} url\n * @returns {any}\n */\nfunction execUrlPattern(pattern, url) {\n if (trailingSlash === undefined || url.pathname === \"/\") {\n return pattern.exec(url.href);\n }\n const alias = new URL(url);\n if (trailingSlash === \"always\") {\n alias.pathname = alias.pathname.replace(/\\/+$/, \"\") || \"/\";\n // Prefer the slashless alias so the canonical slash does not become part\n // of a terminal wildcard capture.\n return pattern.exec(alias.href) ?? pattern.exec(url.href);\n }\n else if (trailingSlash === \"never\") {\n const match = pattern.exec(url.href);\n if (match) {\n return match;\n }\n alias.pathname = alias.pathname.replace(/\\/+$/, \"\") + \"/\";\n return pattern.exec(alias.href);\n }\n return pattern.exec(url.href);\n}\n\n/**\n * @typedef {object} ExtractLocaleFromRequestOptions\n * @property {string | URL} [effectiveRequestUrl] - Effective request URL to use for route matching and locale detection with the URL strategy.\n */\n/**\n * Extracts a locale from a request.\n *\n * Use the function on the server to extract the locale\n * from a request.\n *\n * The function goes through the strategies in the order\n * they are defined. If a strategy returns an invalid locale,\n * it will fall back to the next strategy.\n *\n * Note: Custom server strategies are not supported in this synchronous version.\n * Use `extractLocaleFromRequestAsync` if you need custom server strategies with async getLocale methods.\n *\n * @example\n * const locale = extractLocaleFromRequest(request);\n *\n * @param {Request} request\n * @param {ExtractLocaleFromRequestOptions} [options]\n * @returns {Locale}\n */\nexport const extractLocaleFromRequest = (request, options = {}) => {\n const effectiveRequestUrl = resolveEffectiveRequestUrl(request, options.effectiveRequestUrl);\n return extractLocaleFromRequestWithStrategies(request, getStrategyForUrl(effectiveRequestUrl), effectiveRequestUrl);\n};\n/**\n * Extracts a locale from a request using the provided strategy order.\n *\n * @param {Request} request\n * @param {typeof strategy} strategies\n * @param {string | URL} [url]\n * @returns {Locale}\n */\nexport const extractLocaleFromRequestWithStrategies = (request, strategies, url = request.url) => {\n const effectiveRequestUrl = resolveEffectiveRequestUrl(request, url);\n /** @type {string|undefined} */\n let locale;\n for (const strat of strategies) {\n if (TREE_SHAKE_COOKIE_STRATEGY_USED && strat === \"cookie\") {\n const cookiePrefix = cookieName + \"=\";\n locale = request.headers\n .get(\"cookie\")\n ?.split(\";\")\n .map((c) => c.trim())\n .find((c) => c.startsWith(cookiePrefix))\n ?.slice(cookiePrefix.length);\n }\n else if (TREE_SHAKE_URL_STRATEGY_USED && strat === \"url\") {\n locale = extractLocaleFromUrl(effectiveRequestUrl);\n }\n else if (TREE_SHAKE_PREFERRED_LANGUAGE_STRATEGY_USED &&\n strat === \"preferredLanguage\") {\n locale = extractLocaleFromHeader(request);\n }\n else if (strat === \"globalVariable\") {\n locale = _locale;\n }\n else if (strat === \"baseLocale\") {\n return baseLocale;\n }\n else if (strat === \"localStorage\") {\n continue;\n }\n else if (isCustomStrategy(strat)) {\n // Custom strategies are not supported in sync version\n // Use extractLocaleFromRequestAsync for custom server strategies\n continue;\n }\n const matchedLocale = toLocale(locale);\n if (matchedLocale) {\n return matchedLocale;\n }\n }\n 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://paraglidejs.com/errors#no-locale-found\");\n};\n/**\n * @param {Request} request\n * @param {string | URL | undefined} effectiveRequestUrl\n * @returns {URL}\n */\nfunction resolveEffectiveRequestUrl(request, effectiveRequestUrl = request.url) {\n if (effectiveRequestUrl instanceof URL) {\n return new URL(effectiveRequestUrl.href);\n }\n return new URL(effectiveRequestUrl, request.url);\n}\n\n/**\n * Asynchronously extracts a locale from a request.\n *\n * This function supports async custom server strategies, unlike the synchronous\n * `extractLocaleFromRequest`. Use this function when you have custom server strategies\n * that need to perform asynchronous operations (like database calls) in their getLocale method.\n *\n * The function first processes any custom server strategies asynchronously, then falls back\n * to the synchronous `extractLocaleFromRequest` for all other strategies.\n *\n * @see {@link https://github.com/opral/inlang-paraglide-js/issues/527#issuecomment-2978151022}\n *\n * @example\n * // Basic usage\n * const locale = await extractLocaleFromRequestAsync(request);\n *\n * @example\n * // With custom async server strategy\n * defineCustomServerStrategy(\"custom-database\", {\n * getLocale: async (request) => {\n * const userId = extractUserIdFromRequest(request);\n * return await getUserLocaleFromDatabase(userId);\n * }\n * });\n *\n * const locale = await extractLocaleFromRequestAsync(request);\n *\n * @param {Request} request - The request object to extract the locale from.\n * @param {{ effectiveRequestUrl?: string | URL }} [options] - Effective request URL to use for route matching and locale detection with the URL strategy.\n * @returns {Promise<Locale>} The extracted locale.\n */\nexport const extractLocaleFromRequestAsync = async (request, options = {}) => {\n /** @type {string|undefined} */\n let locale;\n const effectiveRequestUrl = resolveEffectiveRequestUrlFromRequestAsync(request, options.effectiveRequestUrl);\n const strategy = getStrategyForUrl(effectiveRequestUrl);\n // Process custom strategies first, in order\n for (const strat of strategy) {\n if (isCustomStrategy(strat) && customServerStrategies.has(strat)) {\n const handler = customServerStrategies.get(strat);\n if (handler) {\n /** @type {string|undefined} */\n locale = await handler.getLocale(request);\n }\n // If we got a valid locale from this custom strategy, use it\n const matchedLocale = toLocale(locale);\n if (matchedLocale) {\n return matchedLocale;\n }\n }\n }\n // If no custom strategy provided a valid locale, fall back to sync version\n return extractLocaleFromRequestWithStrategies(request, strategy, effectiveRequestUrl);\n};\n/**\n * @param {Request} request\n * @param {string | URL | undefined} effectiveRequestUrl\n * @returns {URL}\n */\nfunction resolveEffectiveRequestUrlFromRequestAsync(request, effectiveRequestUrl = request.url) {\n if (effectiveRequestUrl instanceof URL) {\n return new URL(effectiveRequestUrl.href);\n }\n return new URL(effectiveRequestUrl, request.url);\n}\n\nconst cookieNamePattern = cookieName.replace(/[.*+?^${}()|[\\]\\\\]/g, \"\\\\$&\");\nconst localeCookiePattern = new RegExp(`(?:^|;\\\\s*)${cookieNamePattern}=([^;]*)`);\nconst noCachedLocale = Symbol();\n/** @type {Locale | undefined | typeof noCachedLocale} */\nlet cachedLocaleFromCookie = noCachedLocale;\n/**\n * Clears the cached locale from `document.cookie`.\n */\nfunction clearLocaleCookieCache() {\n cachedLocaleFromCookie = noCachedLocale;\n}\nfunction scheduleLocaleCookieCacheClear() {\n if (typeof queueMicrotask === \"function\") {\n queueMicrotask(clearLocaleCookieCache);\n }\n else {\n Promise.resolve().then(clearLocaleCookieCache);\n }\n}\n/**\n * Extracts a cookie from the document.\n *\n * Will return undefined if the document is not available or if the cookie is not set.\n * The `document` object is not available in server-side rendering, so this function should not be called in that context.\n *\n * @returns {Locale | undefined}\n */\nexport function extractLocaleFromCookie() {\n if (typeof document === \"undefined\") {\n return;\n }\n if (cachedLocaleFromCookie !== noCachedLocale) {\n return cachedLocaleFromCookie;\n }\n const match = document.cookie.match(localeCookiePattern);\n const locale = match?.[1];\n cachedLocaleFromCookie = toLocale(locale);\n scheduleLocaleCookieCacheClear();\n return cachedLocaleFromCookie;\n}\n\n/**\n * Extracts a locale from the accept-language header.\n *\n * Use the function on the server to extract the locale\n * from the accept-language header that is sent by the client.\n *\n * @example\n * const locale = extractLocaleFromHeader(request);\n *\n * @param {Request} request - The request object to extract the locale from.\n * @returns {Locale | undefined} The negotiated preferred language.\n */\nexport function extractLocaleFromHeader(request) {\n const acceptLanguageHeader = request.headers.get(\"accept-language\");\n if (acceptLanguageHeader) {\n // Parse language preferences with their q-values and base language codes\n const languages = acceptLanguageHeader\n .split(\",\")\n .map((lang) => {\n const [tag, q = \"1\"] = lang.trim().split(\";q=\");\n // Get both the full tag and base language code\n const baseTag = tag?.split(\"-\")[0];\n return {\n fullTag: tag,\n baseTag,\n q: Number(q),\n };\n })\n .sort((a, b) => b.q - a.q);\n for (const lang of languages) {\n const fullLocale = toLocale(lang.fullTag);\n if (fullLocale) {\n return fullLocale;\n }\n const baseLocale = toLocale(lang.baseTag);\n if (baseLocale) {\n return baseLocale;\n }\n }\n return undefined;\n }\n return undefined;\n}\n\n/**\n * Negotiates a preferred language from navigator.languages.\n *\n * Use the function on the client to extract the locale\n * from the navigator.languages array.\n *\n * @example\n * const locale = extractLocaleFromNavigator();\n *\n * @returns {Locale | undefined}\n */\nexport function extractLocaleFromNavigator() {\n if (!navigator?.languages?.length) {\n return undefined;\n }\n const languages = navigator.languages.map((lang) => ({\n fullTag: lang,\n baseTag: lang.split(\"-\")[0],\n }));\n for (const lang of languages) {\n const fullLocale = toLocale(lang.fullTag);\n if (fullLocale) {\n return fullLocale;\n }\n const baseLocale = toLocale(lang.baseTag);\n if (baseLocale) {\n return baseLocale;\n }\n }\n return undefined;\n}\n\n/**\n * If extractLocaleFromUrl is called many times on the same page and the URL\n * hasn't changed, we don't need to recompute it every time which can get expensive.\n * We might use a LRU cache if needed, but for now storing only the last result is enough.\n * https://github.com/opral/monorepo/pull/3575#discussion_r2066731243\n */\n/** @type {string|undefined} */\nlet cachedUrl;\n/** @type {Locale|undefined} */\nlet cachedLocale;\n/**\n * Extracts the locale from a given URL using native URLPattern.\n *\n * The built-in default `/:locale/...` routing is case-insensitive because it\n * canonicalizes the first path segment with `toLocale()`. Custom `urlPatterns`\n * keep URLPattern's normal exact matching semantics for path segments.\n *\n * @param {URL|string} url - The full URL from which to extract the locale.\n * @returns {Locale|undefined} The extracted locale, or undefined if no locale is found.\n */\nexport function extractLocaleFromUrl(url) {\n const urlString = typeof url === \"string\" ? url : url.href;\n if (cachedUrl === urlString) {\n return cachedLocale;\n }\n /** @type {Locale | undefined} */\n let result;\n if (TREE_SHAKE_DEFAULT_URL_PATTERN_USED) {\n const urlObj = typeof url === \"string\"\n ? new URL(url, \"http://example.com\")\n : new URL(url);\n result = defaultUrlPatternExtractLocale(normalizeTrailingSlash(urlObj));\n }\n else {\n const urlObj = normalizeTrailingSlash(typeof url === \"string\" ? new URL(url) : new URL(url));\n // Iterate over URL patterns\n for (const element of urlPatterns) {\n for (const [locale, localizedPattern] of element.localized) {\n const match = execUrlPattern(new URLPattern(localizedPattern, urlObj.href), urlObj);\n if (match) {\n result = locale;\n break;\n }\n }\n if (result)\n break;\n }\n }\n cachedUrl = urlString;\n cachedLocale = result;\n return result;\n}\n/**\n * https://github.com/opral/inlang-paraglide-js/issues/381\n *\n * @param {URL | string} url - The full URL from which to extract the locale.\n * @returns {Locale | undefined} The extracted locale, or undefined if no locale is found.\n */\nfunction defaultUrlPatternExtractLocale(url) {\n const urlObj = new URL(url, \"http://example.com\");\n const pathSegments = urlObj.pathname.split(\"/\").filter(Boolean);\n return toLocale(pathSegments[0]) || baseLocale;\n}\n\n/**\n * Lower-level URL localization function, primarily used in server contexts.\n *\n * This function is designed for server-side usage where you need precise control\n * over URL localization, such as in middleware or request handlers. It works with\n * URL objects and always returns absolute URLs.\n *\n * For client-side UI components, use `localizeHref()` instead, which provides\n * a more convenient API with relative paths and automatic locale detection.\n *\n * @see https://paraglidejs.com/i18n-routing\n *\n * @example\n * ```typescript\n * // Server middleware example\n * app.use((req, res, next) => {\n * const url = new URL(req.url, `${req.protocol}://${req.headers.host}`);\n * const localized = localizeUrl(url, { locale: \"de\" });\n *\n * if (localized.href !== url.href) {\n * return res.redirect(localized.href);\n * }\n * next();\n * });\n * ```\n *\n * @example\n * ```typescript\n * // Using with URL patterns\n * const url = new URL(\"https://example.com/about\");\n * localizeUrl(url, { locale: \"de\" });\n * // => URL(\"https://example.com/de/about\")\n *\n * // Using with domain-based localization\n * const url = new URL(\"https://example.com/store\");\n * localizeUrl(url, { locale: \"de\" });\n * // => URL(\"https://de.example.com/store\")\n * ```\n *\n * @param {string | URL} url - The URL to localize. If string, must be absolute.\n * @param {object} [options] - Options for localization\n * @param {Locale} [options.locale] - Target locale. If not provided, uses getLocale()\n * @returns {URL} The localized URL, always absolute\n */\nexport function localizeUrl(url, options) {\n const targetLocale = options?.locale\n ? assertIsLocale(options?.locale)\n : getLocale();\n if (TREE_SHAKE_DEFAULT_URL_PATTERN_USED) {\n return localizeUrlDefaultPattern(url, targetLocale);\n }\n const originalUrl = typeof url === \"string\" ? new URL(url) : url;\n const urlObj = trailingSlash === undefined\n ? originalUrl\n : normalizeTrailingSlash(new URL(originalUrl));\n // Iterate over URL patterns\n for (const element of urlPatterns) {\n // Most applications use a locale prefix (and sometimes a fixed domain)\n // with a trailing catch-all path. Those routes do not need URLPattern's\n // parser or matcher on every call. Keep the generic matcher below as the\n // fallback for every other URLPattern shape. This stays inside the outer\n // loop so specific patterns retain precedence over a later catch-all.\n const fastPathLocalized = localizeUrlFastPath(urlObj, targetLocale, element);\n if (fastPathLocalized !== undefined) {\n return fastPathLocalized;\n }\n // match localized patterns\n for (const [, localizedPattern] of element.localized) {\n const match = execUrlPattern(getUrlPattern(localizedPattern, urlObj), urlObj);\n if (!match) {\n continue;\n }\n const targetPattern = element.localized.find(([locale]) => locale === targetLocale)?.[1];\n if (!targetPattern) {\n continue;\n }\n const localizedUrl = fillPattern(targetPattern, aggregateGroups(match), urlObj.origin);\n return normalizeTrailingSlash(fillMissingUrlParts(localizedUrl, match));\n }\n const unlocalizedMatch = execUrlPattern(getUrlPattern(element.pattern, urlObj), urlObj);\n if (unlocalizedMatch) {\n const targetPattern = element.localized.find(([locale]) => locale === targetLocale)?.[1];\n if (targetPattern) {\n const localizedUrl = fillPattern(targetPattern, aggregateGroups(unlocalizedMatch), urlObj.origin);\n return normalizeTrailingSlash(fillMissingUrlParts(localizedUrl, unlocalizedMatch));\n }\n }\n }\n // If no match found, return the original URL\n return originalUrl;\n}\n/**\n * https://github.com/opral/inlang-paraglide-js/issues/381\n *\n * @param {string | URL} url\n * @param {Locale} locale\n * @returns {URL}\n */\nfunction localizeUrlDefaultPattern(url, locale) {\n const urlObj = normalizeTrailingSlash(typeof url === \"string\" ? new URL(url, getUrlOrigin()) : new URL(url));\n const currentLocale = extractLocaleFromUrl(urlObj);\n // If current locale matches target locale, no change needed\n if (currentLocale === locale) {\n return normalizeTrailingSlash(urlObj);\n }\n const pathSegments = urlObj.pathname.split(\"/\").filter(Boolean);\n // If current path starts with a locale, remove it\n if (pathSegments.length > 0 && toLocale(pathSegments[0])) {\n pathSegments.shift();\n }\n // For base locale, don't add prefix\n if (locale === baseLocale) {\n urlObj.pathname = \"/\" + pathSegments.join(\"/\");\n }\n else {\n // For other locales, add prefix\n urlObj.pathname = \"/\" + locale + \"/\" + pathSegments.join(\"/\");\n }\n return normalizeTrailingSlash(urlObj);\n}\n/**\n * Low-level URL de-localization function, primarily used in server contexts.\n *\n * This function is designed for server-side usage where you need precise control\n * over URL de-localization, such as in middleware or request handlers. It works with\n * URL objects and always returns absolute URLs.\n *\n * For client-side UI components, use `deLocalizeHref()` instead, which provides\n * a more convenient API with relative paths.\n *\n * @see https://paraglidejs.com/i18n-routing\n *\n * @example\n * ```typescript\n * // Server middleware example\n * app.use((req, res, next) => {\n * const url = new URL(req.url, `${req.protocol}://${req.headers.host}`);\n * const baseUrl = deLocalizeUrl(url);\n *\n * // Store the base URL for later use\n * req.baseUrl = baseUrl;\n * next();\n * });\n * ```\n *\n * @example\n * ```typescript\n * // Using with URL patterns\n * const url = new URL(\"https://example.com/de/about\");\n * deLocalizeUrl(url); // => URL(\"https://example.com/about\")\n *\n * // Using with domain-based localization\n * const url = new URL(\"https://de.example.com/store\");\n * deLocalizeUrl(url); // => URL(\"https://example.com/store\")\n * ```\n *\n * @param {string | URL} url - The URL to de-localize. If string, must be absolute.\n * @returns {URL} The de-localized URL, always absolute\n */\nexport function deLocalizeUrl(url) {\n if (TREE_SHAKE_DEFAULT_URL_PATTERN_USED) {\n return deLocalizeUrlDefaultPattern(url);\n }\n const originalUrl = typeof url === \"string\" ? new URL(url) : url;\n const urlObj = trailingSlash === undefined\n ? originalUrl\n : normalizeTrailingSlash(new URL(originalUrl));\n // Iterate over URL patterns\n for (const element of urlPatterns) {\n const fastPathDeLocalized = deLocalizeUrlFastPath(urlObj, element);\n if (fastPathDeLocalized !== undefined) {\n return fastPathDeLocalized;\n }\n // Iterate over localized versions\n for (const [, localizedPattern] of element.localized) {\n const match = execUrlPattern(getUrlPattern(localizedPattern, urlObj), urlObj);\n if (match) {\n // Convert localized URL back to the base pattern\n const groups = aggregateGroups(match);\n const baseUrl = fillPattern(element.pattern, groups, urlObj.origin);\n return normalizeTrailingSlash(fillMissingUrlParts(baseUrl, match));\n }\n }\n // match unlocalized pattern\n const unlocalizedMatch = execUrlPattern(getUrlPattern(element.pattern, urlObj), urlObj);\n if (unlocalizedMatch) {\n const baseUrl = fillPattern(element.pattern, aggregateGroups(unlocalizedMatch), urlObj.origin);\n return normalizeTrailingSlash(fillMissingUrlParts(baseUrl, unlocalizedMatch));\n }\n }\n // no match found return the original url\n return originalUrl;\n}\n/**\n * De-localizes a URL using the default pattern (/:locale/*)\n * @param {string|URL} url\n * @returns {URL}\n */\nfunction deLocalizeUrlDefaultPattern(url) {\n const urlObj = normalizeTrailingSlash(typeof url === \"string\" ? new URL(url, getUrlOrigin()) : new URL(url));\n const pathSegments = urlObj.pathname.split(\"/\").filter(Boolean);\n // If first segment is a locale, remove it\n if (pathSegments.length > 0 && toLocale(pathSegments[0])) {\n urlObj.pathname = \"/\" + pathSegments.slice(1).join(\"/\");\n }\n return normalizeTrailingSlash(urlObj);\n}\n/**\n * Takes matches of implicit wildcards in the UrlPattern (when a part is missing\n * it is equal to '*') and adds them back to the result of fillPattern.\n *\n * At least protocol and hostname are required to create a valid URL inside fillPattern.\n *\n * @param {URL} url\n * @param {any} match\n * @returns {URL}\n */\nfunction fillMissingUrlParts(url, match) {\n if (match.protocol.groups[\"0\"]) {\n url.protocol = match.protocol.groups[\"0\"] ?? \"\";\n }\n if (match.hostname.groups[\"0\"]) {\n url.hostname = match.hostname.groups[\"0\"] ?? \"\";\n }\n if (match.username.groups[\"0\"]) {\n url.username = match.username.groups[\"0\"] ?? \"\";\n }\n if (match.password.groups[\"0\"]) {\n url.password = match.password.groups[\"0\"] ?? \"\";\n }\n if (match.port.groups[\"0\"]) {\n url.port = match.port.groups[\"0\"] ?? \"\";\n }\n if (match.pathname.groups[\"0\"]) {\n url.pathname = match.pathname.groups[\"0\"] ?? \"\";\n }\n if (match.search.groups[\"0\"]) {\n url.search = match.search.groups[\"0\"] ?? \"\";\n }\n if (match.hash.groups[\"0\"]) {\n url.hash = match.hash.groups[\"0\"] ?? \"\";\n }\n return url;\n}\n/**\n * Fills a URL pattern with values for named groups, supporting all URLPattern-style modifiers.\n *\n * This function will eventually be replaced by https://github.com/whatwg/urlpattern/issues/73\n *\n * Matches:\n * - :name -> Simple\n * - :name? -> Optional\n * - :name+ -> One or more\n * - :name* -> Zero or more\n * - :name(...) -> Regex group\n * - {text} -> Group delimiter\n * - {text}? -> Optional group delimiter\n *\n * If the value is `null`, the segment is removed.\n *\n * @param {string} pattern - The URL pattern containing named groups.\n * @param {Record<string, string | null | undefined>} values - Object of values for named groups.\n * @param {string} origin - Base URL to use for URL construction.\n * @returns {URL} - The constructed URL with named groups filled.\n */\nfunction fillPattern(pattern, values, origin) {\n // Pre-process the pattern to handle explicit port numbers\n // This detects patterns like \"http://localhost:5173\" and protects the port number\n // from being interpreted as a parameter\n let processedPattern = pattern.replace(/(https?:\\/\\/[^:/]+):(\\d+)(\\/|$)/g, (_, protocol, port, slash) => {\n // Replace \":5173\" with \"#PORT-5173#\" to protect it from parameter replacement\n return `${protocol}#PORT-${port}#${slash}`;\n });\n // First, handle group delimiters with curly braces\n let processedGroupDelimiters = processedPattern.replace(/\\{([^{}]*)\\}([?+*]?)/g, (_, content, modifier) => {\n // For optional group delimiters\n if (modifier === \"?\") {\n // For optional groups, we'll include the content\n return content;\n }\n // For non-optional group delimiters, always include the content\n return content;\n });\n // Then handle named groups\n let filled = processedGroupDelimiters.replace(/(\\/?):([a-zA-Z0-9_]+)(\\([^)]*\\))?([?+*]?)/g, (_, slash, name, __, modifier) => {\n const value = values[name];\n if (value === null) {\n // If value is null, remove the entire segment including the preceding slash\n return \"\";\n }\n if (modifier === \"?\") {\n // Optional segment\n return value !== undefined ? `${slash}${value}` : \"\";\n }\n if (modifier === \"+\" || modifier === \"*\") {\n // Repeatable segments\n if (value === undefined && modifier === \"+\") {\n throw new Error(`Missing value for \"${name}\" (one or more required)`);\n }\n return value ? `${slash}${value}` : \"\";\n }\n // Simple named group (no modifier)\n if (value === undefined) {\n throw new Error(`Missing value for \"${name}\"`);\n }\n return `${slash}${value}`;\n });\n // Restore port numbers\n filled = filled.replace(/#PORT-(\\d+)#/g, \":$1\");\n return new URL(filled, origin);\n}\n/**\n * Aggregates named groups from various parts of the URLPattern match result.\n *\n *\n * @param {any} match - The URLPattern match result object.\n * @returns {Record<string, string | null | undefined>} An object containing all named groups from the match.\n */\nexport function aggregateGroups(match) {\n return {\n ...match.hash.groups,\n ...match.hostname.groups,\n ...match.password.groups,\n ...match.pathname.groups,\n ...match.port.groups,\n ...match.protocol.groups,\n ...match.search.groups,\n ...match.username.groups,\n };\n}\n/** @type {Map<string, URLPattern>} */\nconst urlPatternCache = new Map();\nconst URL_PATTERN_CACHE_LIMIT = 128;\nconst ABSOLUTE_URL_PATTERN = /^(?:[A-Za-z][A-Za-z\\d+.-]*|:[A-Za-z][A-Za-z\\d_-]*):\\/\\//;\n/**\n * URLPattern's base URL affects relative patterns. Absolute patterns only\n * depend on the pattern itself, while root-relative patterns also depend on\n * the URL origin. Other relative patterns are deliberately not cached because\n * their semantics depend on the complete base URL.\n *\n * @param {string} pattern\n * @param {URL} url\n * @returns {URLPattern}\n */\nfunction getUrlPattern(pattern, url) {\n const isAbsolutePattern = ABSOLUTE_URL_PATTERN.test(pattern);\n const isRootRelativePattern = pattern.startsWith(\"/\");\n if (!isAbsolutePattern && !isRootRelativePattern) {\n return new URLPattern(pattern, url.href);\n }\n const key = isAbsolutePattern\n ? pattern\n : JSON.stringify([url.origin, pattern]);\n const cached = urlPatternCache.get(key);\n if (cached !== undefined) {\n // Refresh the entry so frequently used patterns stay in the bounded cache.\n urlPatternCache.delete(key);\n urlPatternCache.set(key, cached);\n return cached;\n }\n const compiled = new URLPattern(pattern, url.href);\n if (urlPatternCache.size >= URL_PATTERN_CACHE_LIMIT) {\n const oldestKey = urlPatternCache.keys().next().value;\n if (oldestKey !== undefined)\n urlPatternCache.delete(oldestKey);\n }\n urlPatternCache.set(key, compiled);\n return compiled;\n}\n/**\n * A small, deliberately conservative subset of URLPattern routing.\n *\n * The compiler emits routes such as `/:path(.*)?`, `/de/:path*`, or\n * `https://example.com/:path*`. For those routes matching is equivalent to a\n * pathname prefix check and (optionally) an origin check. Everything that has\n * a dynamic host, a custom path regexp, or another URLPattern modifier keeps\n * using the generic implementation above.\n *\n * @typedef {{\n * protocol: string | undefined;\n * hostname: string | undefined;\n * port: string | undefined;\n * pathnamePrefix: string;\n * pathMode: \"segments\" | \"catch-all-optional\" | \"catch-all-required\";\n * }} FastPathPattern\n * @typedef {{\n * base: FastPathPattern;\n * localized: Array<{ locale: string; pattern: FastPathPattern }>;\n * }} FastPathRoute\n */\n/** @type {WeakMap<object, FastPathRoute | null>} */\nconst fastPathRouteCache = new WeakMap();\n/**\n * @param {URL} urlObj\n * @param {string} targetLocale\n * @param {{ pattern: string; localized: Array<[string, string]> }} element\n * @returns {URL | undefined}\n */\nfunction localizeUrlFastPath(urlObj, targetLocale, element) {\n const route = getFastPathRoute(element);\n if (route === null)\n return undefined;\n // Preserve URLPattern's ordering: localized patterns are checked before\n // the unlocalized pattern, and the first matching pattern wins.\n for (const localized of route.localized) {\n const suffix = matchFastPathPattern(localized.pattern, urlObj);\n if (suffix === undefined)\n continue;\n const target = route.localized.find((candidate) => candidate.locale === targetLocale)?.pattern;\n if (target === undefined)\n continue;\n return applyFastPathPattern(target, suffix, urlObj);\n }\n const suffix = matchFastPathPattern(route.base, urlObj);\n if (suffix !== undefined) {\n const target = route.localized.find((candidate) => candidate.locale === targetLocale)?.pattern;\n if (target !== undefined) {\n return applyFastPathPattern(target, suffix, urlObj);\n }\n }\n return undefined;\n}\n/**\n * @param {URL} urlObj\n * @param {{ pattern: string; localized: Array<[string, string]> }} element\n * @returns {URL | undefined}\n */\nfunction deLocalizeUrlFastPath(urlObj, element) {\n const route = getFastPathRoute(element);\n if (route === null)\n return undefined;\n for (const localized of route.localized) {\n const suffix = matchFastPathPattern(localized.pattern, urlObj);\n if (suffix !== undefined) {\n return applyFastPathPattern(route.base, suffix, urlObj);\n }\n }\n const suffix = matchFastPathPattern(route.base, urlObj);\n if (suffix !== undefined) {\n return applyFastPathPattern(route.base, suffix, urlObj);\n }\n return undefined;\n}\n/**\n * @param {{ pattern: string; localized: Array<[string, string]> }} element\n * @returns {FastPathRoute | null}\n */\nfunction getFastPathRoute(element) {\n const cached = fastPathRouteCache.get(element);\n if (cached !== undefined)\n return cached;\n const base = parseFastPathPattern(element.pattern);\n if (base === undefined) {\n fastPathRouteCache.set(element, null);\n return null;\n }\n const localized = [];\n for (const [locale, pattern] of element.localized) {\n const parsed = parseFastPathPattern(pattern);\n if (parsed === undefined || parsed.pathMode !== base.pathMode) {\n fastPathRouteCache.set(element, null);\n return null;\n }\n localized.push({ locale, pattern: parsed });\n }\n const route = { base, localized };\n fastPathRouteCache.set(element, route);\n return route;\n}\n/**\n * Parse only catch-all path patterns. In particular, do not treat `:path(.)?`\n * as a catch-all: URLPattern's `(.)` means exactly one character and cannot be\n * represented by this prefix matcher without changing routing semantics.\n *\n * @param {string} pattern\n * @returns {FastPathPattern | undefined}\n */\nfunction parseFastPathPattern(pattern) {\n const wildcard = pattern.match(/\\/:path(?:\\(\\.\\*\\)(?:\\?)?|\\*)$/);\n if (wildcard === null || wildcard.index === undefined)\n return undefined;\n const prefix = pattern.slice(0, wildcard.index);\n const originAndPath = parseFastPathOriginAndPath(prefix);\n if (originAndPath === undefined)\n return undefined;\n const pathMode = wildcard[0].endsWith(\"*\")\n ? \"segments\"\n : wildcard[0].endsWith(\"?\")\n ? \"catch-all-optional\"\n : \"catch-all-required\";\n return { ...originAndPath, pathMode };\n}\n/**\n * @param {string} prefix\n * @returns {FastPathPattern | undefined}\n */\nfunction parseFastPathOriginAndPath(prefix) {\n if (prefix === \"\" || prefix.startsWith(\"/\")) {\n if (hasUrlPatternSyntax(prefix))\n return undefined;\n return {\n protocol: undefined,\n hostname: undefined,\n port: undefined,\n pathnamePrefix: normalizePathPrefix(prefix),\n pathMode: \"catch-all-optional\",\n };\n }\n // A `:protocol://host` pattern is common in generated configurations. The\n // protocol is intentionally left unconstrained, just like URLPattern.\n const dynamicProtocol = prefix.match(/^:protocol:\\/\\/([^/]+)(\\/.*)?$/);\n const staticOrigin = prefix.match(/^([A-Za-z][A-Za-z\\d+.-]*):\\/\\/([^/]+)(\\/.*)?$/);\n if (dynamicProtocol !== null) {\n const dynamicHost = dynamicProtocol[1] ?? \"\";\n const hostMatch = dynamicHost.match(/^([^:(){}?*+]+)(?::(\\d+))?$/);\n if (hostMatch === null ||\n (dynamicProtocol[2] !== undefined &&\n hasUrlPatternSyntax(dynamicProtocol[2]))) {\n return undefined;\n }\n return {\n protocol: undefined,\n hostname: (hostMatch[1] ?? \"\").toLowerCase(),\n port: hostMatch[2],\n pathnamePrefix: normalizePathPrefix(dynamicProtocol[2] ?? \"\"),\n pathMode: \"catch-all-optional\",\n };\n }\n if (staticOrigin === null)\n return undefined;\n const host = staticOrigin[2] ?? \"\";\n const pathname = staticOrigin[3];\n const hostMatch = host.match(/^([^:(){}?*+]+)(?::(\\d+))?$/);\n if (hostMatch === null ||\n (pathname !== undefined && hasUrlPatternSyntax(pathname))) {\n return undefined;\n }\n return {\n protocol: `${staticOrigin[1]}:`,\n hostname: (hostMatch[1] ?? \"\").toLowerCase(),\n port: normalizePatternPort(hostMatch[2], `${staticOrigin[1]}:`),\n pathnamePrefix: normalizePathPrefix(pathname ?? \"\"),\n pathMode: \"catch-all-optional\",\n };\n}\n/**\n * @param {string | undefined} port\n * @param {string} protocol\n * @returns {string | undefined}\n */\nfunction normalizePatternPort(port, protocol) {\n if (port === \"80\" && protocol === \"http:\")\n return \"\";\n if (port === \"443\" && protocol === \"https:\")\n return \"\";\n return port;\n}\n/**\n * @param {string} value\n * @returns {boolean}\n */\nfunction hasUrlPatternSyntax(value) {\n return /[:(){}?*+]/.test(value);\n}\n/**\n * @param {string} pathname\n * @returns {string}\n */\nfunction normalizePathPrefix(pathname) {\n if (pathname === \"\" || pathname === \"/\")\n return \"/\";\n return pathname.endsWith(\"/\") ? pathname.slice(0, -1) : pathname;\n}\n/**\n * @param {FastPathPattern} pattern\n * @param {URL} urlObj\n * @returns {string | undefined}\n */\nfunction matchFastPathPattern(pattern, urlObj) {\n if (pattern.protocol !== undefined && pattern.protocol !== urlObj.protocol) {\n return undefined;\n }\n if (pattern.hostname !== undefined &&\n pattern.hostname !== urlObj.hostname.toLowerCase()) {\n return undefined;\n }\n if (pattern.hostname !== undefined) {\n const expectedPort = pattern.port ?? defaultPortForProtocol(pattern.protocol ?? urlObj.protocol);\n if (expectedPort !== urlObj.port)\n return undefined;\n }\n const prefix = pattern.pathnamePrefix;\n if (prefix === \"/\") {\n if (urlObj.pathname.startsWith(\"//\"))\n return undefined;\n if (pattern.pathMode === \"segments\") {\n return isNonEmptyPathSegments(urlObj.pathname)\n ? urlObj.pathname\n : undefined;\n }\n return urlObj.pathname;\n }\n if (urlObj.pathname === prefix) {\n return pattern.pathMode === \"catch-all-required\" ? undefined : \"\";\n }\n if (urlObj.pathname.startsWith(`${prefix}/`)) {\n const suffix = urlObj.pathname.slice(prefix.length);\n if (suffix.startsWith(\"//\"))\n return undefined;\n if (pattern.pathMode === \"segments\" &&\n !isNonEmptyPathSegments(suffix)) {\n return undefined;\n }\n return suffix;\n }\n return undefined;\n}\n/**\n * @param {string} pathname\n * @returns {boolean}\n */\nfunction isNonEmptyPathSegments(pathname) {\n return pathname.length > 1 && !pathname.endsWith(\"/\") && !pathname.includes(\"//\");\n}\n/**\n * URLPattern treats the default port as empty in URL instances.\n *\n * @param {string} protocol\n * @returns {string}\n */\nfunction defaultPortForProtocol(protocol) {\n if (protocol === \"http:\")\n return \"\";\n if (protocol === \"https:\")\n return \"\";\n return \"\";\n}\n/**\n * @param {FastPathPattern} pattern\n * @param {string} suffix\n * @param {URL} source\n * @returns {URL}\n */\nfunction applyFastPathPattern(pattern, suffix, source) {\n const localized = new URL(source.href);\n if (pattern.protocol !== undefined)\n localized.protocol = pattern.protocol;\n if (pattern.hostname !== undefined) {\n localized.hostname = pattern.hostname;\n localized.port =\n pattern.port ?? defaultPortForProtocol(localized.protocol);\n }\n localized.pathname = joinFastPathPrefix(pattern.pathnamePrefix, suffix);\n return localized;\n}\n/**\n * @param {string} prefix\n * @param {string} suffix\n * @returns {string}\n */\nfunction joinFastPathPrefix(prefix, suffix) {\n if (prefix === \"/\")\n return suffix === \"\" ? \"/\" : suffix;\n if (suffix === \"\")\n return prefix;\n return `${prefix}${suffix.startsWith(\"/\") ? suffix : `/${suffix}`}`;\n}\n\n/** @type {string | undefined} */\nlet cachedRouteStrategyUrl;\n/** @type {{ match: string; strategy?: typeof strategy; exclude?: boolean } | undefined} */\nlet cachedRouteStrategy;\n/**\n * Match route policy against both the public URL and its canonical URL.\n *\n * The function is deliberately separate from variables.js: configuration is\n * inert data, while canonicalization and route selection form a routing layer.\n *\n * @param {string | URL} url\n * @returns {{ match: string; strategy?: typeof strategy; exclude?: boolean } | undefined}\n */\nexport function findMatchingRouteStrategy(url) {\n if (routeStrategies.length === 0) {\n return undefined;\n }\n const urlString = typeof url === \"string\" ? url : url.href;\n if (cachedRouteStrategyUrl === urlString) {\n return cachedRouteStrategy;\n }\n const publicUrl = normalizeTrailingSlash(new URL(urlString, \"http://example.com\"));\n const canonicalUrl = deLocalizeUrl(publicUrl);\n const candidateUrls = canonicalUrl.href === publicUrl.href\n ? [publicUrl]\n : [publicUrl, canonicalUrl];\n let match;\n for (const candidateUrl of candidateUrls) {\n for (const routeStrategy of routeStrategies) {\n const pattern = new URLPattern(routeStrategy.match, candidateUrl.href);\n if (execUrlPattern(pattern, candidateUrl)) {\n match = routeStrategy;\n break;\n }\n }\n if (match)\n break;\n }\n cachedRouteStrategyUrl = urlString;\n cachedRouteStrategy = match;\n return match;\n}\n/**\n * Returns the strategy to use for a specific URL.\n *\n * If no route strategy matches (or the matching rule is `exclude: true`),\n * the global strategy is returned.\n *\n * @param {string | URL} url\n * @returns {typeof strategy}\n */\nexport function getStrategyForUrl(url) {\n const routeStrategy = findMatchingRouteStrategy(url);\n if (routeStrategy &&\n routeStrategy.exclude !== true &&\n Array.isArray(routeStrategy.strategy)) {\n return routeStrategy.strategy;\n }\n return strategy;\n}\n/**\n * Returns whether the given URL is excluded from middleware i18n processing.\n *\n * @param {string | URL} url\n * @returns {boolean}\n */\nexport function isExcludedByRouteStrategy(url) {\n return findMatchingRouteStrategy(url)?.exclude === true;\n}\n\n/**\n * @typedef {object} ShouldRedirectServerInput\n * @property {Request} request\n * @property {string | URL} [effectiveRequestUrl] - Effective request URL to use for route matching, locale detection with the URL strategy, and redirect targets.\n * @property {Locale} [locale]\n *\n * @typedef {object} ShouldRedirectClientInput\n * @property {undefined} [request]\n * @property {string | URL} [url]\n * @property {Locale} [locale]\n *\n * @typedef {ShouldRedirectServerInput | ShouldRedirectClientInput} ShouldRedirectInput\n *\n * @typedef {object} ShouldRedirectResult\n * @property {boolean} shouldRedirect - Indicates whether the consumer should perform a redirect.\n * @property {Locale} locale - Locale resolved using the configured strategies.\n * @property {URL | undefined} redirectUrl - Destination URL when a redirect is required.\n */\n/**\n * Determines whether a redirect is required to align the current URL with the active locale.\n *\n * This helper mirrors the logic that powers `paraglideMiddleware`, but works in both server\n * and client environments. It evaluates the configured strategies in order, computes the\n * canonical localized URL, and reports when the current URL does not match.\n *\n * When called in the browser without arguments, the current `window.location.href` is used.\n *\n * @see https://paraglidejs.com/i18n-routing#redirects\n *\n * @example\n * // Client side usage (e.g. TanStack Router beforeLoad hook)\n * async function beforeLoad({ location }) {\n * const decision = await shouldRedirect({ url: location.href });\n *\n * if (decision.shouldRedirect) {\n * throw redirect({ to: decision.redirectUrl.href });\n * }\n * }\n *\n * @example\n * // Server side usage with a Request\n * export async function handle(request) {\n * const decision = await shouldRedirect({ request });\n *\n * if (decision.shouldRedirect) {\n * return Response.redirect(decision.redirectUrl, 307);\n * }\n *\n * return render(request, decision.locale);\n * }\n *\n * @example\n * // Server side usage behind a proxy where request.url is not public-facing\n * export async function handle(request) {\n * const effectiveRequestUrl = new URL(request.url);\n * effectiveRequestUrl.protocol = \"https:\";\n * effectiveRequestUrl.host = \"example.com\";\n *\n * const decision = await shouldRedirect({\n * request,\n * effectiveRequestUrl,\n * });\n *\n * if (decision.shouldRedirect) {\n * return Response.redirect(decision.redirectUrl, 307);\n * }\n * }\n *\n * @param {ShouldRedirectInput} [input]\n * @returns {Promise<ShouldRedirectResult>}\n */\nexport async function shouldRedirect(input = {}) {\n const currentUrl = resolveUrl(input);\n const locale = await resolveLocale(input, currentUrl);\n const strategy = getStrategyForUrl(currentUrl.href);\n if (isExcludedByRouteStrategy(currentUrl.href) || !strategy.includes(\"url\")) {\n return { shouldRedirect: false, locale, redirectUrl: undefined };\n }\n const localizedUrl = localizeUrl(currentUrl.href, { locale });\n const shouldRedirectToLocalizedUrl = normalizeUrl(localizedUrl.href) !== normalizeUrl(currentUrl.href);\n return {\n shouldRedirect: shouldRedirectToLocalizedUrl,\n locale,\n redirectUrl: shouldRedirectToLocalizedUrl ? localizedUrl : undefined,\n };\n}\n/**\n * Resolves the locale either from the provided input or by using the configured strategies.\n *\n * @param {ShouldRedirectInput} input\n * @param {URL} currentUrl\n * @returns {Promise<Locale>}\n */\nasync function resolveLocale(input, currentUrl) {\n const locale = toLocale(input.locale);\n if (locale) {\n return locale;\n }\n if (input.request) {\n return extractLocaleFromRequestAsync(input.request, {\n effectiveRequestUrl: currentUrl,\n });\n }\n if (\"url\" in input && typeof input.url !== \"undefined\") {\n return getLocaleForUrl(currentUrl.href);\n }\n return getLocale();\n}\n/**\n * Resolves the current URL from the provided input or runtime context.\n *\n * @param {ShouldRedirectInput} input\n * @returns {URL}\n */\nfunction resolveUrl(input) {\n if (\"effectiveRequestUrl\" in input &&\n input.effectiveRequestUrl instanceof URL) {\n return new URL(input.effectiveRequestUrl.href);\n }\n if (\"effectiveRequestUrl\" in input &&\n typeof input.effectiveRequestUrl === \"string\") {\n return new URL(input.effectiveRequestUrl, input.request ? input.request.url : getUrlOrigin());\n }\n if (input.request) {\n return new URL(input.request.url);\n }\n if (\"url\" in input && input.url instanceof URL) {\n return new URL(input.url.href);\n }\n if (\"url\" in input && typeof input.url === \"string\") {\n return new URL(input.url, getUrlOrigin());\n }\n if (typeof window !== \"undefined\" && window?.location?.href) {\n return new URL(window.location.href);\n }\n throw new Error(\"shouldRedirect() requires either a request, an absolute URL, or must run in a browser environment.\");\n}\n/**\n * Normalize url for comparison by stripping the trailing slash.\n *\n * @param {string} url\n * @returns {string}\n */\nfunction normalizeUrl(url) {\n const urlObj = new URL(url);\n if (trailingSlash === undefined) {\n urlObj.pathname = urlObj.pathname.replace(/\\/$/, \"\");\n }\n return urlObj.href;\n}\n\n/**\n * High-level URL localization function optimized for client-side UI usage.\n *\n * This is a convenience wrapper around `localizeUrl()` that provides features\n * needed in UI:\n *\n * - Accepts relative paths (e.g., \"/about\")\n * - Returns relative paths when possible\n * - Automatically detects current locale if not specified\n * - Handles string input/output instead of URL objects\n *\n * @see https://paraglidejs.com/i18n-routing\n *\n * @example\n * ```typescript\n * // In a React/Vue/Svelte component\n * const NavLink = ({ href }) => {\n * // Automatically uses current locale, keeps path relative\n * return <a href={localizeHref(href)}>...</a>;\n * };\n *\n * // Examples:\n * localizeHref(\"/about\")\n * // => \"/de/about\" (if current locale is \"de\")\n * localizeHref(\"/store\", { locale: \"fr\" })\n * // => \"/fr/store\" (explicit locale)\n *\n * // Cross-origin links remain absolute\n * localizeHref(\"https://other-site.com/about\")\n * // => \"https://other-site.com/de/about\"\n * ```\n *\n * For server-side URL localization (e.g., in middleware), use `localizeUrl()`\n * which provides more precise control over URL handling.\n *\n * @param {string} href - The href to localize (can be relative or absolute)\n * @param {object} [options] - Options for localization\n * @param {Locale} [options.locale] - Target locale. If not provided, uses `getLocale()`\n * @returns {string} The localized href, relative if input was relative\n */\nexport function localizeHref(href, options) {\n const currentLocale = getLocale();\n const locale = options?.locale ?? currentLocale;\n const url = new URL(href, getUrlOrigin());\n const localized = localizeUrl(url, { locale });\n // if the origin is identical and the href is relative,\n // return the relative path\n if (href.startsWith(\"/\") && url.origin === localized.origin) {\n // check for cross origin localization in which case an absolute URL must be returned.\n if (locale !== currentLocale) {\n const localizedCurrentLocale = localizeUrl(url, {\n locale: currentLocale,\n });\n if (localizedCurrentLocale.origin !== localized.origin) {\n return localized.href;\n }\n }\n return localized.pathname + localized.search + localized.hash;\n }\n return localized.href;\n}\n/**\n * High-level URL de-localization function optimized for client-side UI usage.\n *\n * This is a convenience wrapper around `deLocalizeUrl()` that provides features\n * needed in the UI:\n *\n * - Accepts relative paths (e.g., \"/de/about\")\n * - Returns relative paths when possible\n * - Handles string input/output instead of URL objects\n *\n * @see https://paraglidejs.com/i18n-routing\n *\n * @example\n * ```typescript\n * // In a React/Vue/Svelte component\n * const LocaleSwitcher = ({ href }) => {\n * // Remove locale prefix before switching\n * const baseHref = deLocalizeHref(href);\n * return locales.map(locale =>\n * <a href={localizeHref(baseHref, { locale })}>\n * Switch to {locale}\n * </a>\n * );\n * };\n *\n * // Examples:\n * deLocalizeHref(\"/de/about\") // => \"/about\"\n * deLocalizeHref(\"/fr/store\") // => \"/store\"\n *\n * // Cross-origin links remain absolute\n * deLocalizeHref(\"https://example.com/de/about\")\n * // => \"https://example.com/about\"\n * ```\n *\n * For server-side URL de-localization (e.g., in middleware), use `deLocalizeUrl()`\n * which provides more precise control over URL handling.\n *\n * @param {string} href - The href to de-localize (can be relative or absolute)\n * @returns {string} The de-localized href, relative if input was relative\n */\nexport function deLocalizeHref(href) {\n const url = new URL(href, getUrlOrigin());\n const deLocalized = deLocalizeUrl(url);\n // If the origin is identical and the href is relative,\n // return the relative path instead of the full URL.\n if (href.startsWith(\"/\") && url.origin === deLocalized.origin) {\n return deLocalized.pathname + deLocalized.search + deLocalized.hash;\n }\n return deLocalized.href;\n}\n\n/**\n * @param {string} safeModuleId\n * @param {Locale} locale\n */\nexport function trackMessageCall(safeModuleId, locale) {\n if (isServer === false)\n return;\n const store = serverAsyncLocalStorage?.getStore();\n if (store) {\n store.messageCalls?.add(`${safeModuleId}:${locale}`);\n }\n}\n\n/**\n * Generates localized URL variants for all provided URLs based on your configured locales and URL patterns.\n *\n * This function is essential for Static Site Generation (SSG) where you need to tell your framework\n * which pages to pre-render at build time. It's also useful for generating sitemaps and\n * `<link rel=\"alternate\" hreflang>` tags for SEO.\n *\n * The function respects your `urlPatterns` configuration - if you have translated pathnames\n * (e.g., `/about` → `/ueber-uns` for German), it will generate the correct localized paths.\n *\n * @see https://paraglidejs.com/static-site-generation\n *\n * @example\n * // Basic usage - generate all locale variants for a list of paths\n * const localizedUrls = generateStaticLocalizedUrls([\n * \"/\",\n * \"/about\",\n * \"/blog/post-1\",\n * ]);\n * // Returns URL objects for each locale:\n * // [\"/en/\", \"/de/\", \"/en/about\", \"/de/about\", \"/en/blog/post-1\", \"/de/blog/post-1\"]\n *\n * @example\n * // Use with framework SSG APIs\n * // SvelteKit\n * export function entries() {\n * const paths = [\"/\", \"/about\", \"/contact\"];\n * return generateStaticLocalizedUrls(paths).map(url => ({\n * locale: extractLocaleFromUrl(url)\n * }));\n * }\n *\n * @example\n * // Sitemap generation\n * const allPages = [\"/\", \"/about\", \"/blog\"];\n * const sitemapUrls = generateStaticLocalizedUrls(allPages);\n *\n * @param {(string | URL)[]} urls - List of canonical URLs or paths to generate localized versions for.\n * Can be absolute URLs (`https://example.com/about`) or paths (`/about`).\n * Paths are resolved against `http://localhost` internally.\n * @returns {URL[]} Array of URL objects representing all localized variants.\n * The order follows each input URL with all its locale variants before moving to the next URL.\n */\nexport function generateStaticLocalizedUrls(urls) {\n /** @type {Set<URL>} */\n const localizedUrls = new Set();\n // For default URL pattern, we can optimize the generation\n if (TREE_SHAKE_DEFAULT_URL_PATTERN_USED) {\n for (const urlInput of urls) {\n const originalUrl = urlInput instanceof URL\n ? urlInput\n : new URL(urlInput, \"http://localhost\");\n const url = trailingSlash === undefined\n ? originalUrl\n : normalizeTrailingSlash(new URL(originalUrl));\n // Base locale doesn't get a prefix\n localizedUrls.add(url);\n // Other locales get their code as prefix\n for (const locale of locales) {\n if (locale !== baseLocale) {\n const localizedPath = `/${locale}${url.pathname}${url.search}${url.hash}`;\n const localizedUrl = new URL(localizedPath, url.origin);\n localizedUrls.add(normalizeTrailingSlash(localizedUrl));\n }\n }\n }\n return Array.from(localizedUrls);\n }\n // For custom URL patterns, we need to use localizeUrl for each URL and locale\n for (const urlInput of urls) {\n const originalUrl = urlInput instanceof URL\n ? urlInput\n : new URL(urlInput, \"http://localhost\");\n const url = normalizeTrailingSlash(new URL(originalUrl));\n // Try each URL pattern to find one that matches\n let patternFound = false;\n for (const pattern of urlPatterns) {\n try {\n // Try to match the unlocalized pattern\n const unlocalizedMatch = execUrlPattern(new URLPattern(pattern.pattern, url.href), url);\n if (!unlocalizedMatch)\n continue;\n patternFound = true;\n // Track unique localized URLs to avoid duplicates when patterns are the same\n const seenUrls = new Set();\n // Generate localized URL for each locale\n for (const [locale] of pattern.localized) {\n try {\n const localizedUrl = localizeUrl(url, { locale });\n const urlString = localizedUrl.href;\n // Only add if we haven't seen this exact URL before\n if (!seenUrls.has(urlString)) {\n seenUrls.add(urlString);\n localizedUrls.add(localizedUrl);\n }\n }\n catch {\n // Skip if localization fails for this locale\n continue;\n }\n }\n break;\n }\n catch {\n // Skip if pattern matching fails\n continue;\n }\n }\n // If no pattern matched, use the URL as is\n if (!patternFound) {\n localizedUrls.add(originalUrl);\n }\n }\n return Array.from(localizedUrls);\n}\n\n/**\n * @typedef {\"cookie\" | \"baseLocale\" | \"globalVariable\" | \"url\" | \"preferredLanguage\" | \"localStorage\"} BuiltInStrategy\n */\n/**\n * @typedef {`custom_${string}`} CustomStrategy\n */\n/**\n * @typedef {BuiltInStrategy | CustomStrategy} Strategy\n */\n/**\n * @typedef {Array<Strategy>} Strategies\n */\n/**\n * @typedef {{ getLocale: (request?: Request) => Promise<string | undefined> | (string | undefined) }} CustomServerStrategyHandler\n */\n/**\n * @typedef {{ getLocale: () => Promise<string|undefined> | (string | undefined), setLocale: (locale: string) => Promise<void> | void }} CustomClientStrategyHandler\n */\n/** @type {Map<string, CustomServerStrategyHandler>} */\nexport const customServerStrategies = new Map();\n/** @type {Map<string, CustomClientStrategyHandler>} */\nexport const customClientStrategies = new Map();\n/**\n * Checks if the given strategy is a custom strategy.\n *\n * @param {unknown} strategy The name of the custom strategy to validate.\n * Must be a string that starts with \"custom-\" followed by alphanumeric characters, hyphens, or underscores.\n * @returns {boolean} Returns true if it is a custom strategy, false otherwise.\n */\nexport function isCustomStrategy(strategy) {\n return (typeof strategy === \"string\" && /^custom-[A-Za-z0-9_-]+$/.test(strategy));\n}\n/**\n * Defines a custom strategy that is executed on the server.\n *\n * @see https://paraglidejs.com/strategy#write-your-own-strategy\n *\n * @param {string} strategy The name of the custom strategy to define. Must follow the pattern custom-name with alphanumeric characters, hyphens, or underscores.\n * @param {CustomServerStrategyHandler} handler The handler for the custom strategy, which should implement\n * the method getLocale.\n * @returns {void}\n */\nexport function defineCustomServerStrategy(strategy, handler) {\n if (!isCustomStrategy(strategy)) {\n throw new Error(`Invalid custom strategy: \"${strategy}\". Must be a custom strategy following the pattern custom-name.`);\n }\n customServerStrategies.set(strategy, handler);\n}\n/**\n * Defines a custom strategy that is executed on the client.\n *\n * @see https://paraglidejs.com/strategy#write-your-own-strategy\n *\n * @param {string} strategy The name of the custom strategy to define. Must follow the pattern custom-name with alphanumeric characters, hyphens, or underscores.\n * @param {CustomClientStrategyHandler} handler The handler for the custom strategy, which should implement the\n * methods getLocale and setLocale.\n * @returns {void}\n */\nexport function defineCustomClientStrategy(strategy, handler) {\n if (!isCustomStrategy(strategy)) {\n throw new Error(`Invalid custom strategy: \"${strategy}\". Must be a custom strategy following the pattern custom-name.`);\n }\n customClientStrategies.set(strategy, handler);\n}\n\n// ------ TYPES ------\nexport {};\n/**\n * A locale that is available in the project.\n *\n * @example\n * setLocale(request.locale as Locale)\n *\n * @typedef {typeof locales[number]} Locale\n */\n/**\n * A branded type representing a localized string.\n *\n * Message functions return this type instead of \\`string\\`, enabling TypeScript\n * to distinguish translated strings from regular strings at compile time.\n * This allows you to enforce that only properly localized content is used\n * in your UI components.\n *\n * Since \\`LocalizedString\\` is a branded subtype of \\`string\\`, it remains fully\n * backward compatible—you can pass it anywhere a \\`string\\` is expected.\n *\n * @example\n * // Enforce localized strings in your components\n * function PageTitle(props: { title: LocalizedString }) {\n * return <h1>{props.title}</h1>\n * }\n *\n * // ✅ Correct: using a message function\n * <PageTitle title={m.welcome_title()} />\n *\n * // ❌ Type error: raw strings are not LocalizedString\n * <PageTitle title=\"Welcome\" />\n *\n * @example\n * // LocalizedString is assignable to string (backward compatible)\n * const localized: LocalizedString = m.greeting()\n * const str: string = localized // ✅ works fine\n *\n * // But string is not assignable to LocalizedString\n * const raw: LocalizedString = \"Hello\" // ❌ Type error\n *\n * @example\n * // Catches accidental string concatenation\n * function showMessage(msg: LocalizedString) { ... }\n *\n * showMessage(m.hello()) // ✅\n * showMessage(\"Hello \" + userName) // ❌ Type error\n * showMessage(m.hello_user({ name: userName })) // ✅ use params instead\n *\n * @typedef {string & { readonly __brand: 'LocalizedString' }} LocalizedString\n */\n/**\n * A single markup option passed to a tag instance.\n *\n * @typedef {{\n * name: string;\n * value: unknown;\n * }} MessageMarkupOption\n */\n/**\n * A single static markup attribute attached to a tag instance.\n *\n * @typedef {{\n * name: string;\n * value: string | true;\n * }} MessageMarkupAttribute\n */\n/**\n * Record of markup options for a tag instance.\n *\n * @typedef {Record<string, unknown>} MessageMarkupOptions\n */\n/**\n * Record of markup attributes for a tag instance.\n *\n * @typedef {Record<string, string | true>} MessageMarkupAttributes\n */\n/**\n * Type-level schema for a single markup tag.\n *\n * @typedef {{\n * options: MessageMarkupOptions;\n * attributes: MessageMarkupAttributes;\n * children: boolean;\n * }} MessageMarkupTag\n */\n/**\n * Type-level schema for all markup tags in a message.\n *\n * @typedef {Record<string, MessageMarkupTag>} MessageMarkupSchema\n */\n/**\n * Type-only metadata attached to compiled message functions.\n *\n * @template Inputs\n * @template Options\n * @template {MessageMarkupSchema} [Markup = MessageMarkupSchema]\n * @typedef {{\n * readonly __paraglide?: {\n * inputs: Inputs;\n * options: Options;\n * markup: Markup;\n * };\n * }} MessageMetadata\n */\n/**\n * A compiled, framework-neutral message part.\n *\n * @typedef {{\n * type: \"text\";\n * value: string;\n * } | {\n * type: \"markup-start\";\n * name: string;\n * options: MessageMarkupOptions;\n * attributes: MessageMarkupAttributes;\n * } | {\n * type: \"markup-end\";\n * name: string;\n * options: MessageMarkupOptions;\n * attributes: MessageMarkupAttributes;\n * } | {\n * type: \"markup-standalone\";\n * name: string;\n * options: MessageMarkupOptions;\n * attributes: MessageMarkupAttributes;\n * }} MessagePart\n */\n/**\n * A message function is a message for a specific locale.\n *\n * @example\n * m.hello({ name: 'world' })\n *\n * @typedef {(inputs?: Record<string, never>) => LocalizedString} MessageFunction\n */\n/**\n * A message bundle function that selects the message to be returned.\n *\n * Uses `getLocale()` under the hood to determine the locale with an option.\n *\n * @template {string} T\n *\n * @example\n * * m.hello({ name: 'world' }, { locale: \"en\" })\n *\n * @typedef {(params: Record<string, never>, options: { locale: T }) => LocalizedString} MessageBundleFunction\n */\n"],"mappings":"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"}
1
+ {"version":3,"file":"runtime.js","names":[],"sources":["../../src/paraglide/runtime.js"],"sourcesContent":["/* eslint-disable */\n\n/** @type {any} */\nconst URLPattern = {}\n\n/**\n * The project's base locale.\n *\n * @example\n * if (locale === baseLocale) {\n * // do something\n * }\n */\nexport const baseLocale = \"en-gb\";\n/**\n * The project's locales that have been specified in the settings.\n *\n * @example\n * if (locales.includes(userSelectedLocale) === false) {\n * throw new Error('Locale is not available');\n * }\n */\nexport const locales = /** @type {const} */ ([\"en-gb\",\"nb\"]);\n/** @type {string} */\nexport const cookieName = \"PARAGLIDE_LOCALE\";\n/** @type {number} */\nexport const cookieMaxAge = 34560000;\n/** @type {string} */\nexport const cookieDomain = \"\";\n/** @type {string} */\nexport const localStorageKey = \"PARAGLIDE_LOCALE\";\n/**\n * @type {Array<\"cookie\" | \"baseLocale\" | \"globalVariable\" | \"url\" | \"preferredLanguage\" | \"localStorage\" | `custom-${string}`>}\n */\nexport const strategy = [\n \"globalVariable\",\n \"baseLocale\"\n];\n/**\n * Route-level strategy overrides.\n *\n * `match` uses URLPattern syntax.\n *\n * @type {Array<{\n * match: string;\n * strategy?: Array<\"cookie\" | \"baseLocale\" | \"globalVariable\" | \"url\" | \"preferredLanguage\" | \"localStorage\" | `custom-${string}`>;\n * exclude?: boolean;\n * }>}\n */\nexport const routeStrategies = [];\n/**\n * The used URL patterns.\n *\n * @type {Array<{ pattern: string, localized: Array<[Locale, string]> }>}\n */\nexport const urlPatterns = [\n {\n \"pattern\": \":protocol://:domain(.*)::port?/:path(.*)?\",\n \"localized\": [\n [\n \"nb\",\n \":protocol://:domain(.*)::port?/nb/:path(.*)?\"\n ],\n [\n \"en-gb\",\n \":protocol://:domain(.*)::port?/:path(.*)?\"\n ]\n ]\n }\n];\n/**\n * Controls trailing slash canonicalization for localized URLs.\n *\n * @type {\"always\" | \"never\" | undefined}\n */\nexport const trailingSlash = undefined;\n/**\n * @typedef {{\n * \t\tgetStore(): {\n * \t\tlocale?: Locale,\n * \t\t\torigin?: string,\n * \t\t\tmessageCalls?: Set<string>\n * \t} | undefined,\n * \t\trun: (store: { locale?: Locale, origin?: string, messageCalls?: Set<string>},\n * cb: any) => any\n * }} ParaglideAsyncLocalStorage\n */\n/**\n * Server side async local storage that is set by `serverMiddleware()`.\n *\n * The variable is used to retrieve the locale and origin in a server-side\n * rendering context without effecting other requests.\n *\n * @type {ParaglideAsyncLocalStorage | undefined}\n */\nexport let serverAsyncLocalStorage = undefined;\n/**\n * Returns the current server-side async local storage instance.\n *\n * Accessing the mutable value through a function keeps it observable when\n * module interceptors wrap exported bindings and snapshot their initial value.\n *\n * @returns {ParaglideAsyncLocalStorage | undefined}\n */\nexport function getServerAsyncLocalStorage() {\n return serverAsyncLocalStorage;\n}\nexport const disableAsyncLocalStorage = false;\nexport const experimentalMiddlewareLocaleSplitting = false;\nexport const isServer = typeof window === 'undefined';\n/** @type {Locale | undefined} */\nexport const experimentalStaticLocale = undefined;\n/**\n * Sets the server side async local storage.\n *\n * The function is needed because the `runtime.js` file\n * must define the `serverAsyncLocalStorage` variable to\n * avoid a circular import between `runtime.js` and\n * `server.js` files.\n *\n * @param {ParaglideAsyncLocalStorage | undefined} value\n */\nexport function overwriteServerAsyncLocalStorage(value) {\n serverAsyncLocalStorage = value;\n}\nconst TREE_SHAKE_COOKIE_STRATEGY_USED = false;\nconst TREE_SHAKE_URL_STRATEGY_USED = false;\nconst TREE_SHAKE_GLOBAL_VARIABLE_STRATEGY_USED = true;\nconst TREE_SHAKE_PREFERRED_LANGUAGE_STRATEGY_USED = false;\nconst TREE_SHAKE_DEFAULT_URL_PATTERN_USED = true;\nconst TREE_SHAKE_LOCAL_STORAGE_STRATEGY_USED = false;\n\n/** @type {any} */ (globalThis).__paraglide =\n\t/** @type {any} */ (globalThis).__paraglide ?? {};\n/** @type {any} */ (globalThis).__paraglide.ssr =\n\t/** @type {any} */ (globalThis).__paraglide.ssr ?? {};\n\n/**\n * This is a fallback to get started with a custom\n * strategy and avoid type errors.\n *\n * The implementation is overwritten\n * by `overwriteGetLocale()` and `defineSetLocale()`.\n *\n * @type {Locale | undefined}\n */\nlet _locale;\nlet localeInitiallySet = false;\n/**\n * Get the current locale.\n *\n * The locale is resolved using your configured strategies (URL, cookie, localStorage, etc.)\n * in the order they are defined. In SSR contexts, the locale is retrieved from AsyncLocalStorage\n * which is set by the `paraglideMiddleware()`.\n *\n * @see https://paraglidejs.com/strategy - Configure locale detection strategies\n *\n * @example\n * if (getLocale() === 'de') {\n * console.log('Germany 🇩🇪');\n * } else if (getLocale() === 'nl') {\n * console.log('Netherlands 🇳🇱');\n * }\n *\n * @returns {Locale} The current locale.\n */\nexport let getLocale = () => {\n if (experimentalStaticLocale !== undefined) {\n return experimentalStaticLocale;\n }\n // if running in a server-side rendering context\n // retrieve the locale from the async local storage\n if (serverAsyncLocalStorage) {\n const locale = serverAsyncLocalStorage?.getStore()?.locale;\n if (locale) {\n return locale;\n }\n }\n let strategyToUse = strategy;\n if (!isServer && typeof window !== \"undefined\" && window.location?.href) {\n strategyToUse = getStrategyForUrl(window.location.href);\n }\n const resolved = resolveLocaleWithStrategies(strategyToUse, typeof window !== \"undefined\" ? window.location?.href : undefined);\n if (resolved) {\n if (!localeInitiallySet) {\n _locale = resolved;\n // https://github.com/opral/inlang-paraglide-js/issues/455\n localeInitiallySet = true;\n setLocale(resolved, { reload: false });\n }\n return resolved;\n }\n throw new Error(\"No locale found. Read the docs https://paraglidejs.com/errors#no-locale-found\");\n};\n/**\n * Resolve locale for a given URL using route-aware strategies.\n *\n * @param {string | URL} url\n * @returns {Locale}\n */\nexport function getLocaleForUrl(url) {\n if (experimentalStaticLocale !== undefined) {\n return experimentalStaticLocale;\n }\n const strategyToUse = getStrategyForUrl(url);\n const resolved = resolveLocaleWithStrategies(strategyToUse, typeof url === \"string\" ? url : url.href);\n if (resolved) {\n return resolved;\n }\n throw new Error(\"No locale found. Read the docs https://paraglidejs.com/errors#no-locale-found\");\n}\n/**\n * @param {typeof strategy} strategyToUse\n * @param {string | undefined} urlForUrlStrategy\n * @returns {Locale | undefined}\n */\nfunction resolveLocaleWithStrategies(strategyToUse, urlForUrlStrategy) {\n /** @type {string | undefined} */\n let locale;\n for (const strat of strategyToUse) {\n if (TREE_SHAKE_COOKIE_STRATEGY_USED && strat === \"cookie\") {\n locale = extractLocaleFromCookie();\n }\n else if (strat === \"baseLocale\") {\n locale = baseLocale;\n }\n else if (TREE_SHAKE_URL_STRATEGY_USED &&\n strat === \"url\" &&\n !isServer &&\n typeof urlForUrlStrategy === \"string\") {\n locale = extractLocaleFromUrl(urlForUrlStrategy);\n }\n else if (TREE_SHAKE_GLOBAL_VARIABLE_STRATEGY_USED &&\n strat === \"globalVariable\" &&\n _locale !== undefined) {\n locale = _locale;\n }\n else if (TREE_SHAKE_PREFERRED_LANGUAGE_STRATEGY_USED &&\n strat === \"preferredLanguage\" &&\n !isServer) {\n locale = extractLocaleFromNavigator();\n }\n else if (TREE_SHAKE_LOCAL_STORAGE_STRATEGY_USED &&\n strat === \"localStorage\" &&\n !isServer) {\n locale = localStorage.getItem(localStorageKey) ?? undefined;\n }\n else if (isCustomStrategy(strat) && customClientStrategies.has(strat)) {\n const handler = customClientStrategies.get(strat);\n if (handler) {\n const result = handler.getLocale();\n // Handle both sync and async results - skip async in sync getLocale\n if (result instanceof Promise) {\n // Can't await in sync function, skip async strategies\n continue;\n }\n if (result !== undefined) {\n return assertIsLocale(result);\n }\n }\n }\n const matchedLocale = toLocale(locale);\n if (matchedLocale) {\n return matchedLocale;\n }\n }\n return undefined;\n}\n/**\n * Overwrite the `getLocale()` function.\n *\n * Use this function to overwrite how the locale is resolved. This is useful\n * for custom locale resolution or advanced use cases like SSG with concurrent rendering.\n *\n * @see https://paraglidejs.com/strategy\n *\n * @example\n * overwriteGetLocale(() => {\n * return Cookies.get('locale') ?? baseLocale\n * });\n *\n * @param {() => Locale} fn - The new implementation for `getLocale()`.\n */\nexport const overwriteGetLocale = (fn) => {\n getLocale = fn;\n};\n\nconst rtlLanguages = new Set([\n \"ar\",\n \"dv\",\n \"fa\",\n \"he\",\n \"ks\",\n \"ku\",\n \"ps\",\n \"sd\",\n \"ug\",\n \"ur\",\n \"yi\",\n]);\n/**\n * Get writing direction for a locale.\n *\n * Uses `Intl.Locale` text info when available and falls back to a\n * language-based RTL check for runtimes without `getTextInfo()`.\n *\n * @example\n * getTextDirection(); // \"ltr\" or \"rtl\" for current locale\n * getTextDirection(\"ar\"); // \"rtl\"\n * getTextDirection(\"en\"); // \"ltr\"\n *\n * @param {string} [locale] - Target locale. If not provided, uses `getLocale()`\n * @returns {\"ltr\" | \"rtl\"}\n */\nexport function getTextDirection(locale = getLocale()) {\n try {\n const intlLocale = /** @type {Intl.Locale & {\n getTextInfo?: () => { direction?: string };\n textInfo?: { direction?: string };\n }} */ (new Intl.Locale(locale));\n const direction = intlLocale.getTextInfo?.().direction ?? intlLocale.textInfo?.direction;\n if (direction === \"ltr\" || direction === \"rtl\") {\n return direction;\n }\n }\n catch {\n // Ignore Intl.Locale parsing/runtime errors and use fallback below.\n }\n const language = locale.split(\"-\")[0]?.toLowerCase();\n return rtlLanguages.has(language ?? \"\") ? \"rtl\" : \"ltr\";\n}\n\n/**\n * Navigates to the localized URL, or reloads the current page\n *\n * @param {string} [newLocation] The new location\n */\nconst navigateOrReload = (newLocation) => {\n if (newLocation) {\n // reload the page by navigating to the new url\n window.location.href = newLocation;\n }\n else {\n // reload the page to reflect the new locale\n window.location.reload();\n }\n};\n/**\n * @typedef {(newLocale: Locale, options?: { reload?: boolean }) => void | Promise<void>} SetLocaleFn\n */\n/**\n * Set the locale.\n *\n * Updates the locale using your configured strategies (cookie, localStorage, URL, etc.).\n * By default, this navigates the client to the localized URL or reloads the current\n * document to reflect the new locale. `reload: false` is a narrow browser-only escape\n * hatch for a fully client-rendered, non-URL-routed surface that owns its reactive\n * updates and document state. It does not re-render the UI or update the document.\n * Do not use it for normal locale pickers, URL-routed pages, or switching an SSR,\n * SSG, or hydrated document. It is incompatible with per-locale builds.\n *\n * If any custom strategy's `setLocale` function is async, then this function\n * will become async as well.\n *\n * @see https://paraglidejs.com/strategy\n *\n * @example\n * setLocale('en');\n *\n * @example\n * setLocale('en', { reload: false });\n *\n * @type {SetLocaleFn}\n */\nexport let setLocale = (newLocale, options) => {\n const optionsWithDefaults = {\n reload: true,\n ...options,\n };\n if (experimentalStaticLocale !== undefined &&\n newLocale !== experimentalStaticLocale &&\n optionsWithDefaults.reload === false) {\n console.warn(`Paraglide: setLocale(${JSON.stringify(newLocale)}, { reload: false }) cannot switch away from the statically built locale ${JSON.stringify(experimentalStaticLocale)}. A document navigation is required; reload has been forced to true.`);\n optionsWithDefaults.reload = true;\n }\n // locale is already set\n // https://github.com/opral/inlang-paraglide-js/issues/430\n /** @type {Locale | undefined} */\n let currentLocale;\n try {\n currentLocale = getLocale();\n }\n catch {\n // do nothing, no locale has been set yet.\n }\n /** @type {Array<Promise<void>>} */\n const customSetLocalePromises = [];\n /** @type {string | undefined} */\n let newLocation = undefined;\n let strategyToUse = strategy;\n if (!isServer && typeof window !== \"undefined\" && window.location?.href) {\n strategyToUse = getStrategyForUrl(window.location.href);\n }\n for (const strat of strategyToUse) {\n if (TREE_SHAKE_GLOBAL_VARIABLE_STRATEGY_USED &&\n strat === \"globalVariable\") {\n // a default for a custom strategy to get started quickly\n // is likely overwritten by `defineSetLocale()`\n _locale = newLocale;\n }\n else if (TREE_SHAKE_COOKIE_STRATEGY_USED && strat === \"cookie\") {\n if (isServer ||\n typeof document === \"undefined\" ||\n typeof window === \"undefined\") {\n continue;\n }\n // set the cookie\n const cookieString = `${cookieName}=${newLocale}; path=/; max-age=${cookieMaxAge}`;\n document.cookie = cookieDomain\n ? `${cookieString}; domain=${cookieDomain}`\n : cookieString;\n clearLocaleCookieCache();\n }\n else if (strat === \"baseLocale\") {\n // nothing to be set here. baseLocale is only a fallback\n continue;\n }\n else if (TREE_SHAKE_URL_STRATEGY_USED &&\n strat === \"url\" &&\n typeof window !== \"undefined\") {\n // route to the new url\n //\n // this triggers a page reload but a user rarely\n // switches locales, so this should be fine.\n //\n // if the behavior is not desired, the implementation\n // can be overwritten by `defineSetLocale()` to avoid\n // a full page reload.\n newLocation = localizeUrl(window.location.href, {\n locale: newLocale,\n }).href;\n }\n else if (TREE_SHAKE_LOCAL_STORAGE_STRATEGY_USED &&\n strat === \"localStorage\" &&\n typeof window !== \"undefined\") {\n // set the localStorage\n localStorage.setItem(localStorageKey, newLocale);\n }\n else if (isCustomStrategy(strat) && customClientStrategies.has(strat)) {\n const handler = customClientStrategies.get(strat);\n if (handler) {\n let result = handler.setLocale(newLocale);\n // Handle async setLocale\n if (result instanceof Promise) {\n result = result.catch((error) => {\n throw new Error(`Custom strategy \"${strat}\" setLocale failed.`, {\n cause: error,\n });\n });\n customSetLocalePromises.push(result);\n }\n }\n }\n }\n const runReload = () => {\n if (!isServer &&\n optionsWithDefaults.reload &&\n window.location &&\n newLocale !== currentLocale) {\n navigateOrReload(newLocation);\n }\n };\n if (customSetLocalePromises.length) {\n return Promise.all(customSetLocalePromises).then(() => {\n runReload();\n });\n }\n runReload();\n return;\n};\n/**\n * Overwrite the `setLocale()` function.\n *\n * Use this function to overwrite how the locale is set. For example,\n * modify a cookie, env variable, or a user's preference.\n *\n * @example\n * overwriteSetLocale((newLocale) => {\n * // set the locale in a cookie\n * return Cookies.set('locale', newLocale)\n * });\n *\n * @param {SetLocaleFn} fn\n */\nexport const overwriteSetLocale = (fn) => {\n setLocale = fn;\n};\n\n/**\n * The origin of the current URL.\n *\n * Defaults to \"http://example.com\" in non-browser environments. If this\n * behavior is not desired, the implementation can be overwritten\n * by `overwriteGetUrlOrigin()`.\n *\n * @type {() => string}\n */\nexport let getUrlOrigin = () => {\n if (serverAsyncLocalStorage) {\n return serverAsyncLocalStorage.getStore()?.origin ?? \"http://fallback.com\";\n }\n else if (typeof window !== \"undefined\") {\n return window.location.origin;\n }\n return \"http://fallback.com\";\n};\n/**\n * Overwrite the getUrlOrigin function.\n *\n * Use this function in server environments to\n * define how the URL origin is resolved.\n *\n * @param {() => string} fn - The new implementation for `getUrlOrigin()`.\n */\nexport let overwriteGetUrlOrigin = (fn) => {\n getUrlOrigin = fn;\n};\n\n/**\n * Coerces a locale-like string to the canonical locale value used by the runtime.\n *\n * @param {unknown} value\n * @returns {Locale | undefined}\n */\nexport function toLocale(value) {\n if (typeof value !== \"string\") {\n return undefined;\n }\n const lowerValue = value.toLowerCase();\n for (const locale of locales) {\n if (locale.toLowerCase() === lowerValue) {\n return locale;\n }\n }\n return undefined;\n}\n/**\n * Check if something is an available locale with the canonical project casing.\n *\n * @example\n * if (isLocale(params.locale)) {\n * setLocale(params.locale);\n * } else {\n * setLocale('en');\n * }\n *\n * Use `toLocale()` when you want case-insensitive matching and canonicalization.\n *\n * @param {unknown} locale\n * @returns {locale is Locale}\n */\nexport function isLocale(locale) {\n return !!locale && locales.some((item) => item === locale);\n}\n/**\n * Asserts that the input can be normalized to a locale.\n *\n * @param {unknown} input - The input to check.\n * @returns {Locale} The input normalized to a Locale.\n * @throws {Error} If the input is not a locale.\n */\nexport function assertIsLocale(input) {\n const locale = toLocale(input);\n if (locale)\n return locale;\n throw new Error(`Invalid locale: ${input}. Expected one of: ${locales.join(\", \")}`);\n}\n\n/**\n * Applies the configured trailing slash policy to a URL.\n *\n * The root pathname always remains `/`. Query parameters and hashes are not\n * modified.\n *\n * @param {URL} url\n * @returns {URL}\n */\nfunction normalizeTrailingSlash(url) {\n if (trailingSlash === undefined || url.pathname === \"/\") {\n return url;\n }\n if (trailingSlash === \"never\") {\n url.pathname = url.pathname.replace(/\\/+$/, \"\") || \"/\";\n }\n else if (trailingSlash === \"always\") {\n url.pathname = url.pathname.replace(/\\/+$/, \"\") + \"/\";\n }\n return url;\n}\n\n/**\n * Matches a canonical URL while allowing configured patterns to retain their\n * existing trailing slash style.\n *\n * @param {URLPattern} pattern\n * @param {URL} url\n * @returns {any}\n */\nfunction execUrlPattern(pattern, url) {\n if (trailingSlash === undefined || url.pathname === \"/\") {\n return pattern.exec(url.href);\n }\n const alias = new URL(url);\n if (trailingSlash === \"always\") {\n alias.pathname = alias.pathname.replace(/\\/+$/, \"\") || \"/\";\n // Prefer the slashless alias so the canonical slash does not become part\n // of a terminal wildcard capture.\n return pattern.exec(alias.href) ?? pattern.exec(url.href);\n }\n else if (trailingSlash === \"never\") {\n const match = pattern.exec(url.href);\n if (match) {\n return match;\n }\n alias.pathname = alias.pathname.replace(/\\/+$/, \"\") + \"/\";\n return pattern.exec(alias.href);\n }\n return pattern.exec(url.href);\n}\n\n/**\n * @typedef {object} ExtractLocaleFromRequestOptions\n * @property {string | URL} [effectiveRequestUrl] - Effective request URL to use for route matching and locale detection with the URL strategy.\n */\n/**\n * Extracts a locale from a request.\n *\n * Use the function on the server to extract the locale\n * from a request.\n *\n * The function goes through the strategies in the order\n * they are defined. If a strategy returns an invalid locale,\n * it will fall back to the next strategy.\n *\n * Note: Custom server strategies are not supported in this synchronous version.\n * Use `extractLocaleFromRequestAsync` if you need custom server strategies with async getLocale methods.\n *\n * @example\n * const locale = extractLocaleFromRequest(request);\n *\n * @param {Request} request\n * @param {ExtractLocaleFromRequestOptions} [options]\n * @returns {Locale}\n */\nexport const extractLocaleFromRequest = (request, options = {}) => {\n const effectiveRequestUrl = resolveEffectiveRequestUrl(request, options.effectiveRequestUrl);\n return extractLocaleFromRequestWithStrategies(request, getStrategyForUrl(effectiveRequestUrl), effectiveRequestUrl);\n};\n/**\n * Extracts a locale from a request using the provided strategy order.\n *\n * @param {Request} request\n * @param {typeof strategy} strategies\n * @param {string | URL} [url]\n * @returns {Locale}\n */\nexport const extractLocaleFromRequestWithStrategies = (request, strategies, url = request.url) => {\n const effectiveRequestUrl = resolveEffectiveRequestUrl(request, url);\n /** @type {string|undefined} */\n let locale;\n for (const strat of strategies) {\n if (TREE_SHAKE_COOKIE_STRATEGY_USED && strat === \"cookie\") {\n const cookiePrefix = cookieName + \"=\";\n locale = request.headers\n .get(\"cookie\")\n ?.split(\";\")\n .map((c) => c.trim())\n .find((c) => c.startsWith(cookiePrefix))\n ?.slice(cookiePrefix.length);\n }\n else if (TREE_SHAKE_URL_STRATEGY_USED && strat === \"url\") {\n locale = extractLocaleFromUrl(effectiveRequestUrl);\n }\n else if (TREE_SHAKE_PREFERRED_LANGUAGE_STRATEGY_USED &&\n strat === \"preferredLanguage\") {\n locale = extractLocaleFromHeader(request);\n }\n else if (strat === \"globalVariable\") {\n locale = _locale;\n }\n else if (strat === \"baseLocale\") {\n return baseLocale;\n }\n else if (strat === \"localStorage\") {\n continue;\n }\n else if (isCustomStrategy(strat)) {\n // Custom strategies are not supported in sync version\n // Use extractLocaleFromRequestAsync for custom server strategies\n continue;\n }\n const matchedLocale = toLocale(locale);\n if (matchedLocale) {\n return matchedLocale;\n }\n }\n 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://paraglidejs.com/errors#no-locale-found\");\n};\n/**\n * @param {Request} request\n * @param {string | URL | undefined} effectiveRequestUrl\n * @returns {URL}\n */\nfunction resolveEffectiveRequestUrl(request, effectiveRequestUrl = request.url) {\n if (effectiveRequestUrl instanceof URL) {\n return new URL(effectiveRequestUrl.href);\n }\n return new URL(effectiveRequestUrl, request.url);\n}\n\n/**\n * Asynchronously extracts a locale from a request.\n *\n * This function supports async custom server strategies, unlike the synchronous\n * `extractLocaleFromRequest`. Use this function when you have custom server strategies\n * that need to perform asynchronous operations (like database calls) in their getLocale method.\n *\n * The function first processes any custom server strategies asynchronously, then falls back\n * to the synchronous `extractLocaleFromRequest` for all other strategies.\n *\n * @see {@link https://github.com/opral/inlang-paraglide-js/issues/527#issuecomment-2978151022}\n *\n * @example\n * // Basic usage\n * const locale = await extractLocaleFromRequestAsync(request);\n *\n * @example\n * // With custom async server strategy\n * defineCustomServerStrategy(\"custom-database\", {\n * getLocale: async (request) => {\n * const userId = extractUserIdFromRequest(request);\n * return await getUserLocaleFromDatabase(userId);\n * }\n * });\n *\n * const locale = await extractLocaleFromRequestAsync(request);\n *\n * @param {Request} request - The request object to extract the locale from.\n * @param {{ effectiveRequestUrl?: string | URL }} [options] - Effective request URL to use for route matching and locale detection with the URL strategy.\n * @returns {Promise<Locale>} The extracted locale.\n */\nexport const extractLocaleFromRequestAsync = async (request, options = {}) => {\n /** @type {string|undefined} */\n let locale;\n const effectiveRequestUrl = resolveEffectiveRequestUrlFromRequestAsync(request, options.effectiveRequestUrl);\n const strategy = getStrategyForUrl(effectiveRequestUrl);\n // Process custom strategies first, in order\n for (const strat of strategy) {\n if (isCustomStrategy(strat) && customServerStrategies.has(strat)) {\n const handler = customServerStrategies.get(strat);\n if (handler) {\n /** @type {string|undefined} */\n locale = await handler.getLocale(request);\n }\n // If we got a valid locale from this custom strategy, use it\n const matchedLocale = toLocale(locale);\n if (matchedLocale) {\n return matchedLocale;\n }\n }\n }\n // If no custom strategy provided a valid locale, fall back to sync version\n return extractLocaleFromRequestWithStrategies(request, strategy, effectiveRequestUrl);\n};\n/**\n * @param {Request} request\n * @param {string | URL | undefined} effectiveRequestUrl\n * @returns {URL}\n */\nfunction resolveEffectiveRequestUrlFromRequestAsync(request, effectiveRequestUrl = request.url) {\n if (effectiveRequestUrl instanceof URL) {\n return new URL(effectiveRequestUrl.href);\n }\n return new URL(effectiveRequestUrl, request.url);\n}\n\nconst cookieNamePattern = cookieName.replace(/[.*+?^${}()|[\\]\\\\]/g, \"\\\\$&\");\nconst localeCookiePattern = new RegExp(`(?:^|;\\\\s*)${cookieNamePattern}=([^;]*)`);\nconst noCachedLocale = Symbol();\n/** @type {Locale | undefined | typeof noCachedLocale} */\nlet cachedLocaleFromCookie = noCachedLocale;\n/**\n * Clears the cached locale from `document.cookie`.\n */\nfunction clearLocaleCookieCache() {\n cachedLocaleFromCookie = noCachedLocale;\n}\nfunction scheduleLocaleCookieCacheClear() {\n if (typeof queueMicrotask === \"function\") {\n queueMicrotask(clearLocaleCookieCache);\n }\n else {\n Promise.resolve().then(clearLocaleCookieCache);\n }\n}\n/**\n * Extracts a cookie from the document.\n *\n * Will return undefined if the document is not available or if the cookie is not set.\n * The `document` object is not available in server-side rendering, so this function should not be called in that context.\n *\n * @returns {Locale | undefined}\n */\nexport function extractLocaleFromCookie() {\n if (typeof document === \"undefined\") {\n return;\n }\n if (cachedLocaleFromCookie !== noCachedLocale) {\n return cachedLocaleFromCookie;\n }\n const match = document.cookie.match(localeCookiePattern);\n const locale = match?.[1];\n cachedLocaleFromCookie = toLocale(locale);\n scheduleLocaleCookieCacheClear();\n return cachedLocaleFromCookie;\n}\n\n/**\n * Extracts a locale from the accept-language header.\n *\n * Use the function on the server to extract the locale\n * from the accept-language header that is sent by the client.\n *\n * @example\n * const locale = extractLocaleFromHeader(request);\n *\n * @param {Request} request - The request object to extract the locale from.\n * @returns {Locale | undefined} The negotiated preferred language.\n */\nexport function extractLocaleFromHeader(request) {\n const acceptLanguageHeader = request.headers.get(\"accept-language\");\n if (acceptLanguageHeader) {\n // Parse language preferences with their q-values and base language codes\n const languages = acceptLanguageHeader\n .split(\",\")\n .map((lang) => {\n const [tag, q = \"1\"] = lang.trim().split(\";q=\");\n // Get both the full tag and base language code\n const baseTag = tag?.split(\"-\")[0];\n return {\n fullTag: tag,\n baseTag,\n q: Number(q),\n };\n })\n .sort((a, b) => b.q - a.q);\n for (const lang of languages) {\n const fullLocale = toLocale(lang.fullTag);\n if (fullLocale) {\n return fullLocale;\n }\n const baseLocale = toLocale(lang.baseTag);\n if (baseLocale) {\n return baseLocale;\n }\n }\n return undefined;\n }\n return undefined;\n}\n\n/**\n * Negotiates a preferred language from navigator.languages.\n *\n * Use the function on the client to extract the locale\n * from the navigator.languages array.\n *\n * @example\n * const locale = extractLocaleFromNavigator();\n *\n * @returns {Locale | undefined}\n */\nexport function extractLocaleFromNavigator() {\n if (!navigator?.languages?.length) {\n return undefined;\n }\n const languages = navigator.languages.map((lang) => ({\n fullTag: lang,\n baseTag: lang.split(\"-\")[0],\n }));\n for (const lang of languages) {\n const fullLocale = toLocale(lang.fullTag);\n if (fullLocale) {\n return fullLocale;\n }\n const baseLocale = toLocale(lang.baseTag);\n if (baseLocale) {\n return baseLocale;\n }\n }\n return undefined;\n}\n\n/**\n * If extractLocaleFromUrl is called many times on the same page and the URL\n * hasn't changed, we don't need to recompute it every time which can get expensive.\n * We might use a LRU cache if needed, but for now storing only the last result is enough.\n * https://github.com/opral/monorepo/pull/3575#discussion_r2066731243\n */\n/** @type {string|undefined} */\nlet cachedUrl;\n/** @type {Locale|undefined} */\nlet cachedLocale;\n/**\n * Extracts the locale from a given URL using native URLPattern.\n *\n * The built-in default `/:locale/...` routing is case-insensitive because it\n * canonicalizes the first path segment with `toLocale()`. Custom `urlPatterns`\n * keep URLPattern's normal exact matching semantics for path segments.\n *\n * @param {URL|string} url - The full URL from which to extract the locale.\n * @returns {Locale|undefined} The extracted locale, or undefined if no locale is found.\n */\nexport function extractLocaleFromUrl(url) {\n const urlString = typeof url === \"string\" ? url : url.href;\n if (cachedUrl === urlString) {\n return cachedLocale;\n }\n /** @type {Locale | undefined} */\n let result;\n if (TREE_SHAKE_DEFAULT_URL_PATTERN_USED) {\n const urlObj = typeof url === \"string\"\n ? new URL(url, \"http://example.com\")\n : new URL(url);\n result = defaultUrlPatternExtractLocale(normalizeTrailingSlash(urlObj));\n }\n else {\n const urlObj = normalizeTrailingSlash(typeof url === \"string\" ? new URL(url) : new URL(url));\n // Iterate over URL patterns\n for (const element of urlPatterns) {\n for (const [locale, localizedPattern] of element.localized) {\n const match = execUrlPattern(new URLPattern(localizedPattern, urlObj.href), urlObj);\n if (match) {\n result = locale;\n break;\n }\n }\n if (result)\n break;\n }\n }\n cachedUrl = urlString;\n cachedLocale = result;\n return result;\n}\n/**\n * https://github.com/opral/inlang-paraglide-js/issues/381\n *\n * @param {URL | string} url - The full URL from which to extract the locale.\n * @returns {Locale | undefined} The extracted locale, or undefined if no locale is found.\n */\nfunction defaultUrlPatternExtractLocale(url) {\n const urlObj = new URL(url, \"http://example.com\");\n const pathSegments = urlObj.pathname.split(\"/\").filter(Boolean);\n return toLocale(pathSegments[0]) || baseLocale;\n}\n\n/**\n * Lower-level URL localization function, primarily used in server contexts.\n *\n * This function is designed for server-side usage where you need precise control\n * over URL localization, such as in middleware or request handlers. It works with\n * URL objects and always returns absolute URLs.\n *\n * For client-side UI components, use `localizeHref()` instead, which provides\n * a more convenient API with relative paths and automatic locale detection.\n *\n * @see https://paraglidejs.com/i18n-routing\n *\n * @example\n * ```typescript\n * // Server middleware example\n * app.use((req, res, next) => {\n * const url = new URL(req.url, `${req.protocol}://${req.headers.host}`);\n * const localized = localizeUrl(url, { locale: \"de\" });\n *\n * if (localized.href !== url.href) {\n * return res.redirect(localized.href);\n * }\n * next();\n * });\n * ```\n *\n * @example\n * ```typescript\n * // Using with URL patterns\n * const url = new URL(\"https://example.com/about\");\n * localizeUrl(url, { locale: \"de\" });\n * // => URL(\"https://example.com/de/about\")\n *\n * // Using with domain-based localization\n * const url = new URL(\"https://example.com/store\");\n * localizeUrl(url, { locale: \"de\" });\n * // => URL(\"https://de.example.com/store\")\n * ```\n *\n * @param {string | URL} url - The URL to localize. If string, must be absolute.\n * @param {object} [options] - Options for localization\n * @param {Locale} [options.locale] - Target locale. If not provided, uses getLocale()\n * @returns {URL} The localized URL, always absolute\n */\nexport function localizeUrl(url, options) {\n const targetLocale = options?.locale\n ? assertIsLocale(options?.locale)\n : getLocale();\n if (TREE_SHAKE_DEFAULT_URL_PATTERN_USED) {\n return localizeUrlDefaultPattern(url, targetLocale);\n }\n const originalUrl = typeof url === \"string\" ? new URL(url) : url;\n const urlObj = trailingSlash === undefined\n ? originalUrl\n : normalizeTrailingSlash(new URL(originalUrl));\n // Iterate over URL patterns\n for (const element of urlPatterns) {\n // Most applications use a locale prefix (and sometimes a fixed domain)\n // with a trailing catch-all path. Those routes do not need URLPattern's\n // parser or matcher on every call. Keep the generic matcher below as the\n // fallback for every other URLPattern shape. This stays inside the outer\n // loop so specific patterns retain precedence over a later catch-all.\n const fastPathLocalized = localizeUrlFastPath(urlObj, targetLocale, element);\n if (fastPathLocalized !== undefined) {\n return fastPathLocalized;\n }\n // match localized patterns\n for (const [, localizedPattern] of element.localized) {\n const match = execUrlPattern(getUrlPattern(localizedPattern, urlObj), urlObj);\n if (!match) {\n continue;\n }\n const targetPattern = element.localized.find(([locale]) => locale === targetLocale)?.[1];\n if (!targetPattern) {\n continue;\n }\n const localizedUrl = fillPattern(targetPattern, aggregateGroups(match), urlObj.origin);\n return normalizeTrailingSlash(fillMissingUrlParts(localizedUrl, match));\n }\n const unlocalizedMatch = execUrlPattern(getUrlPattern(element.pattern, urlObj), urlObj);\n if (unlocalizedMatch) {\n const targetPattern = element.localized.find(([locale]) => locale === targetLocale)?.[1];\n if (targetPattern) {\n const localizedUrl = fillPattern(targetPattern, aggregateGroups(unlocalizedMatch), urlObj.origin);\n return normalizeTrailingSlash(fillMissingUrlParts(localizedUrl, unlocalizedMatch));\n }\n }\n }\n // If no match found, return the original URL\n return originalUrl;\n}\n/**\n * https://github.com/opral/inlang-paraglide-js/issues/381\n *\n * @param {string | URL} url\n * @param {Locale} locale\n * @returns {URL}\n */\nfunction localizeUrlDefaultPattern(url, locale) {\n const urlObj = normalizeTrailingSlash(typeof url === \"string\" ? new URL(url, getUrlOrigin()) : new URL(url));\n const currentLocale = extractLocaleFromUrl(urlObj);\n // If current locale matches target locale, no change needed\n if (currentLocale === locale) {\n return normalizeTrailingSlash(urlObj);\n }\n // Ignore leading separators like locale detection, preserving the remaining path.\n const pathSegments = urlObj.pathname.replace(/^\\/+/, \"\").split(\"/\");\n // If current path starts with a locale, remove it\n if (pathSegments.length > 0 && toLocale(pathSegments[0])) {\n pathSegments.shift();\n }\n // For base locale, don't add prefix\n if (locale === baseLocale) {\n urlObj.pathname = \"/\" + pathSegments.join(\"/\");\n }\n else {\n // For other locales, add prefix\n urlObj.pathname = \"/\" + locale + \"/\" + pathSegments.join(\"/\");\n }\n return normalizeTrailingSlash(urlObj);\n}\n/**\n * Low-level URL de-localization function, primarily used in server contexts.\n *\n * This function is designed for server-side usage where you need precise control\n * over URL de-localization, such as in middleware or request handlers. It works with\n * URL objects and always returns absolute URLs.\n *\n * For client-side UI components, use `deLocalizeHref()` instead, which provides\n * a more convenient API with relative paths.\n *\n * @see https://paraglidejs.com/i18n-routing\n *\n * @example\n * ```typescript\n * // Server middleware example\n * app.use((req, res, next) => {\n * const url = new URL(req.url, `${req.protocol}://${req.headers.host}`);\n * const baseUrl = deLocalizeUrl(url);\n *\n * // Store the base URL for later use\n * req.baseUrl = baseUrl;\n * next();\n * });\n * ```\n *\n * @example\n * ```typescript\n * // Using with URL patterns\n * const url = new URL(\"https://example.com/de/about\");\n * deLocalizeUrl(url); // => URL(\"https://example.com/about\")\n *\n * // Using with domain-based localization\n * const url = new URL(\"https://de.example.com/store\");\n * deLocalizeUrl(url); // => URL(\"https://example.com/store\")\n * ```\n *\n * @param {string | URL} url - The URL to de-localize. If string, must be absolute.\n * @returns {URL} The de-localized URL, always absolute\n */\nexport function deLocalizeUrl(url) {\n if (TREE_SHAKE_DEFAULT_URL_PATTERN_USED) {\n return deLocalizeUrlDefaultPattern(url);\n }\n const originalUrl = typeof url === \"string\" ? new URL(url) : url;\n const urlObj = trailingSlash === undefined\n ? originalUrl\n : normalizeTrailingSlash(new URL(originalUrl));\n // Iterate over URL patterns\n for (const element of urlPatterns) {\n const fastPathDeLocalized = deLocalizeUrlFastPath(urlObj, element);\n if (fastPathDeLocalized !== undefined) {\n return fastPathDeLocalized;\n }\n // Iterate over localized versions\n for (const [, localizedPattern] of element.localized) {\n const match = execUrlPattern(getUrlPattern(localizedPattern, urlObj), urlObj);\n if (match) {\n // Convert localized URL back to the base pattern\n const groups = aggregateGroups(match);\n const baseUrl = fillPattern(element.pattern, groups, urlObj.origin);\n return normalizeTrailingSlash(fillMissingUrlParts(baseUrl, match));\n }\n }\n // match unlocalized pattern\n const unlocalizedMatch = execUrlPattern(getUrlPattern(element.pattern, urlObj), urlObj);\n if (unlocalizedMatch) {\n const baseUrl = fillPattern(element.pattern, aggregateGroups(unlocalizedMatch), urlObj.origin);\n return normalizeTrailingSlash(fillMissingUrlParts(baseUrl, unlocalizedMatch));\n }\n }\n // no match found return the original url\n return originalUrl;\n}\n/**\n * De-localizes a URL using the default pattern (/:locale/*)\n * @param {string|URL} url\n * @returns {URL}\n */\nfunction deLocalizeUrlDefaultPattern(url) {\n const urlObj = normalizeTrailingSlash(typeof url === \"string\" ? new URL(url, getUrlOrigin()) : new URL(url));\n // Ignore leading separators like locale detection, preserving the remaining path.\n const pathSegments = urlObj.pathname.replace(/^\\/+/, \"\").split(\"/\");\n // If first segment is a locale, remove it\n if (pathSegments.length > 0 && toLocale(pathSegments[0])) {\n urlObj.pathname = \"/\" + pathSegments.slice(1).join(\"/\");\n }\n return normalizeTrailingSlash(urlObj);\n}\n/**\n * Takes matches of implicit wildcards in the UrlPattern (when a part is missing\n * it is equal to '*') and adds them back to the result of fillPattern.\n *\n * At least protocol and hostname are required to create a valid URL inside fillPattern.\n *\n * @param {URL} url\n * @param {any} match\n * @returns {URL}\n */\nfunction fillMissingUrlParts(url, match) {\n if (match.protocol.groups[\"0\"]) {\n url.protocol = match.protocol.groups[\"0\"] ?? \"\";\n }\n if (match.hostname.groups[\"0\"]) {\n url.hostname = match.hostname.groups[\"0\"] ?? \"\";\n }\n if (match.username.groups[\"0\"]) {\n url.username = match.username.groups[\"0\"] ?? \"\";\n }\n if (match.password.groups[\"0\"]) {\n url.password = match.password.groups[\"0\"] ?? \"\";\n }\n if (match.port.groups[\"0\"]) {\n url.port = match.port.groups[\"0\"] ?? \"\";\n }\n if (match.pathname.groups[\"0\"]) {\n url.pathname = match.pathname.groups[\"0\"] ?? \"\";\n }\n if (match.search.groups[\"0\"]) {\n url.search = match.search.groups[\"0\"] ?? \"\";\n }\n if (match.hash.groups[\"0\"]) {\n url.hash = match.hash.groups[\"0\"] ?? \"\";\n }\n return url;\n}\n/**\n * Fills a URL pattern with values for named groups, supporting all URLPattern-style modifiers.\n *\n * This function will eventually be replaced by https://github.com/whatwg/urlpattern/issues/73\n *\n * Matches:\n * - :name -> Simple\n * - :name? -> Optional\n * - :name+ -> One or more\n * - :name* -> Zero or more\n * - :name(...) -> Regex group\n * - {text} -> Group delimiter\n * - {text}? -> Optional group delimiter\n *\n * If the value is `null`, the segment is removed.\n *\n * @param {string} pattern - The URL pattern containing named groups.\n * @param {Record<string, string | null | undefined>} values - Object of values for named groups.\n * @param {string} origin - Base URL to use for URL construction.\n * @returns {URL} - The constructed URL with named groups filled.\n */\nfunction fillPattern(pattern, values, origin) {\n // Pre-process the pattern to handle explicit port numbers\n // This detects patterns like \"http://localhost:5173\" and protects the port number\n // from being interpreted as a parameter\n let processedPattern = pattern.replace(/(https?:\\/\\/[^:/]+):(\\d+)(\\/|$)/g, (_, protocol, port, slash) => {\n // Replace \":5173\" with \"#PORT-5173#\" to protect it from parameter replacement\n return `${protocol}#PORT-${port}#${slash}`;\n });\n // First, handle group delimiters with curly braces\n let processedGroupDelimiters = processedPattern.replace(/\\{([^{}]*)\\}([?+*]?)/g, (_, content, modifier) => {\n // For optional group delimiters\n if (modifier === \"?\") {\n // For optional groups, we'll include the content\n return content;\n }\n // For non-optional group delimiters, always include the content\n return content;\n });\n // Then handle named groups\n let filled = processedGroupDelimiters.replace(/(\\/?):([a-zA-Z0-9_]+)(\\([^)]*\\))?([?+*]?)/g, (_, slash, name, __, modifier) => {\n const value = values[name];\n if (value === null) {\n // If value is null, remove the entire segment including the preceding slash\n return \"\";\n }\n if (modifier === \"?\") {\n // Optional segment\n return value !== undefined ? `${slash}${value}` : \"\";\n }\n if (modifier === \"+\" || modifier === \"*\") {\n // Repeatable segments\n if (value === undefined && modifier === \"+\") {\n throw new Error(`Missing value for \"${name}\" (one or more required)`);\n }\n return value ? `${slash}${value}` : \"\";\n }\n // Simple named group (no modifier)\n if (value === undefined) {\n throw new Error(`Missing value for \"${name}\"`);\n }\n return `${slash}${value}`;\n });\n // Restore port numbers\n filled = filled.replace(/#PORT-(\\d+)#/g, \":$1\");\n return new URL(filled, origin);\n}\n/**\n * Aggregates named groups from various parts of the URLPattern match result.\n *\n *\n * @param {any} match - The URLPattern match result object.\n * @returns {Record<string, string | null | undefined>} An object containing all named groups from the match.\n */\nexport function aggregateGroups(match) {\n return {\n ...match.hash.groups,\n ...match.hostname.groups,\n ...match.password.groups,\n ...match.pathname.groups,\n ...match.port.groups,\n ...match.protocol.groups,\n ...match.search.groups,\n ...match.username.groups,\n };\n}\n/** @type {Map<string, URLPattern>} */\nconst urlPatternCache = new Map();\nconst URL_PATTERN_CACHE_LIMIT = 128;\nconst ABSOLUTE_URL_PATTERN = /^(?:[A-Za-z][A-Za-z\\d+.-]*|:[A-Za-z][A-Za-z\\d_-]*):\\/\\//;\n/**\n * URLPattern's base URL affects relative patterns. Absolute patterns only\n * depend on the pattern itself, while root-relative patterns also depend on\n * the URL origin. Other relative patterns are deliberately not cached because\n * their semantics depend on the complete base URL.\n *\n * @param {string} pattern\n * @param {URL} url\n * @returns {URLPattern}\n */\nfunction getUrlPattern(pattern, url) {\n const isAbsolutePattern = ABSOLUTE_URL_PATTERN.test(pattern);\n const isRootRelativePattern = pattern.startsWith(\"/\");\n if (!isAbsolutePattern && !isRootRelativePattern) {\n return new URLPattern(pattern, url.href);\n }\n const key = isAbsolutePattern\n ? pattern\n : JSON.stringify([url.origin, pattern]);\n const cached = urlPatternCache.get(key);\n if (cached !== undefined) {\n // Refresh the entry so frequently used patterns stay in the bounded cache.\n urlPatternCache.delete(key);\n urlPatternCache.set(key, cached);\n return cached;\n }\n const compiled = new URLPattern(pattern, url.href);\n if (urlPatternCache.size >= URL_PATTERN_CACHE_LIMIT) {\n const oldestKey = urlPatternCache.keys().next().value;\n if (oldestKey !== undefined)\n urlPatternCache.delete(oldestKey);\n }\n urlPatternCache.set(key, compiled);\n return compiled;\n}\n/**\n * A small, deliberately conservative subset of URLPattern routing.\n *\n * The compiler emits routes such as `/:path(.*)?`, `/de/:path*`, or\n * `https://example.com/:path*`. For those routes matching is equivalent to a\n * pathname prefix check and (optionally) an origin check. Everything that has\n * a dynamic host, a custom path regexp, or another URLPattern modifier keeps\n * using the generic implementation above.\n *\n * @typedef {{\n * protocol: string | undefined;\n * hostname: string | undefined;\n * port: string | undefined;\n * pathnamePrefix: string;\n * pathMode: \"segments\" | \"catch-all-optional\" | \"catch-all-required\";\n * }} FastPathPattern\n * @typedef {{\n * base: FastPathPattern;\n * localized: Array<{ locale: string; pattern: FastPathPattern }>;\n * }} FastPathRoute\n */\n/** @type {WeakMap<object, FastPathRoute | null>} */\nconst fastPathRouteCache = new WeakMap();\n/**\n * @param {URL} urlObj\n * @param {string} targetLocale\n * @param {{ pattern: string; localized: Array<[string, string]> }} element\n * @returns {URL | undefined}\n */\nfunction localizeUrlFastPath(urlObj, targetLocale, element) {\n const route = getFastPathRoute(element);\n if (route === null)\n return undefined;\n // Preserve URLPattern's ordering: localized patterns are checked before\n // the unlocalized pattern, and the first matching pattern wins.\n for (const localized of route.localized) {\n const suffix = matchFastPathPattern(localized.pattern, urlObj);\n if (suffix === undefined)\n continue;\n const target = route.localized.find((candidate) => candidate.locale === targetLocale)?.pattern;\n if (target === undefined)\n continue;\n return applyFastPathPattern(target, suffix, urlObj);\n }\n const suffix = matchFastPathPattern(route.base, urlObj);\n if (suffix !== undefined) {\n const target = route.localized.find((candidate) => candidate.locale === targetLocale)?.pattern;\n if (target !== undefined) {\n return applyFastPathPattern(target, suffix, urlObj);\n }\n }\n return undefined;\n}\n/**\n * @param {URL} urlObj\n * @param {{ pattern: string; localized: Array<[string, string]> }} element\n * @returns {URL | undefined}\n */\nfunction deLocalizeUrlFastPath(urlObj, element) {\n const route = getFastPathRoute(element);\n if (route === null)\n return undefined;\n for (const localized of route.localized) {\n const suffix = matchFastPathPattern(localized.pattern, urlObj);\n if (suffix !== undefined) {\n return applyFastPathPattern(route.base, suffix, urlObj);\n }\n }\n const suffix = matchFastPathPattern(route.base, urlObj);\n if (suffix !== undefined) {\n return applyFastPathPattern(route.base, suffix, urlObj);\n }\n return undefined;\n}\n/**\n * @param {{ pattern: string; localized: Array<[string, string]> }} element\n * @returns {FastPathRoute | null}\n */\nfunction getFastPathRoute(element) {\n const cached = fastPathRouteCache.get(element);\n if (cached !== undefined)\n return cached;\n const base = parseFastPathPattern(element.pattern);\n if (base === undefined) {\n fastPathRouteCache.set(element, null);\n return null;\n }\n const localized = [];\n for (const [locale, pattern] of element.localized) {\n const parsed = parseFastPathPattern(pattern);\n if (parsed === undefined || parsed.pathMode !== base.pathMode) {\n fastPathRouteCache.set(element, null);\n return null;\n }\n localized.push({ locale, pattern: parsed });\n }\n const route = { base, localized };\n fastPathRouteCache.set(element, route);\n return route;\n}\n/**\n * Parse only catch-all path patterns. In particular, do not treat `:path(.)?`\n * as a catch-all: URLPattern's `(.)` means exactly one character and cannot be\n * represented by this prefix matcher without changing routing semantics.\n *\n * @param {string} pattern\n * @returns {FastPathPattern | undefined}\n */\nfunction parseFastPathPattern(pattern) {\n const wildcard = pattern.match(/\\/:path(?:\\(\\.\\*\\)(?:\\?)?|\\*)$/);\n if (wildcard === null || wildcard.index === undefined)\n return undefined;\n const prefix = pattern.slice(0, wildcard.index);\n const originAndPath = parseFastPathOriginAndPath(prefix);\n if (originAndPath === undefined)\n return undefined;\n const pathMode = wildcard[0].endsWith(\"*\")\n ? \"segments\"\n : wildcard[0].endsWith(\"?\")\n ? \"catch-all-optional\"\n : \"catch-all-required\";\n return { ...originAndPath, pathMode };\n}\n/**\n * @param {string} prefix\n * @returns {FastPathPattern | undefined}\n */\nfunction parseFastPathOriginAndPath(prefix) {\n if (prefix === \"\" || prefix.startsWith(\"/\")) {\n if (hasUrlPatternSyntax(prefix))\n return undefined;\n return {\n protocol: undefined,\n hostname: undefined,\n port: undefined,\n pathnamePrefix: normalizePathPrefix(prefix),\n pathMode: \"catch-all-optional\",\n };\n }\n // A `:protocol://host` pattern is common in generated configurations. The\n // protocol is intentionally left unconstrained, just like URLPattern.\n const dynamicProtocol = prefix.match(/^:protocol:\\/\\/([^/]+)(\\/.*)?$/);\n const staticOrigin = prefix.match(/^([A-Za-z][A-Za-z\\d+.-]*):\\/\\/([^/]+)(\\/.*)?$/);\n if (dynamicProtocol !== null) {\n const dynamicHost = dynamicProtocol[1] ?? \"\";\n const hostMatch = dynamicHost.match(/^([^:(){}?*+]+)(?::(\\d+))?$/);\n if (hostMatch === null ||\n (dynamicProtocol[2] !== undefined &&\n hasUrlPatternSyntax(dynamicProtocol[2]))) {\n return undefined;\n }\n return {\n protocol: undefined,\n hostname: (hostMatch[1] ?? \"\").toLowerCase(),\n port: hostMatch[2],\n pathnamePrefix: normalizePathPrefix(dynamicProtocol[2] ?? \"\"),\n pathMode: \"catch-all-optional\",\n };\n }\n if (staticOrigin === null)\n return undefined;\n const host = staticOrigin[2] ?? \"\";\n const pathname = staticOrigin[3];\n const hostMatch = host.match(/^([^:(){}?*+]+)(?::(\\d+))?$/);\n if (hostMatch === null ||\n (pathname !== undefined && hasUrlPatternSyntax(pathname))) {\n return undefined;\n }\n return {\n protocol: `${staticOrigin[1]}:`,\n hostname: (hostMatch[1] ?? \"\").toLowerCase(),\n port: normalizePatternPort(hostMatch[2], `${staticOrigin[1]}:`),\n pathnamePrefix: normalizePathPrefix(pathname ?? \"\"),\n pathMode: \"catch-all-optional\",\n };\n}\n/**\n * @param {string | undefined} port\n * @param {string} protocol\n * @returns {string | undefined}\n */\nfunction normalizePatternPort(port, protocol) {\n if (port === \"80\" && protocol === \"http:\")\n return \"\";\n if (port === \"443\" && protocol === \"https:\")\n return \"\";\n return port;\n}\n/**\n * @param {string} value\n * @returns {boolean}\n */\nfunction hasUrlPatternSyntax(value) {\n return /[:(){}?*+]/.test(value);\n}\n/**\n * @param {string} pathname\n * @returns {string}\n */\nfunction normalizePathPrefix(pathname) {\n if (pathname === \"\" || pathname === \"/\")\n return \"/\";\n return pathname.endsWith(\"/\") ? pathname.slice(0, -1) : pathname;\n}\n/**\n * @param {FastPathPattern} pattern\n * @param {URL} urlObj\n * @returns {string | undefined}\n */\nfunction matchFastPathPattern(pattern, urlObj) {\n if (pattern.protocol !== undefined && pattern.protocol !== urlObj.protocol) {\n return undefined;\n }\n if (pattern.hostname !== undefined &&\n pattern.hostname !== urlObj.hostname.toLowerCase()) {\n return undefined;\n }\n if (pattern.hostname !== undefined) {\n const expectedPort = pattern.port ?? defaultPortForProtocol(pattern.protocol ?? urlObj.protocol);\n if (expectedPort !== urlObj.port)\n return undefined;\n }\n const prefix = pattern.pathnamePrefix;\n if (prefix === \"/\") {\n if (urlObj.pathname.startsWith(\"//\"))\n return undefined;\n if (pattern.pathMode === \"segments\") {\n return isNonEmptyPathSegments(urlObj.pathname)\n ? urlObj.pathname\n : undefined;\n }\n return urlObj.pathname;\n }\n if (urlObj.pathname === prefix) {\n return pattern.pathMode === \"catch-all-required\" ? undefined : \"\";\n }\n if (urlObj.pathname.startsWith(`${prefix}/`)) {\n const suffix = urlObj.pathname.slice(prefix.length);\n if (suffix.startsWith(\"//\"))\n return undefined;\n if (pattern.pathMode === \"segments\" &&\n !isNonEmptyPathSegments(suffix)) {\n return undefined;\n }\n return suffix;\n }\n return undefined;\n}\n/**\n * @param {string} pathname\n * @returns {boolean}\n */\nfunction isNonEmptyPathSegments(pathname) {\n return pathname.length > 1 && !pathname.endsWith(\"/\") && !pathname.includes(\"//\");\n}\n/**\n * URLPattern treats the default port as empty in URL instances.\n *\n * @param {string} protocol\n * @returns {string}\n */\nfunction defaultPortForProtocol(protocol) {\n if (protocol === \"http:\")\n return \"\";\n if (protocol === \"https:\")\n return \"\";\n return \"\";\n}\n/**\n * @param {FastPathPattern} pattern\n * @param {string} suffix\n * @param {URL} source\n * @returns {URL}\n */\nfunction applyFastPathPattern(pattern, suffix, source) {\n const localized = new URL(source.href);\n if (pattern.protocol !== undefined)\n localized.protocol = pattern.protocol;\n if (pattern.hostname !== undefined) {\n localized.hostname = pattern.hostname;\n localized.port =\n pattern.port ?? defaultPortForProtocol(localized.protocol);\n }\n localized.pathname = joinFastPathPrefix(pattern.pathnamePrefix, suffix);\n return localized;\n}\n/**\n * @param {string} prefix\n * @param {string} suffix\n * @returns {string}\n */\nfunction joinFastPathPrefix(prefix, suffix) {\n if (prefix === \"/\")\n return suffix === \"\" ? \"/\" : suffix;\n if (suffix === \"\")\n return prefix;\n return `${prefix}${suffix.startsWith(\"/\") ? suffix : `/${suffix}`}`;\n}\n\n/** @type {string | undefined} */\nlet cachedRouteStrategyUrl;\n/** @type {{ match: string; strategy?: typeof strategy; exclude?: boolean } | undefined} */\nlet cachedRouteStrategy;\n/**\n * Match route policy against both the public URL and its canonical URL.\n *\n * The function is deliberately separate from variables.js: configuration is\n * inert data, while canonicalization and route selection form a routing layer.\n *\n * @param {string | URL} url\n * @returns {{ match: string; strategy?: typeof strategy; exclude?: boolean } | undefined}\n */\nexport function findMatchingRouteStrategy(url) {\n if (routeStrategies.length === 0) {\n return undefined;\n }\n const urlString = typeof url === \"string\" ? url : url.href;\n if (cachedRouteStrategyUrl === urlString) {\n return cachedRouteStrategy;\n }\n const publicUrl = normalizeTrailingSlash(new URL(urlString, \"http://example.com\"));\n const canonicalUrl = deLocalizeUrl(publicUrl);\n const candidateUrls = canonicalUrl.href === publicUrl.href\n ? [publicUrl]\n : [publicUrl, canonicalUrl];\n let match;\n for (const candidateUrl of candidateUrls) {\n for (const routeStrategy of routeStrategies) {\n const pattern = new URLPattern(routeStrategy.match, candidateUrl.href);\n if (execUrlPattern(pattern, candidateUrl)) {\n match = routeStrategy;\n break;\n }\n }\n if (match)\n break;\n }\n cachedRouteStrategyUrl = urlString;\n cachedRouteStrategy = match;\n return match;\n}\n/**\n * Returns the strategy to use for a specific URL.\n *\n * If no route strategy matches (or the matching rule is `exclude: true`),\n * the global strategy is returned.\n *\n * @param {string | URL} url\n * @returns {typeof strategy}\n */\nexport function getStrategyForUrl(url) {\n const routeStrategy = findMatchingRouteStrategy(url);\n if (routeStrategy &&\n routeStrategy.exclude !== true &&\n Array.isArray(routeStrategy.strategy)) {\n return routeStrategy.strategy;\n }\n return strategy;\n}\n/**\n * Returns whether the given URL is excluded from middleware i18n processing.\n *\n * @param {string | URL} url\n * @returns {boolean}\n */\nexport function isExcludedByRouteStrategy(url) {\n return findMatchingRouteStrategy(url)?.exclude === true;\n}\n\n/**\n * @typedef {object} ShouldRedirectServerInput\n * @property {Request} request\n * @property {string | URL} [effectiveRequestUrl] - Effective request URL to use for route matching, locale detection with the URL strategy, and redirect targets.\n * @property {Locale} [locale]\n *\n * @typedef {object} ShouldRedirectClientInput\n * @property {undefined} [request]\n * @property {string | URL} [url]\n * @property {Locale} [locale]\n *\n * @typedef {ShouldRedirectServerInput | ShouldRedirectClientInput} ShouldRedirectInput\n *\n * @typedef {object} ShouldRedirectResult\n * @property {boolean} shouldRedirect - Indicates whether the consumer should perform a redirect.\n * @property {Locale} locale - Locale resolved using the configured strategies.\n * @property {URL | undefined} redirectUrl - Destination URL when a redirect is required.\n */\n/**\n * Determines whether a redirect is required to align the current URL with the active locale.\n *\n * This helper mirrors the logic that powers `paraglideMiddleware`, but works in both server\n * and client environments. It evaluates the configured strategies in order, computes the\n * canonical localized URL, and reports when the current URL does not match.\n *\n * When called in the browser without arguments, the current `window.location.href` is used.\n *\n * @see https://paraglidejs.com/i18n-routing#redirects\n *\n * @example\n * // Client side usage (e.g. TanStack Router beforeLoad hook)\n * async function beforeLoad({ location }) {\n * const decision = await shouldRedirect({ url: location.href });\n *\n * if (decision.shouldRedirect) {\n * throw redirect({ to: decision.redirectUrl.href });\n * }\n * }\n *\n * @example\n * // Server side usage with a Request\n * export async function handle(request) {\n * const decision = await shouldRedirect({ request });\n *\n * if (decision.shouldRedirect) {\n * return Response.redirect(decision.redirectUrl, 307);\n * }\n *\n * return render(request, decision.locale);\n * }\n *\n * @example\n * // Server side usage behind a proxy where request.url is not public-facing\n * export async function handle(request) {\n * const effectiveRequestUrl = new URL(request.url);\n * effectiveRequestUrl.protocol = \"https:\";\n * effectiveRequestUrl.host = \"example.com\";\n *\n * const decision = await shouldRedirect({\n * request,\n * effectiveRequestUrl,\n * });\n *\n * if (decision.shouldRedirect) {\n * return Response.redirect(decision.redirectUrl, 307);\n * }\n * }\n *\n * @param {ShouldRedirectInput} [input]\n * @returns {Promise<ShouldRedirectResult>}\n */\nexport async function shouldRedirect(input = {}) {\n const currentUrl = resolveUrl(input);\n const locale = await resolveLocale(input, currentUrl);\n const strategy = getStrategyForUrl(currentUrl.href);\n if (isExcludedByRouteStrategy(currentUrl.href) || !strategy.includes(\"url\")) {\n return { shouldRedirect: false, locale, redirectUrl: undefined };\n }\n const localizedUrl = localizeUrl(currentUrl.href, { locale });\n const shouldRedirectToLocalizedUrl = normalizeUrl(localizedUrl.href) !== normalizeUrl(currentUrl.href);\n return {\n shouldRedirect: shouldRedirectToLocalizedUrl,\n locale,\n redirectUrl: shouldRedirectToLocalizedUrl ? localizedUrl : undefined,\n };\n}\n/**\n * Resolves the locale either from the provided input or by using the configured strategies.\n *\n * @param {ShouldRedirectInput} input\n * @param {URL} currentUrl\n * @returns {Promise<Locale>}\n */\nasync function resolveLocale(input, currentUrl) {\n const locale = toLocale(input.locale);\n if (locale) {\n return locale;\n }\n if (input.request) {\n return extractLocaleFromRequestAsync(input.request, {\n effectiveRequestUrl: currentUrl,\n });\n }\n if (\"url\" in input && typeof input.url !== \"undefined\") {\n return getLocaleForUrl(currentUrl.href);\n }\n return getLocale();\n}\n/**\n * Resolves the current URL from the provided input or runtime context.\n *\n * @param {ShouldRedirectInput} input\n * @returns {URL}\n */\nfunction resolveUrl(input) {\n if (\"effectiveRequestUrl\" in input &&\n input.effectiveRequestUrl instanceof URL) {\n return new URL(input.effectiveRequestUrl.href);\n }\n if (\"effectiveRequestUrl\" in input &&\n typeof input.effectiveRequestUrl === \"string\") {\n return new URL(input.effectiveRequestUrl, input.request ? input.request.url : getUrlOrigin());\n }\n if (input.request) {\n return new URL(input.request.url);\n }\n if (\"url\" in input && input.url instanceof URL) {\n return new URL(input.url.href);\n }\n if (\"url\" in input && typeof input.url === \"string\") {\n return new URL(input.url, getUrlOrigin());\n }\n if (typeof window !== \"undefined\" && window?.location?.href) {\n return new URL(window.location.href);\n }\n throw new Error(\"shouldRedirect() requires either a request, an absolute URL, or must run in a browser environment.\");\n}\n/**\n * Normalize url for comparison by stripping the trailing slash.\n *\n * @param {string} url\n * @returns {string}\n */\nfunction normalizeUrl(url) {\n const urlObj = new URL(url);\n if (trailingSlash === undefined) {\n urlObj.pathname = urlObj.pathname.replace(/\\/$/, \"\");\n }\n return urlObj.href;\n}\n\n/**\n * High-level URL localization function optimized for client-side UI usage.\n *\n * This is a convenience wrapper around `localizeUrl()` that provides features\n * needed in UI:\n *\n * - Accepts relative paths (e.g., \"/about\")\n * - Returns relative paths when possible\n * - Automatically detects current locale if not specified\n * - Handles string input/output instead of URL objects\n *\n * @see https://paraglidejs.com/i18n-routing\n *\n * @example\n * ```typescript\n * // In a React/Vue/Svelte component\n * const NavLink = ({ href }) => {\n * // Automatically uses current locale, keeps path relative\n * return <a href={localizeHref(href)}>...</a>;\n * };\n *\n * // Examples:\n * localizeHref(\"/about\")\n * // => \"/de/about\" (if current locale is \"de\")\n * localizeHref(\"/store\", { locale: \"fr\" })\n * // => \"/fr/store\" (explicit locale)\n *\n * // Cross-origin links remain absolute\n * localizeHref(\"https://other-site.com/about\")\n * // => \"https://other-site.com/de/about\"\n * ```\n *\n * For server-side URL localization (e.g., in middleware), use `localizeUrl()`\n * which provides more precise control over URL handling.\n *\n * @param {string} href - The href to localize (can be relative or absolute)\n * @param {object} [options] - Options for localization\n * @param {Locale} [options.locale] - Target locale. If not provided, uses `getLocale()`\n * @returns {string} The localized href, relative if input was relative\n */\nexport function localizeHref(href, options) {\n const currentLocale = getLocale();\n const locale = options?.locale ?? currentLocale;\n const url = new URL(href, getUrlOrigin());\n const localized = localizeUrl(url, { locale });\n // if the origin is identical and the href is relative,\n // return the relative path\n if (href.startsWith(\"/\") && url.origin === localized.origin) {\n // check for cross origin localization in which case an absolute URL must be returned.\n if (locale !== currentLocale) {\n const localizedCurrentLocale = localizeUrl(url, {\n locale: currentLocale,\n });\n if (localizedCurrentLocale.origin !== localized.origin) {\n return localized.href;\n }\n }\n return localized.pathname + localized.search + localized.hash;\n }\n return localized.href;\n}\n/**\n * High-level URL de-localization function optimized for client-side UI usage.\n *\n * This is a convenience wrapper around `deLocalizeUrl()` that provides features\n * needed in the UI:\n *\n * - Accepts relative paths (e.g., \"/de/about\")\n * - Returns relative paths when possible\n * - Handles string input/output instead of URL objects\n *\n * @see https://paraglidejs.com/i18n-routing\n *\n * @example\n * ```typescript\n * // In a React/Vue/Svelte component\n * const LocaleSwitcher = ({ href }) => {\n * // Remove locale prefix before switching\n * const baseHref = deLocalizeHref(href);\n * return locales.map(locale =>\n * <a href={localizeHref(baseHref, { locale })}>\n * Switch to {locale}\n * </a>\n * );\n * };\n *\n * // Examples:\n * deLocalizeHref(\"/de/about\") // => \"/about\"\n * deLocalizeHref(\"/fr/store\") // => \"/store\"\n *\n * // Cross-origin links remain absolute\n * deLocalizeHref(\"https://example.com/de/about\")\n * // => \"https://example.com/about\"\n * ```\n *\n * For server-side URL de-localization (e.g., in middleware), use `deLocalizeUrl()`\n * which provides more precise control over URL handling.\n *\n * @param {string} href - The href to de-localize (can be relative or absolute)\n * @returns {string} The de-localized href, relative if input was relative\n */\nexport function deLocalizeHref(href) {\n const url = new URL(href, getUrlOrigin());\n const deLocalized = deLocalizeUrl(url);\n // If the origin is identical and the href is relative,\n // return the relative path instead of the full URL.\n if (href.startsWith(\"/\") && url.origin === deLocalized.origin) {\n return deLocalized.pathname + deLocalized.search + deLocalized.hash;\n }\n return deLocalized.href;\n}\n\n/**\n * @param {string} safeModuleId\n * @param {Locale} locale\n */\nexport function trackMessageCall(safeModuleId, locale) {\n if (isServer === false)\n return;\n const store = serverAsyncLocalStorage?.getStore();\n if (store) {\n store.messageCalls?.add(`${safeModuleId}:${locale}`);\n }\n}\n\n/**\n * Generates localized URL variants for all provided URLs based on your configured locales and URL patterns.\n *\n * This function is essential for Static Site Generation (SSG) where you need to tell your framework\n * which pages to pre-render at build time. It's also useful for generating sitemaps and\n * `<link rel=\"alternate\" hreflang>` tags for SEO.\n *\n * The function respects your `urlPatterns` configuration - if you have translated pathnames\n * (e.g., `/about` → `/ueber-uns` for German), it will generate the correct localized paths.\n *\n * @see https://paraglidejs.com/static-site-generation\n *\n * @example\n * // Basic usage - generate all locale variants for a list of paths\n * const localizedUrls = generateStaticLocalizedUrls([\n * \"/\",\n * \"/about\",\n * \"/blog/post-1\",\n * ]);\n * // Returns URL objects for each locale:\n * // [\"/en/\", \"/de/\", \"/en/about\", \"/de/about\", \"/en/blog/post-1\", \"/de/blog/post-1\"]\n *\n * @example\n * // Use with framework SSG APIs\n * // SvelteKit\n * export function entries() {\n * const paths = [\"/\", \"/about\", \"/contact\"];\n * return generateStaticLocalizedUrls(paths).map(url => ({\n * locale: extractLocaleFromUrl(url)\n * }));\n * }\n *\n * @example\n * // Sitemap generation\n * const allPages = [\"/\", \"/about\", \"/blog\"];\n * const sitemapUrls = generateStaticLocalizedUrls(allPages);\n *\n * @param {(string | URL)[]} urls - List of canonical URLs or paths to generate localized versions for.\n * Can be absolute URLs (`https://example.com/about`) or paths (`/about`).\n * Paths are resolved against `http://localhost` internally.\n * @returns {URL[]} Array of URL objects representing all localized variants.\n * The order follows each input URL with all its locale variants before moving to the next URL.\n */\nexport function generateStaticLocalizedUrls(urls) {\n /** @type {Set<URL>} */\n const localizedUrls = new Set();\n // For default URL pattern, we can optimize the generation\n if (TREE_SHAKE_DEFAULT_URL_PATTERN_USED) {\n for (const urlInput of urls) {\n const originalUrl = urlInput instanceof URL\n ? urlInput\n : new URL(urlInput, \"http://localhost\");\n const url = trailingSlash === undefined\n ? originalUrl\n : normalizeTrailingSlash(new URL(originalUrl));\n // Base locale doesn't get a prefix\n localizedUrls.add(url);\n // Other locales get their code as prefix\n for (const locale of locales) {\n if (locale !== baseLocale) {\n const localizedPath = `/${locale}${url.pathname}${url.search}${url.hash}`;\n const localizedUrl = new URL(localizedPath, url.origin);\n localizedUrls.add(normalizeTrailingSlash(localizedUrl));\n }\n }\n }\n return Array.from(localizedUrls);\n }\n // For custom URL patterns, we need to use localizeUrl for each URL and locale\n for (const urlInput of urls) {\n const originalUrl = urlInput instanceof URL\n ? urlInput\n : new URL(urlInput, \"http://localhost\");\n const url = normalizeTrailingSlash(new URL(originalUrl));\n // Try each URL pattern to find one that matches\n let patternFound = false;\n for (const pattern of urlPatterns) {\n try {\n // Try to match the unlocalized pattern\n const unlocalizedMatch = execUrlPattern(new URLPattern(pattern.pattern, url.href), url);\n if (!unlocalizedMatch)\n continue;\n patternFound = true;\n // Track unique localized URLs to avoid duplicates when patterns are the same\n const seenUrls = new Set();\n // Generate localized URL for each locale\n for (const [locale] of pattern.localized) {\n try {\n const localizedUrl = localizeUrl(url, { locale });\n const urlString = localizedUrl.href;\n // Only add if we haven't seen this exact URL before\n if (!seenUrls.has(urlString)) {\n seenUrls.add(urlString);\n localizedUrls.add(localizedUrl);\n }\n }\n catch {\n // Skip if localization fails for this locale\n continue;\n }\n }\n break;\n }\n catch {\n // Skip if pattern matching fails\n continue;\n }\n }\n // If no pattern matched, use the URL as is\n if (!patternFound) {\n localizedUrls.add(originalUrl);\n }\n }\n return Array.from(localizedUrls);\n}\n\n/**\n * @typedef {\"cookie\" | \"baseLocale\" | \"globalVariable\" | \"url\" | \"preferredLanguage\" | \"localStorage\"} BuiltInStrategy\n */\n/**\n * @typedef {`custom_${string}`} CustomStrategy\n */\n/**\n * @typedef {BuiltInStrategy | CustomStrategy} Strategy\n */\n/**\n * @typedef {Array<Strategy>} Strategies\n */\n/**\n * @typedef {{ getLocale: (request?: Request) => Promise<string | undefined> | (string | undefined) }} CustomServerStrategyHandler\n */\n/**\n * @typedef {{ getLocale: () => Promise<string|undefined> | (string | undefined), setLocale: (locale: string) => Promise<void> | void }} CustomClientStrategyHandler\n */\n/** @type {Map<string, CustomServerStrategyHandler>} */\nexport const customServerStrategies = new Map();\n/** @type {Map<string, CustomClientStrategyHandler>} */\nexport const customClientStrategies = new Map();\n/**\n * Checks if the given strategy is a custom strategy.\n *\n * @param {unknown} strategy The name of the custom strategy to validate.\n * Must be a string that starts with \"custom-\" followed by alphanumeric characters, hyphens, or underscores.\n * @returns {boolean} Returns true if it is a custom strategy, false otherwise.\n */\nexport function isCustomStrategy(strategy) {\n return (typeof strategy === \"string\" && /^custom-[A-Za-z0-9_-]+$/.test(strategy));\n}\n/**\n * Defines a custom strategy that is executed on the server.\n *\n * @see https://paraglidejs.com/strategy#write-your-own-strategy\n *\n * @param {string} strategy The name of the custom strategy to define. Must follow the pattern custom-name with alphanumeric characters, hyphens, or underscores.\n * @param {CustomServerStrategyHandler} handler The handler for the custom strategy, which should implement\n * the method getLocale.\n * @returns {void}\n */\nexport function defineCustomServerStrategy(strategy, handler) {\n if (!isCustomStrategy(strategy)) {\n throw new Error(`Invalid custom strategy: \"${strategy}\". Must be a custom strategy following the pattern custom-name.`);\n }\n customServerStrategies.set(strategy, handler);\n}\n/**\n * Defines a custom strategy that is executed on the client.\n *\n * @see https://paraglidejs.com/strategy#write-your-own-strategy\n *\n * @param {string} strategy The name of the custom strategy to define. Must follow the pattern custom-name with alphanumeric characters, hyphens, or underscores.\n * @param {CustomClientStrategyHandler} handler The handler for the custom strategy, which should implement the\n * methods getLocale and setLocale.\n * @returns {void}\n */\nexport function defineCustomClientStrategy(strategy, handler) {\n if (!isCustomStrategy(strategy)) {\n throw new Error(`Invalid custom strategy: \"${strategy}\". Must be a custom strategy following the pattern custom-name.`);\n }\n customClientStrategies.set(strategy, handler);\n}\n\n// ------ TYPES ------\nexport {};\n/**\n * A locale that is available in the project.\n *\n * @example\n * setLocale(request.locale as Locale)\n *\n * @typedef {typeof locales[number]} Locale\n */\n/**\n * A branded type representing a localized string.\n *\n * Message functions return this type instead of \\`string\\`, enabling TypeScript\n * to distinguish translated strings from regular strings at compile time.\n * This allows you to enforce that only properly localized content is used\n * in your UI components.\n *\n * Since \\`LocalizedString\\` is a branded subtype of \\`string\\`, it remains fully\n * backward compatible—you can pass it anywhere a \\`string\\` is expected.\n *\n * @example\n * // Enforce localized strings in your components\n * function PageTitle(props: { title: LocalizedString }) {\n * return <h1>{props.title}</h1>\n * }\n *\n * // ✅ Correct: using a message function\n * <PageTitle title={m.welcome_title()} />\n *\n * // ❌ Type error: raw strings are not LocalizedString\n * <PageTitle title=\"Welcome\" />\n *\n * @example\n * // LocalizedString is assignable to string (backward compatible)\n * const localized: LocalizedString = m.greeting()\n * const str: string = localized // ✅ works fine\n *\n * // But string is not assignable to LocalizedString\n * const raw: LocalizedString = \"Hello\" // ❌ Type error\n *\n * @example\n * // Catches accidental string concatenation\n * function showMessage(msg: LocalizedString) { ... }\n *\n * showMessage(m.hello()) // ✅\n * showMessage(\"Hello \" + userName) // ❌ Type error\n * showMessage(m.hello_user({ name: userName })) // ✅ use params instead\n *\n * @typedef {string & { readonly __brand: 'LocalizedString' }} LocalizedString\n */\n/**\n * A single markup option passed to a tag instance.\n *\n * @typedef {{\n * name: string;\n * value: unknown;\n * }} MessageMarkupOption\n */\n/**\n * A single static markup attribute attached to a tag instance.\n *\n * @typedef {{\n * name: string;\n * value: string | true;\n * }} MessageMarkupAttribute\n */\n/**\n * Record of markup options for a tag instance.\n *\n * @typedef {Record<string, unknown>} MessageMarkupOptions\n */\n/**\n * Record of markup attributes for a tag instance.\n *\n * @typedef {Record<string, string | true>} MessageMarkupAttributes\n */\n/**\n * Type-level schema for a single markup tag.\n *\n * @typedef {{\n * options: MessageMarkupOptions;\n * attributes: MessageMarkupAttributes;\n * children: boolean;\n * }} MessageMarkupTag\n */\n/**\n * Type-level schema for all markup tags in a message.\n *\n * @typedef {Record<string, MessageMarkupTag>} MessageMarkupSchema\n */\n/**\n * Type-only metadata attached to compiled message functions.\n *\n * @template Inputs\n * @template Options\n * @template {MessageMarkupSchema} [Markup = MessageMarkupSchema]\n * @typedef {{\n * readonly __paraglide?: {\n * inputs: Inputs;\n * options: Options;\n * markup: Markup;\n * };\n * }} MessageMetadata\n */\n/**\n * A compiled, framework-neutral message part.\n *\n * @typedef {{\n * type: \"text\";\n * value: string;\n * } | {\n * type: \"markup-start\";\n * name: string;\n * options: MessageMarkupOptions;\n * attributes: MessageMarkupAttributes;\n * } | {\n * type: \"markup-end\";\n * name: string;\n * options: MessageMarkupOptions;\n * attributes: MessageMarkupAttributes;\n * } | {\n * type: \"markup-standalone\";\n * name: string;\n * options: MessageMarkupOptions;\n * attributes: MessageMarkupAttributes;\n * }} MessagePart\n */\n/**\n * A message function is a message for a specific locale.\n *\n * @example\n * m.hello({ name: 'world' })\n *\n * @typedef {(inputs?: Record<string, never>) => LocalizedString} MessageFunction\n */\n/**\n * A message bundle function that selects the message to be returned.\n *\n * Uses `getLocale()` under the hood to determine the locale with an option.\n *\n * @template {string} T\n *\n * @example\n * * m.hello({ name: 'world' }, { locale: \"en\" })\n *\n * @typedef {(params: Record<string, never>, options: { locale: T }) => LocalizedString} MessageBundleFunction\n */\n"],"mappings":"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"}
@@ -0,0 +1 @@
1
+ export declare const fieldErrorMessages: (errors?: readonly unknown[] | null) => string[];
@@ -0,0 +1,10 @@
1
+ //#region src/primitives/fieldErrors.ts
2
+ var e = (e) => {
3
+ let t = [];
4
+ for (let n of e ?? []) typeof n == "string" ? t.push(n) : typeof n == "object" && n && "message" in n && typeof n.message == "string" && t.push(n.message);
5
+ return [...new Set(t)];
6
+ };
7
+ //#endregion
8
+ export { e as fieldErrorMessages };
9
+
10
+ //# sourceMappingURL=fieldErrors.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fieldErrors.js","names":[],"sources":["../../src/primitives/fieldErrors.ts"],"sourcesContent":["export const fieldErrorMessages = (errors?: readonly unknown[] | null): string[] => {\n const messages: string[] = [];\n for (const error of errors ?? []) {\n if (typeof error === 'string') {\n messages.push(error);\n } else if (\n error !== null &&\n typeof error === 'object' &&\n 'message' in error &&\n typeof error.message === 'string'\n ) {\n messages.push(error.message);\n }\n }\n return [...new Set(messages)];\n};\n"],"mappings":";AAAA,IAAa,KAAsB,MAAiD;CAClF,IAAM,IAAqB,CAAC;CAC5B,KAAK,IAAM,KAAS,KAAU,CAAC,GAC7B,AAAI,OAAO,KAAU,WACnB,EAAS,KAAK,CAAK,IAGnB,OAAO,KAAU,YADjB,KAEA,aAAa,KACb,OAAO,EAAM,WAAY,YAEzB,EAAS,KAAK,EAAM,OAAO;CAG/B,OAAO,CAAC,GAAG,IAAI,IAAI,CAAQ,CAAC;AAC9B"}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "$schema": "https://json.schemastore.org/package",
3
3
  "name": "@manafishrov/ui",
4
- "version": "1.5.13",
4
+ "version": "1.5.14",
5
5
  "description": "Styled component library for Manafish interfaces ",
6
6
  "license": "AGPL-3.0-or-later",
7
7
  "repository": {
@@ -12,6 +12,7 @@ import {
12
12
  import { type VariantProps, tv, cn } from 'tailwind-variants';
13
13
 
14
14
  import { Separator } from '@/components/Separator';
15
+ import { fieldErrorMessages } from '@/primitives/fieldErrors';
15
16
 
16
17
  export { useFieldset } from '@ark-ui/solid/fieldset';
17
18
  export const FieldContext = PrimitiveField.Context;
@@ -248,29 +249,14 @@ export const FieldSeparator: Component<FieldSeparatorProps> = (props) => {
248
249
  };
249
250
 
250
251
  export type FieldErrorProps = PrimitiveField.ErrorTextProps & {
251
- errors?: ({ message?: string } | string | undefined)[];
252
+ /** Display strings or objects with a string message; ignore other validator values. */
253
+ errors?: readonly unknown[];
252
254
  };
253
255
 
254
256
  export const FieldError: Component<FieldErrorProps> = (props) => {
255
257
  const [local, others] = splitProps(props, ['class', 'children', 'errors']);
256
258
 
257
- const uniqueErrors = createMemo(() => {
258
- const { errors } = local;
259
- if (!errors || errors.length === 0) {
260
- return [];
261
- }
262
-
263
- const messages: string[] = [];
264
- for (const error of errors) {
265
- if (typeof error === 'string') {
266
- messages.push(error);
267
- } else if (error && typeof error === 'object' && typeof error.message === 'string') {
268
- messages.push(error.message);
269
- }
270
- }
271
-
272
- return [...new Set(messages)];
273
- });
259
+ const uniqueErrors = createMemo(() => fieldErrorMessages(local.errors));
274
260
 
275
261
  return (
276
262
  <div class='mt-[3px] flex min-h-[0.875rem] flex-col justify-start'>
@@ -0,0 +1,16 @@
1
+ export const fieldErrorMessages = (errors?: readonly unknown[] | null): string[] => {
2
+ const messages: string[] = [];
3
+ for (const error of errors ?? []) {
4
+ if (typeof error === 'string') {
5
+ messages.push(error);
6
+ } else if (
7
+ error !== null &&
8
+ typeof error === 'object' &&
9
+ 'message' in error &&
10
+ typeof error.message === 'string'
11
+ ) {
12
+ messages.push(error.message);
13
+ }
14
+ }
15
+ return [...new Set(messages)];
16
+ };