Skip to main content

mf2_locale_data/
lib.rs

1//! `mf2-locale-data` — the locale data Rust MF2 catalogs carry, build side
2//! only: never linked into a client.
3//!
4//! The crate ships its data, derived from Unicode CLDR, in `data/`: a build
5//! downloads nothing. From CLDR's JSON:
6//!
7//! * **plural** rules and each locale's **text direction**: the UTS #35 rule parser, the canonical encoder
8//!   of the `plural.cardinal` / `plural.ordinal` entries; the CLDR
9//!   `@integer`/`@decimal` samples of every locale are tests of the client
10//!   evaluator;
11//! * **numbers**, from every locale's `numbers.json`: symbols, grouping, numbering systems and
12//!   their digits, the percent and currency patterns, deduplicated against
13//!   CLDR's parent locales (`data/numbers.txt`), and the `number.symbols` /
14//!   `number.patterns` entries built from them (`number`);
15//! * **currencies and units**, from every locale's `currencies.json` and
16//!   `units.json`
17//!   (`data/currencies.txt`, `data/units.txt`, deduplicated against the
18//!   parents and CLDR's fallbacks), and the `currency.data` / `unit.data`
19//!   entries for the configured sets (`currency`, `unit`);
20//! * **language matching**, from `likelySubtags.json`,
21//!   `languageMatching.json` and `territoryContainment.json`
22//!   (`data/matching.txt`): what `mf2`'s one locale matcher reads, cut to a
23//!   corpus's languages for its generated module (`matching`).
24//!
25//! A corpus's needs — which entries, which currencies and units — are
26//! `LocaleNeeds` / `NumberNeeds` (`NumberNeeds::add_message` reads them
27//! off the data model); `locale_entries` writes the entries.
28//!
29//! # What 2.x promises here
30//!
31//! `mf2-build` and `mf2`'s `compile` feature use this crate; an application
32//! never names it. Its tables and entry builders are the catalog's layout,
33//! which 1.x does not promise (`docs/versioning.md`), so they are hidden
34//! from the documentation. What is promised: the errors a build can return
35//! from here ([`Error`], [`ParseError`]), the CLDR release the data comes
36//! from ([`CLDR_VERSION`]) and a locale's text [`direction`].
37//!
38//! # The user guide
39//!
40//! The [Rust MF2 book](https://evancarroll.github.io/rust-mf2/) is the user
41//! guide: how the crates fit together, web and native applications, the
42//! command line, and what 2.x promises.
43//! An application reaches this crate through `mf2-build`
44//! and [`mf2`](https://docs.rs/mf2)'s `compile` feature.
45
46#![warn(missing_docs)]
47// docs.rs (`cargo xtask docs-rs`): each feature-gated item says which features it needs.
48#![cfg_attr(docsrs, feature(doc_cfg))]
49
50#[doc(hidden)]
51pub mod blocks;
52#[doc(hidden)]
53pub mod currency;
54mod direction;
55mod error;
56#[cfg(feature = "extract")]
57#[doc(hidden)]
58pub mod extract;
59#[cfg(feature = "icu-blob")]
60#[doc(hidden)]
61pub mod icu_blob;
62#[doc(hidden)]
63pub mod matching;
64#[doc(hidden)]
65pub mod number;
66#[doc(hidden)]
67pub mod plural;
68#[doc(hidden)]
69pub mod template;
70#[doc(hidden)]
71pub mod unit;
72
73#[doc(hidden)]
74pub use currency::CurrencyData;
75pub use direction::direction;
76pub use error::{Error, ParseError};
77pub use mf2_catalog::CldrVersion;
78#[doc(hidden)]
79pub use number::{
80    CurrencyNeeds, NumberData, NumberNeeds, Selection, UnitNeeds, number_data,
81    number_locale_entries, number_locales,
82};
83#[doc(hidden)]
84pub use plural::{
85    LocaleRules, PluralKind, plural_entry, plural_locale_entries, plural_locales, plural_rules,
86};
87#[doc(hidden)]
88pub use unit::{UnitData, composition, unit_ids};
89
90/// The CLDR release the shipped data comes from (`third_party/cldr-json/PIN`).
91pub const CLDR_VERSION: CldrVersion = CldrVersion {
92    major: 48,
93    minor: 2,
94    patch: 1,
95};
96
97/// Everything a corpus needs of its locale's data: plural rules of each
98/// kind it selects on, and number data ([`NumberNeeds`]). The slicing rule
99/// is `plans/02-catalog-format.md` §4.4. Build one with `default()` and set
100/// fields.
101#[derive(Clone, Debug, Default, PartialEq, Eq)]
102#[non_exhaustive]
103#[doc(hidden)]
104pub struct LocaleNeeds {
105    /// Some selector uses `select=plural` (the default) → `plural.cardinal`.
106    pub cardinal: bool,
107    /// Some selector uses `select=ordinal` → `plural.ordinal`.
108    pub ordinal: bool,
109    /// The number entries.
110    pub numbers: NumberNeeds,
111}
112
113/// The LOCALE entries a catalog for `locale` carries under `needs`, sorted by
114/// key, as `mf2_catalog::writer::Options::locale_entries` takes them;
115/// `plural.cardinal` also when units or currency names need it.
116#[doc(hidden)]
117pub fn locale_entries(locale: &str, needs: &LocaleNeeds) -> Result<Vec<(u32, Vec<u8>)>, Error> {
118    let mut kinds = Vec::new();
119    if needs.cardinal || needs.numbers.needs_cardinal() {
120        kinds.push(PluralKind::Cardinal);
121    }
122    if needs.ordinal {
123        kinds.push(PluralKind::Ordinal);
124    }
125    let mut out = plural_locale_entries(locale, &kinds)?;
126    out.extend(number_locale_entries(locale, &needs.numbers)?);
127    out.sort_by_key(|(k, _)| *k);
128    Ok(out)
129}