Skip to main content

Crate cratefield_i18n

Crate cratefield_i18n 

Source
Expand description

cratefield-i18n: the strings a venture owns, in the languages it owns them in (issue #190).

Nothing here is notification-specific. A Catalog answers “render message booking-confirmed, attribute .title, in id-ID”, and the caller decides what to do with the answer — a push title, a mail subject, a waitlist template.

use cratefield_i18n::{Args, Catalog, FluentCatalog, TITLE, localize};

let catalog = FluentCatalog::builder()
    .default_locale("en")
    .locale("en", "booking-confirmed =\n    .title = Booking confirmed\n")
    .locale("id", "booking-confirmed =\n    .title = Pesanan dikonfirmasi\n")
    .build()
    .expect("the catalog parses");

let asked = "id-ID".parse().expect("a language tag");
let rendered = localize(&catalog, &asked, "booking-confirmed", TITLE, &Args::new());
assert_eq!(rendered.text, "Pesanan dikonfirmasi");
assert_eq!(rendered.locale.to_string(), "id"); // id-ID negotiated down to id
assert!(!rendered.missing);

§The three things this crate exists to get right

Thread safety. The default FluentBundle is built on Rc and RefCell: it is neither Send nor Sync, so it cannot live behind a port that is. SendWrapper does not fix it — that grants Send alone, and panics if the value is dropped on another thread. This crate uses the concurrent memoizer (Arc/RwLock) instead, and a static assertion in the fluent module pins it so the day somebody swaps the import back is a compile error rather than a runtime one.

Direction. unic-langid parses language identifiers and carries no directionality data at all: there is no is_rtl() to call. Direction therefore comes from an explicit script and language list here — see direction — and is tested.

A missing key is visible. localize never returns an empty string for a key the catalog does not have. It renders the key itself and sets Localized::missing, so the caller can say so on the bus and whoever reads the notification sees booking-confirmed.title rather than a blank line.

§What a caller must not do with the answer

Args values come from the caller of a notification — a coach’s name, a place, a booking reference. A rendered string is therefore personal data: it belongs in the message that is delivered and nowhere else. No error, event or log line in this crate ever carries an argument value or a rendered string, and a caller must keep that boundary too.

Structs§

FluentCatalog
A catalog built from embedded .ftl sources.
FluentCatalogBuilder
Assembles a FluentCatalog.
LanguageIdentifier
LanguageIdentifier is a core struct representing a Unicode Language Identifier.
Localized
One rendered string, and what it took to get there.
Missing
One key.attribute a locale does not have, as the completeness check reports it.
StaticCatalog
A catalog of literal strings.

Enums§

CatalogError
Why a catalog could not be built.
Direction
Which way a locale’s text runs, as dir takes it.

Constants§

BODY
The attribute a body is stored under.
SUBJECT
The attribute a mail subject is stored under, where a venture wants one that is not the title.
TITLE
The attribute a title is stored under: booking-confirmed.title.

Traits§

Catalog
A catalog of a venture’s own strings.

Functions§

accept_language
The locales header asks for, best first.
direction
Which way locale’s text runs.
localize
Renders key.attribute for a recipient who asked for requested.
missing_messages
Every key.attribute pair that some locale in catalog cannot render, in locale order then key order.
missing_text
What a message no locale has renders as: the key and the attribute, exactly as a caller wrote them.
parse_locale
The one place a language tag enters this system from outside it.

Type Aliases§

Args
The placeables a message is rendered with: { $coach }, { $count }.