Skip to main content

leptos_use_intl_datetime_format/
options.rs

1use crate::{js, js_value_from_to_string};
2use default_struct_builder::DefaultBuilder;
3use std::fmt::Display;
4use wasm_bindgen::JsValue;
5
6#[derive(Default, Copy, Clone, PartialEq, Eq, Hash, Debug)]
7pub enum FormatMatcher {
8    Basic,
9    #[default]
10    BestFit,
11}
12
13impl Display for FormatMatcher {
14    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
15        match self {
16            Self::Basic => write!(f, "basic"),
17            Self::BestFit => write!(f, "best fit"),
18        }
19    }
20}
21
22js_value_from_to_string!(FormatMatcher);
23
24#[derive(Default, Copy, Clone, PartialEq, Eq, Hash, Debug)]
25pub enum LocaleMatcher {
26    #[default]
27    BestFit,
28    Lookup,
29}
30
31impl Display for LocaleMatcher {
32    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
33        match self {
34            Self::BestFit => write!(f, "best fit"),
35            Self::Lookup => write!(f, "lookup"),
36        }
37    }
38}
39
40js_value_from_to_string!(LocaleMatcher);
41
42#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
43pub enum HourCycle {
44    /// hour system using 0–11; corresponds to midnight starting at 0:00 AM.
45    H11,
46    /// hour system using 1–12; corresponds to midnight starting at 12:00 AM.
47    H12,
48    /// hour system using 0–23; corresponds to midnight starting at 0:00.
49    H23,
50    /// hour system using 1–24; corresponds to midnight starting at 24:00.
51    H24,
52}
53
54impl Display for HourCycle {
55    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
56        match self {
57            Self::H11 => write!(f, "h11"),
58            Self::H12 => write!(f, "h12"),
59            Self::H23 => write!(f, "h23"),
60            Self::H24 => write!(f, "h24"),
61        }
62    }
63}
64
65js_value_from_to_string!(HourCycle);
66
67#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
68pub enum DateTimeStyle {
69    Full,
70    Long,
71    Medium,
72    Short,
73}
74
75impl Display for DateTimeStyle {
76    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
77        match self {
78            Self::Full => write!(f, "full"),
79            Self::Long => write!(f, "long"),
80            Self::Medium => write!(f, "medium"),
81            Self::Short => write!(f, "short"),
82        }
83    }
84}
85
86js_value_from_to_string!(DateTimeStyle);
87
88#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
89pub enum WeekdayFormat {
90    /// e.g., `Thursday`
91    Long,
92    /// e.g., `Thu`
93    Short,
94    /// e.g., `T`. Note that two weekdays may have the same narrow style for some locales (e.g. `Tuesday`'s narrow style is also `T`).
95    Narrow,
96}
97
98impl Display for WeekdayFormat {
99    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
100        match self {
101            Self::Long => write!(f, "long"),
102            Self::Short => write!(f, "short"),
103            Self::Narrow => write!(f, "narrow"),
104        }
105    }
106}
107
108js_value_from_to_string!(WeekdayFormat);
109
110#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
111pub enum EraFormat {
112    /// e.g., `Anno Domini`
113    Long,
114    /// e.g., `AD`
115    Short,
116    /// e.g., `A`
117    Narrow,
118}
119
120impl Display for EraFormat {
121    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
122        match self {
123            Self::Long => write!(f, "long"),
124            Self::Short => write!(f, "short"),
125            Self::Narrow => write!(f, "narrow"),
126        }
127    }
128}
129
130js_value_from_to_string!(EraFormat);
131
132#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
133pub enum YearFormat {
134    /// e.g., `2012`
135    Numeric,
136    /// e.g., `12`
137    TwoDigit,
138}
139
140impl Display for YearFormat {
141    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
142        match self {
143            Self::Numeric => write!(f, "numeric"),
144            Self::TwoDigit => write!(f, "2-digit"),
145        }
146    }
147}
148
149js_value_from_to_string!(YearFormat);
150
151#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
152pub enum MonthFormat {
153    /// e.g., `2`
154    Numeric,
155    /// e.g., `02`
156    TwoDigit,
157    /// e.g., `March`
158    Long,
159    /// e.g., `Mar`
160    Short,
161    /// e.g., `M`
162    Narrow,
163}
164
165impl Display for MonthFormat {
166    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
167        match self {
168            Self::Numeric => write!(f, "numeric"),
169            Self::TwoDigit => write!(f, "2-digit"),
170            Self::Long => write!(f, "long"),
171            Self::Short => write!(f, "short"),
172            Self::Narrow => write!(f, "narrow"),
173        }
174    }
175}
176
177js_value_from_to_string!(MonthFormat);
178
179#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
180pub enum DayFormat {
181    /// e.g., `1`
182    Numeric,
183    /// e.g., `01`
184    TwoDigit,
185}
186
187impl Display for DayFormat {
188    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
189        match self {
190            Self::Numeric => write!(f, "numeric"),
191            Self::TwoDigit => write!(f, "2-digit"),
192        }
193    }
194}
195
196js_value_from_to_string!(DayFormat);
197
198#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
199pub enum TimeNumericFormat {
200    /// e.g., `1`
201    Numeric,
202    /// e.g., `01`
203    TwoDigit,
204}
205
206impl Display for TimeNumericFormat {
207    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
208        match self {
209            Self::Numeric => write!(f, "numeric"),
210            Self::TwoDigit => write!(f, "2-digit"),
211        }
212    }
213}
214
215js_value_from_to_string!(TimeNumericFormat);
216
217#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
218pub enum DayPeriodFormat {
219    Long,
220    Short,
221    Narrow,
222}
223
224impl Display for DayPeriodFormat {
225    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
226        match self {
227            Self::Long => write!(f, "long"),
228            Self::Short => write!(f, "short"),
229            Self::Narrow => write!(f, "narrow"),
230        }
231    }
232}
233
234js_value_from_to_string!(DayPeriodFormat);
235
236#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
237pub enum TimeZoneNameFormat {
238    /// Long localized form (e.g., `Pacific Standard Time`, `Nordamerikanische Westküsten-Normalzeit`)
239    Long,
240    /// Short localized form (e.g.: `PST`, `GMT-8`)
241    Short,
242    /// Short localized GMT format (e.g., `GMT-8`)
243    ShortOffset,
244    /// Long localized GMT format (e.g., `GMT-0800`)
245    LongOffset,
246    /// Short generic non-location format (e.g.: `PT`, `Los Angeles Zeit`).
247    ShortGeneric,
248    /// Long generic non-location format (e.g.: `Pacific Time`, `Nordamerikanische Westküstenzeit`)
249    LongGeneric,
250}
251
252impl Display for TimeZoneNameFormat {
253    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
254        match self {
255            Self::Long => write!(f, "long"),
256            Self::Short => write!(f, "short"),
257            Self::ShortOffset => write!(f, "shortOffset"),
258            Self::LongOffset => write!(f, "longOffset"),
259            Self::ShortGeneric => write!(f, "shortGeneric"),
260            Self::LongGeneric => write!(f, "longGeneric"),
261        }
262    }
263}
264
265js_value_from_to_string!(TimeZoneNameFormat);
266
267#[derive(DefaultBuilder, Default)]
268#[cfg_attr(feature = "ssr", allow(dead_code))]
269pub struct UseIntlDateTimeFormatOptions {
270    /// A vec of strings, each with a BCP 47 language tag. Please refer to the
271    /// [MDN Docs](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/DateTimeFormat/DateTimeFormat#parameters)
272    /// for more info.
273    pub(crate) locales: Vec<String>,
274
275    /// The locale matching algorithm to use. Possible values are `Lookup` and `BestFit`; the default is `BestFit`.
276    /// For information about this option, see the [Intl page](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl#locale_identification_and_negotiation).
277    locale_matcher: LocaleMatcher,
278
279    /// The calendar to use, such as `"chinese"`, `"gregory"`, `"persian"` etc. For a list of the
280    /// supported calendar types, see [the MDN docs](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/Locale/getCalendars#supported_calendar_types).
281    #[builder(into)]
282    calendar: Option<String>,
283
284    /// The way day periods should be expressed. This option only has an effect if a 12-hour clock
285    /// (`hour_cycle` `H11` or `H12`, or `hour12` is `true`) is used. Note that the day period may
286    /// be displayed even if the `hour` is not set to be displayed.
287    #[builder(into)]
288    day_period: Option<DayPeriodFormat>,
289
290    /// The numbering system to use. Possible values include: `"arab"`, `"arabext"`, `"bali"`, `"beng"`, `"deva"`, `"fullwide"`, `"gujr"`, `"guru"`, `"hanidec"`, `"khmr"`, `"knda"`, `"laoo"`, `"latn"`, `"limb"`, `"mlym"`, `"mong"`, `"mymr"`, `"orya"`, `"tamldec"`, `"telu"`, `"thai"`, `"tibt"`.
291    #[builder(into)]
292    numbering_system: Option<String>,
293
294    /// Whether to use 12-hour time (as opposed to 24-hour time). The default is locale dependent.
295    /// This option overrides the `hc` language tag and/or the `hour_cycle` option in case both are present.
296    #[builder(into)]
297    hour12: Option<bool>,
298
299    /// The hour cycle to use. This option overrides the `hc` language tag, if both are present, and
300    /// the `hour12` option takes precedence in case both options have been specified.
301    ///
302    /// - `H11`: hour system using 0–11; corresponds to midnight starting at 0:00 AM.
303    /// - `H12`: hour system using 1–12; corresponds to midnight starting at 12:00 AM.
304    /// - `H23`: hour system using 0–23; corresponds to midnight starting at 0:00.
305    /// - `H24`: hour system using 1–24; corresponds to midnight starting at 24:00.
306    #[builder(into)]
307    hour_cycle: Option<HourCycle>,
308
309    /// The time zone to use. The only value implementations must recognize is `"UTC"`; the default
310    /// is the runtime's default time zone. Implementations may also recognize the time zone names
311    /// of the [IANA time zone database](https://www.iana.org/time-zones), such as `"Asia/Shanghai"`,
312    /// `"Asia/Kolkata"`, `"America/New_York"`.
313    #[builder(into)]
314    time_zone: Option<String>,
315
316    /// The format matching algorithm to use. Possible values are `Basic` and `BestFit`; the default
317    /// is `BestFit`. See the [MDN docs](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/DateTimeFormat/DateTimeFormat#formatmatcher)
318    /// for details. Only has an effect when using the individual date-time component options
319    /// (and not [`UseIntlDateTimeFormatOptions::date_style`] / [`UseIntlDateTimeFormatOptions::time_style`]).
320    format_matcher: FormatMatcher,
321
322    /// The representation of the weekday.
323    ///
324    /// - `Long`: e.g., `Thursday`
325    /// - `Short`: e.g., `Thu`
326    /// - `Narrow`: e.g., `T`. Two weekdays may have the same narrow style for some locales (e.g. `Tuesday`'s narrow style is also `T`).
327    ///
328    /// Cannot be combined with [`UseIntlDateTimeFormatOptions::date_style`] / [`UseIntlDateTimeFormatOptions::time_style`].
329    #[builder(into)]
330    weekday: Option<WeekdayFormat>,
331
332    /// The representation of the era.
333    ///
334    /// - `Long`: e.g., `Anno Domini`
335    /// - `Short`: e.g., `AD`
336    /// - `Narrow`: e.g., `A`
337    ///
338    /// Cannot be combined with [`UseIntlDateTimeFormatOptions::date_style`] / [`UseIntlDateTimeFormatOptions::time_style`].
339    #[builder(into)]
340    era: Option<EraFormat>,
341
342    /// The representation of the year.
343    ///
344    /// - `Numeric`: e.g., `2012`
345    /// - `TwoDigit`: e.g., `12`
346    ///
347    /// Cannot be combined with [`UseIntlDateTimeFormatOptions::date_style`] / [`UseIntlDateTimeFormatOptions::time_style`].
348    #[builder(into)]
349    year: Option<YearFormat>,
350
351    /// The representation of the month.
352    ///
353    /// - `Numeric`: e.g., `3`
354    /// - `TwoDigit`: e.g., `03`
355    /// - `Long`: e.g., `March`
356    /// - `Short`: e.g., `Mar`
357    /// - `Narrow`: e.g., `M`. Two months may have the same narrow style for some locales (e.g. `May`'s narrow style is also `M`).
358    ///
359    /// Cannot be combined with [`UseIntlDateTimeFormatOptions::date_style`] / [`UseIntlDateTimeFormatOptions::time_style`].
360    #[builder(into)]
361    month: Option<MonthFormat>,
362
363    /// The representation of the day.
364    ///
365    /// - `Numeric`: e.g., `1`
366    /// - `TwoDigit`: e.g., `01`
367    ///
368    /// Cannot be combined with [`UseIntlDateTimeFormatOptions::date_style`] / [`UseIntlDateTimeFormatOptions::time_style`].
369    #[builder(into)]
370    day: Option<DayFormat>,
371
372    /// The representation of the hour.
373    ///
374    /// - `Numeric`: e.g., `1`
375    /// - `TwoDigit`: e.g., `01`
376    ///
377    /// Cannot be combined with [`UseIntlDateTimeFormatOptions::date_style`] / [`UseIntlDateTimeFormatOptions::time_style`].
378    #[builder(into)]
379    hour: Option<TimeNumericFormat>,
380
381    /// The representation of the minute.
382    ///
383    /// - `Numeric`: e.g., `1`
384    /// - `TwoDigit`: e.g., `01`
385    ///
386    /// Cannot be combined with [`UseIntlDateTimeFormatOptions::date_style`] / [`UseIntlDateTimeFormatOptions::time_style`].
387    #[builder(into)]
388    minute: Option<TimeNumericFormat>,
389
390    /// The representation of the second.
391    ///
392    /// - `Numeric`: e.g., `1`
393    /// - `TwoDigit`: e.g., `01`
394    ///
395    /// Cannot be combined with [`UseIntlDateTimeFormatOptions::date_style`] / [`UseIntlDateTimeFormatOptions::time_style`].
396    #[builder(into)]
397    second: Option<TimeNumericFormat>,
398
399    /// The number of digits used to represent fractions of a second (any additional digits are
400    /// truncated). Possible values are from `1` to `3`.
401    #[builder(into)]
402    fractional_second_digits: Option<u8>,
403
404    /// The localized representation of the time zone name.
405    ///
406    /// - `Long`: long localized form (e.g., `Pacific Standard Time`).
407    /// - `Short`: short localized form (e.g.: `PST`).
408    /// - `ShortOffset`: short localized GMT format (e.g., `GMT-8`).
409    /// - `LongOffset`: long localized GMT format (e.g., `GMT-0800`).
410    /// - `ShortGeneric`: short generic non-location format (e.g.: `PT`).
411    /// - `LongGeneric`: long generic non-location format (e.g.: `Pacific Time`).
412    #[builder(into)]
413    time_zone_name: Option<TimeZoneNameFormat>,
414
415    /// The date formatting length. Cannot be combined with the individual date-time component
416    /// options (`weekday`, `era`, `year`, `month`, `day`, `hour`, `minute`, `second`,
417    /// `fractional_second_digits`, `time_zone_name`, `day_period`).
418    ///
419    /// Possible values are `Full`, `Long`, `Medium` and `Short`.
420    #[builder(into)]
421    date_style: Option<DateTimeStyle>,
422
423    /// The time formatting length. Cannot be combined with the individual date-time component
424    /// options (`weekday`, `era`, `year`, `month`, `day`, `hour`, `minute`, `second`,
425    /// `fractional_second_digits`, `time_zone_name`, `day_period`).
426    ///
427    /// Possible values are `Full`, `Long`, `Medium` and `Short`.
428    #[builder(into)]
429    time_style: Option<DateTimeStyle>,
430}
431
432impl UseIntlDateTimeFormatOptions {
433    /// A string with a BCP 47 language tag. Please refer to the
434    /// [MDN Docs](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/DateTimeFormat/DateTimeFormat#parameters)
435    /// for more info.
436    pub fn locale(self, locale: &str) -> Self {
437        Self {
438            locales: vec![locale.to_string()],
439            ..self
440        }
441    }
442}
443
444impl From<UseIntlDateTimeFormatOptions> for js_sys::Object {
445    fn from(options: UseIntlDateTimeFormatOptions) -> Self {
446        let object = Self::new();
447
448        _ = js!(object["localeMatcher"] = options.locale_matcher);
449        _ = js!(object["formatMatcher"] = options.format_matcher);
450
451        if let Some(calendar) = options.calendar {
452            _ = js!(object["calendar"] = calendar);
453        }
454        if let Some(day_period) = options.day_period {
455            _ = js!(object["dayPeriod"] = day_period);
456        }
457        if let Some(numbering_system) = options.numbering_system {
458            _ = js!(object["numberingSystem"] = numbering_system);
459        }
460        if let Some(hour12) = options.hour12 {
461            _ = js!(object["hour12"] = hour12);
462        }
463        if let Some(hour_cycle) = options.hour_cycle {
464            _ = js!(object["hourCycle"] = hour_cycle);
465        }
466        if let Some(time_zone) = options.time_zone {
467            _ = js!(object["timeZone"] = time_zone);
468        }
469        if let Some(weekday) = options.weekday {
470            _ = js!(object["weekday"] = weekday);
471        }
472        if let Some(era) = options.era {
473            _ = js!(object["era"] = era);
474        }
475        if let Some(year) = options.year {
476            _ = js!(object["year"] = year);
477        }
478        if let Some(month) = options.month {
479            _ = js!(object["month"] = month);
480        }
481        if let Some(day) = options.day {
482            _ = js!(object["day"] = day);
483        }
484        if let Some(hour) = options.hour {
485            _ = js!(object["hour"] = hour);
486        }
487        if let Some(minute) = options.minute {
488            _ = js!(object["minute"] = minute);
489        }
490        if let Some(second) = options.second {
491            _ = js!(object["second"] = second);
492        }
493        if let Some(fractional_second_digits) = options.fractional_second_digits {
494            _ = js!(object["fractionalSecondDigits"] = fractional_second_digits);
495        }
496        if let Some(time_zone_name) = options.time_zone_name {
497            _ = js!(object["timeZoneName"] = time_zone_name);
498        }
499        if let Some(date_style) = options.date_style {
500            _ = js!(object["dateStyle"] = date_style);
501        }
502        if let Some(time_style) = options.time_style {
503            _ = js!(object["timeStyle"] = time_style);
504        }
505
506        object
507    }
508}