Locale and Localizations
Purpose
The interface's language, and the words the framework says in it.
Signature
pub struct Locale { .. }
pub trait Localizations { .. }
Example

From frus-examples/widgets/src/features/state/widgets/localizations.rs:
//! `Locale` and `Localizations` — the language the interface is in, and the words the
//! framework itself says in it: button labels a screen reader announces, month names in a
//! date picker, "1–10 of 100" under a table, digit grouping.
//!
//! The application states which languages it has and, optionally, the one the reader
//! picked; `locale::of()` and `localizations::of()` answer from anywhere. Your own
//! strings come from your own translation files, chosen by `locale::of()`.
use std::rc::Rc;
use frus::{
component, host, locale, localizations, Align, Callback, Column, English, French, Locale, Row,
SegmentedButton, Text, Widget,
};
use crate::common::shared::{section, sections};
pub fn example() -> Box<dyn Widget> {
Box::new(component(|cx| {
let scheme = &cx.theme().scheme;
let current = locale::of();
let french = current.language_code() == "fr";
// Switching changes the whole application, on the next frame.
let picker = SegmentedButton::new(usize::from(french), |index| {
Callback::new(move || {
let app = host::app();
app.set_supported_locales(vec![Locale::new("en"), Locale::new("fr")]);
if index == 1 {
app.set_locale(Some(Locale::new("fr")));
app.set_localizations(Some(Rc::new(French)));
} else {
app.set_locale(Some(Locale::new("en")));
app.set_localizations(Some(Rc::new(English)));
}
})
})
.segment("English")
.segment("Français");
// The table in force. It always answers: English when nothing is installed.
let words = localizations::of();
let months = words.months();
let lines = [
("locale::of()", current.to_string()),
(
"ok / cancel",
format!(
"{} / {}",
words.ok_button_label(),
words.cancel_button_label()
),
),
("back button", words.back_button_label().to_string()),
("first months", months[..3].join(", ")),
("narrow weekdays", words.narrow_weekdays().join(" ")),
(
"page_range_label(1, 10, 1234)",
words.page_range_label(1, 10, 1234),
),
("group_digits(1234567)", words.group_digits(1_234_567)),
];
let table = lines.into_iter().fold(
Column::new()
.spacing(6.0)
.cross_axis_alignment(Align::Start),
|column, (name, value)| {
column.child(
Row::new()
.spacing(8.0)
.child(Text::new(name).size(12.0).color(scheme.on_surface_variant))
.child(Text::new(value)),
)
},
);
sections(vec![
Box::new(section("The application's language", picker)),
Box::new(section("What the framework says", table)),
])
}))
}
Properties
No builder methods: everything is set through the constructor.
Behaviour
Locale
Comparison is exact — fr is not fr-CA. Deciding that one of them will do for the other is resolve's work, and it takes the whole list to do it.
Localizations
What the framework says, for one language.
Every method has an English body, so implementing this means writing down only what differs.
A default is not agreement. An entry left unanswered is an English string in a French interface, and it compiles. So a table shipped here writes out every entry, even the ones whose right answer in that language is the English one — "OK" is "OK" in a good many languages — with the reason beside it; French does, and a test reads this file to check that it still does.
See also
- MediaQuery & MediaScope: the screen's size, insets, text scale, brightness and size class.
- Responsive, LayoutBuilder & OrientationBuilder: one interface, several layouts, by window or by box.
- The guide: Starting a frus application
- API reference:
Locale - API reference:
Localizations
Source: crates/frus-widgets/src/locale.rs, crates/frus-widgets/src/localizations.rs @ e6fba33f5b42