Skip to main content

citum_schema_style/locale/
date_patterns.rs

1/*
2SPDX-License-Identifier: MIT OR Apache-2.0
3SPDX-FileCopyrightText: © 2023-2026 Bruce D'Arcus and Citum contributors
4*/
5
6use super::Locale;
7use super::message::MessageArgs;
8use super::types::MessageSyntax;
9
10impl Locale {
11    /// Resolve a `pattern.date-*` message with locale-specific year/month/day
12    /// components.
13    ///
14    /// Returns `Some(rendered)` only when the locale carries an MF2 message
15    /// at `message_id` and the evaluator produces output. Callers fall back
16    /// to the engine's hardcoded English assembly on `None`.
17    ///
18    /// A component is forwarded to the evaluator only when non-empty; an
19    /// authored pattern that references `{$day}` therefore yields `None` if
20    /// the input date carries no day, letting the caller pick a shorter form.
21    ///
22    /// The day argument is taken as `Option<u32>` rather than a pre-formatted
23    /// string so the digit-to-string allocation is deferred until after the
24    /// message lookup succeeds - the common case for legacy locales (`en-US`,
25    /// every v1 file) is the lookup miss, which now incurs zero allocation.
26    pub fn resolve_date_pattern(
27        &self,
28        message_id: &str,
29        year: Option<&str>,
30        month: Option<&str>,
31        day: Option<u32>,
32    ) -> Option<String> {
33        let message = self.messages.get(message_id)?;
34        if self.evaluation.message_syntax == MessageSyntax::Static {
35            return None;
36        }
37
38        let day_str = day.map(|d| d.to_string());
39        let args = MessageArgs {
40            year: year.filter(|s| !s.is_empty()),
41            month: month.filter(|s| !s.is_empty()),
42            day: day_str.as_deref(),
43            ..MessageArgs::default()
44        };
45        self.evaluator.evaluate(message, &args)
46    }
47
48    /// Resolve a shared-year `pattern.date-range-*` message with pre-formatted
49    /// endpoint fragments and their common year.
50    ///
51    /// The message is evaluated only for MF2 locales. Callers fall back to
52    /// their established date-form assembly when a locale has not authored
53    /// the requested interval pattern.
54    pub fn resolve_date_range_pattern(
55        &self,
56        message_id: &str,
57        start: &str,
58        end: &str,
59        year: Option<&str>,
60    ) -> Option<String> {
61        let message = self.messages.get(message_id)?;
62        if self.evaluation.message_syntax == MessageSyntax::Static {
63            return None;
64        }
65
66        let args = MessageArgs {
67            start: (!start.is_empty()).then_some(start),
68            end: (!end.is_empty()).then_some(end),
69            year: year.filter(|value| !value.is_empty()),
70            ..MessageArgs::default()
71        };
72        self.evaluator.evaluate(message, &args)
73    }
74}