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}