use std::sync::Arc;
use qframe::date::Date;
use qframe::i18n::I18n;
fn in_language<R>(code: &str, f: impl FnOnce() -> R) -> R {
let mut i18n = I18n::builtin();
assert!(i18n.set_active(code), "{code} is a built-in language");
qframe::i18n::scope(Arc::new(i18n), f)
}
#[test]
fn a_language_that_writes_a_comma_gets_a_comma() {
for code in ["en", "ja", "zh-Hans"] {
assert_eq!(in_language(code, || qframe::i18n::number(0.5, 1)), "0.5", "{code}");
assert_eq!(in_language(code, qframe::i18n::decimal_separator), '.', "{code}");
}
for code in ["de", "fr", "es", "ru", "pt-BR", "tr"] {
assert_eq!(in_language(code, || qframe::i18n::number(0.5, 1)), "0,5", "{code}");
assert_eq!(in_language(code, qframe::i18n::decimal_separator), ',', "{code}");
}
assert_eq!(in_language("fr", || qframe::i18n::number(12.0, 0)), "12");
}
#[test]
fn every_language_says_what_it_writes_between_a_number_and_its_decimals() {
let i18n = I18n::builtin();
for (code, _) in i18n.list() {
assert!(i18n.has(&code, "quvyta.number.decimal"), "{code} gives its own separator");
}
}
#[test]
fn a_date_reads_in_the_order_its_language_writes_dates_in_every_form() {
let day = Date::new(2026, 9, 18).expect("a real date");
let cases = [
("en", "September 18, 2026", "Sep 18, 2026", "September 18", "Sep 18"),
("tr", "18 Eylül 2026", "18 Eyl 2026", "18 Eylül", "18 Eyl"),
("de", "18. September 2026", "18. Sep 2026", "18. September", "18. Sep"),
("ja", "2026年9月18日", "2026年9月18日", "9月18日", "9月18日"),
];
for (code, long, short, day_month, day_month_short) in cases {
assert_eq!(in_language(code, || day.written()), long, "{code}");
assert_eq!(in_language(code, || day.written_short()), short, "{code}");
assert_eq!(in_language(code, || day.day_and_month()), day_month, "{code}");
assert_eq!(in_language(code, || day.day_and_month_short()), day_month_short, "{code}");
}
}
#[test]
fn every_language_gives_the_day_and_month_with_the_whole_month_name() {
let i18n = I18n::builtin();
for (code, _) in i18n.list() {
assert!(i18n.has(&code, "quvyta.date.format-day-month-long"), "{code} gives the heading form");
}
}
#[test]
fn the_chinese_minute_is_one_character_beside_a_number() {
let unit = in_language("zh-Hans", || qframe::t!("quvyta.duration.minutes"));
assert_eq!(unit, "分");
let span = in_language("zh-Hans", || qframe::t!("quvyta.time.hours-minutes", hours = 1, minutes = 30));
assert_eq!(span, "1小时30分");
let words = in_language("zh-Hans", || qframe::t!("quvyta.duration.minute-words"));
assert!(words.contains("分钟"), "{words}");
}
mod screen {
use qframe::date::Date;
use qframe::prelude::*;
use qframe::widgets::{Bar, BarChart, DatePicker, DurationInput, NumberInput};
#[derive(Default)]
pub struct Customs {
pub hours: f64,
}
impl App for Customs {
type Msg = f64;
fn update(&mut self, hours: f64) -> Command<f64> {
self.hours = hours;
Command::none()
}
fn view(&self, ui: &mut View<'_, f64>) {
ui.add(BarChart::new([Bar::new("Mon", 0.5)]).unit("h")).fill_width().id("chart");
ui.add(NumberInput::new(self.hours).range(0.0, 9.0).step(0.5).on_change(|value| value))
.width(Length::Cells(12))
.id("number");
ui.add(DurationInput::new(std::time::Duration::from_secs(90 * 60))).width(Length::Cells(16)).id("duration");
ui.add(DatePicker::new(Date::new(2026, 9, 18))).width(Length::Cells(30)).id("date");
}
}
}
#[test]
fn the_numbers_dates_and_units_a_screen_draws_follow_its_language() {
use qframe::runtime::Harness;
let mut h = Harness::new(screen::Customs { hours: 1.5 }, 40, 12);
assert!(h.screen().contains("0.5 h"), "English writes a point:\n{}", h.screen());
assert!(h.screen().contains("1.5"), "and so does the field:\n{}", h.screen());
assert!(h.screen().contains("September 18, 2026"), "{}", h.screen());
h.set_locale("fr");
assert!(h.screen().contains("0,5 h"), "French writes a comma in the chart:\n{}", h.screen());
assert!(h.screen().contains("1,5"), "and in the field:\n{}", h.screen());
assert!(h.screen().contains("18 septembre 2026"), "and the date reads in French order:\n{}", h.screen());
h.set_locale("zh-Hans");
assert!(h.screen().contains("分"), "{}", h.screen());
assert!(!h.screen().contains("分钟"), "the long word does not fit beside a number:\n{}", h.screen());
}