es-fluent 0.19.0

Type-safe Fluent localization derives and runtime traits for Rust applications
Documentation
#![cfg(all(feature = "derive", feature = "icu-datetime"))]

use es_fluent::registry::StaticFluentMessageKey;
use es_fluent::{EsFluent, FluentArgs, FluentMessage, FluentValue};
use std::collections::HashMap;
use std::time::{Duration, SystemTime, UNIX_EPOCH};

#[derive(EsFluent)]
struct StdTimeMessage<'a> {
    system_time: SystemTime,
    borrowed_system_time: &'a SystemTime,
    maybe_system_time_present: Option<SystemTime>,
    maybe_system_time_missing: Option<SystemTime>,
    maybe_borrowed_system_time_present: Option<&'a SystemTime>,
    maybe_borrowed_system_time_missing: Option<&'a SystemTime>,
    #[fluent(value = |value: &SystemTime| *value)]
    transformed_system_time: SystemTime,
}

#[derive(EsFluent)]
struct StdDurationMessage<'a> {
    duration: Duration,
    borrowed_duration: &'a Duration,
    maybe_duration_present: Option<Duration>,
    maybe_duration_missing: Option<Duration>,
    maybe_borrowed_duration_present: Option<&'a Duration>,
    maybe_borrowed_duration_missing: Option<&'a Duration>,
    #[fluent(value = |value: &Duration| *value)]
    transformed_duration: Duration,
}

fn render_args(message: &impl FluentMessage, language: &str) -> HashMap<String, String> {
    let mut rendered = HashMap::new();
    let intls = intl_memoizer::IntlLangMemoizer::new(language.parse().unwrap());
    message.to_fluent_string_with(
        &mut |_key: StaticFluentMessageKey, args: Option<&FluentArgs<'_>>| {
            for (name, value) in args.expect("std time message arguments").as_raw() {
                let value = match value {
                    FluentValue::Custom(value) => value.as_string(&intls).into_owned(),
                    FluentValue::None => "<none>".to_string(),
                    other => panic!("expected an ICU4X Fluent custom value, got {other:?}"),
                };
                rendered.insert(name.as_str().to_string(), value);
            }
            "rendered".to_string()
        },
    );
    rendered
}

#[test]
fn derived_messages_accept_owned_borrowed_and_optional_system_times() {
    let system_time = UNIX_EPOCH + Duration::from_secs(1_784_035_815);
    let borrowed_system_time = system_time + Duration::from_secs(3_600);
    let args = render_args(
        &StdTimeMessage {
            system_time,
            borrowed_system_time: &borrowed_system_time,
            maybe_system_time_present: Some(system_time + Duration::from_secs(86_400)),
            maybe_system_time_missing: None,
            maybe_borrowed_system_time_present: Some(&borrowed_system_time),
            maybe_borrowed_system_time_missing: None,
            transformed_system_time: system_time,
        },
        "en-US",
    );

    assert_eq!(args["system_time"], "Jul 14, 2026, 1:30:15\u{202f}PM GMT+0");
    assert_eq!(
        args["borrowed_system_time"],
        "Jul 14, 2026, 2:30:15\u{202f}PM GMT+0"
    );
    assert_eq!(
        args["maybe_system_time_present"],
        "Jul 15, 2026, 1:30:15\u{202f}PM GMT+0"
    );
    assert_eq!(args["maybe_system_time_missing"], "<none>");
    assert_eq!(
        args["maybe_borrowed_system_time_present"],
        "Jul 14, 2026, 2:30:15\u{202f}PM GMT+0"
    );
    assert_eq!(args["maybe_borrowed_system_time_missing"], "<none>");
    assert_eq!(
        args["transformed_system_time"],
        "Jul 14, 2026, 1:30:15\u{202f}PM GMT+0"
    );
}

#[test]
fn derived_messages_accept_owned_borrowed_and_optional_std_durations() {
    let duration = Duration::from_secs(3_723);
    let args = render_args(
        &StdDurationMessage {
            duration,
            borrowed_duration: &duration,
            maybe_duration_present: Some(duration),
            maybe_duration_missing: None,
            maybe_borrowed_duration_present: Some(&duration),
            maybe_borrowed_duration_missing: None,
            transformed_duration: duration,
        },
        "fr-FR",
    );
    let expected = "1\u{202f}h, 2\u{a0}min et 3\u{202f}s";

    assert_eq!(args["duration"], expected);
    assert_eq!(args["borrowed_duration"], expected);
    assert_eq!(args["maybe_duration_present"], expected);
    assert_eq!(args["maybe_duration_missing"], "<none>");
    assert_eq!(args["maybe_borrowed_duration_present"], expected);
    assert_eq!(args["maybe_borrowed_duration_missing"], "<none>");
    assert_eq!(args["transformed_duration"], expected);
}