Use full `Locale` instead of `LanguageIdentifier` subset

finchie
Jul 22, 2025, 1:59 AM
6XEMHUGSNX5YSWZYM7PZUTTUMFODMGO74QLHGEXQ5LAC7LPS7JNQC

Dependencies

  • [2] LIO32J4B Fix compiler error when `expand` feature is disabled
  • [3] VJCANIBG Move `old_locale_version` hack out of `Localize` trait
  • [4] AAERM7PB Add selector tests for the `fr` locale
  • [5] BFL2Y7GN Add relative timestamps using `jiff` and `icu_relativetime`
  • [6] 3NMKD6I5 Refactor `Localize` trait to use `std::io::Write`
  • [7] UN2XEIEU Migrate from `locale_select` to `env_preferences`
  • [8] WWDZWJTR Implement `Localize` for string types
  • [9] C6W7N6N5 Implement `Localize` for `FixedDecimal` and primitive number types
  • [10] 7U2DXFMP Refactor `fluent_embed::Localize` to support overriding locales
  • [11] 73C6NOJ7 Fix minimal `Localize` implementation on errors
  • [12] JWZT34UC Add `Localize`` trait bound for each field in the derived item
  • [13] IRW6JACS Implement `Localize` for `RelativeTime`
  • [14] K3G4HK2J Track Fluent files using `include!`
  • [15] XGRU7WZE Add `expand` feature for proc-macro debugging
  • [16] RUFPE6OO Include canonical locale in list of available locales
  • [17] CESJ4CTO Move macro-specific code into `macro_impl` module
  • [18] MWN4CAOZ Update `LocalizationError` in `fluent_embed`
  • [19] GJMBIJOE Migrate to latest env_preferences version
  • [20] OWXLFLRM Merge `cli_macros` shim into `fluent_embed`
  • [21] MABGENI7 Refactor `fluent_embed_derive` tests
  • [22] QJC4IQIT Refactor `Localize` functions to infallibly return `String`
  • [23] 5I5NR4DQ Make `Localize::CANONICAL_LOCALE` a function instead of associated constant
  • [24] S2444K42 Refactor selectors test to not rely on funciton calls
  • [25] QSK7JRBA Add simple `attribute_path` function
  • [26] KF65O6OD Add tests for placeables
  • [27] XEEXWJLG Add simple end-to-end test for selectors
  • [28] 7M4UI3TW Update dependencies to latest versions
  • [29] 4BMW4JJO Add support for deriving items with generics
  • [30] 7JPOCQEI Add explicit error handling for macro parsing
  • [31] U2PHMYPD Return `String` directly instead of writing to buffer in `Localize::localize`
  • [32] LU6IFZFG Remove `std::io::Write` trait bound from `Localize`
  • [33] HHJDRLLN Create `fluent_embed_runtime` crate
  • [34] QM64L3XO Replace `duplicate` macro with `macro_rules!`
  • [35] 6ABVDTXZ Improve `fluent_embed_derive` test suite
  • [*] XGNME3WR Move `Group::derive_enum` to new `crate::parse_macro` module
  • [*] O77KA6C4 Create `fluent_embed` crate

Change contents

  • replacement in fluent_embed_derive/tests/selectors.rs at line 7
    [4.70][4.0:46](),[4.40][4.0:46]()
    use icu_locale::{langid, LanguageIdentifier};
    [4.70]
    [4.0]
    use icu_locale::{Locale, locale};
  • replacement in fluent_embed_derive/tests/selectors.rs at line 17
    [4.65][4.46:244]()
    #[case::zero_en(langid!("en-US"), 0, "You have 0 unread emails.")]
    #[case::one_en(langid!("en-US"), 1, "You have 1 unread email.")]
    #[case::two_en(langid!("en-US"), 2, "You have 2 unread emails.")]
    [4.65]
    [4.244]
    #[case::zero_en(locale!("en-US"), 0, "You have 0 unread emails.")]
    #[case::one_en(locale!("en-US"), 1, "You have 1 unread email.")]
    #[case::two_en(locale!("en-US"), 2, "You have 2 unread emails.")]
  • replacement in fluent_embed_derive/tests/selectors.rs at line 21
    [4.260][4.260:282]()
    langid!("en-US"),
    [4.260]
    [4.282]
    locale!("en-US"),
  • replacement in fluent_embed_derive/tests/selectors.rs at line 25
    [4.356][4.356:661]()
    #[case::zero_fr(langid!("fr"), 0, "Vous avez 0 e-mail non lu.")]
    #[case::one_fr(langid!("fr"), 1, "Vous avez 1 e-mail non lu.")]
    #[case::two_fr(langid!("fr"), 2, "Vous avez 2 e-mails non lus.")]
    #[case::max_fr(langid!("fr"), u64::MAX, "Vous avez 18 446 744 073 709 551 615 e-mails non lus.")]
    [4.356]
    [4.1067]
    #[case::zero_fr(locale!("fr"), 0, "Vous avez 0 e-mail non lu.")]
    #[case::one_fr(locale!("fr"), 1, "Vous avez 1 e-mail non lu.")]
    #[case::two_fr(locale!("fr"), 2, "Vous avez 2 e-mails non lus.")]
    #[case::max_fr(locale!("fr"), u64::MAX, "Vous avez 18 446 744 073 709 551 615 e-mails non lus.")]
  • replacement in fluent_embed_derive/tests/selectors.rs at line 30
    [4.1090][4.662:702]()
    #[case] locale: LanguageIdentifier,
    [4.1090]
    [4.702]
    #[case] locale: Locale,
  • replacement in fluent_embed_derive/tests/recursive.rs at line 7
    [4.326][4.326:350]()
    use icu_locale::langid;
    [4.326]
    [4.350]
    use icu_locale::locale;
  • replacement in fluent_embed_derive/tests/recursive.rs at line 32
    [4.772][4.772:798]()
    langid!("en-US"),
    [4.772]
    [4.798]
    locale!("en-US"),
  • replacement in fluent_embed_derive/tests/recursive.rs at line 46
    [4.1031][4.1031:1057]()
    langid!("en-US"),
    [4.1031]
    [4.1057]
    locale!("en-US"),
  • replacement in fluent_embed_derive/tests/placeables.rs at line 7
    [4.70][4.47:71](),[4.176][4.47:71]()
    use icu_locale::langid;
    [4.70]
    [4.233]
    use icu_locale::locale;
  • replacement in fluent_embed_derive/tests/placeables.rs at line 25
    [4.448][4.448:474]()
    langid!("en-US"),
    [4.448]
    [4.474]
    locale!("en-US"),
  • replacement in fluent_embed_derive/tests/placeables.rs at line 39
    [4.750][4.750:776]()
    langid!("en-US"),
    [4.750]
    [4.776]
    locale!("en-US"),
  • replacement in fluent_embed_derive/tests/placeables.rs at line 54
    [4.1190][4.1190:1216]()
    langid!("en-US"),
    [4.1190]
    [4.2015]
    locale!("en-US"),
  • replacement in fluent_embed_derive/tests/lifetimes.rs at line 7
    [4.1434][4.1434:1458]()
    use icu_locale::langid;
    [4.1434]
    [4.1458]
    use icu_locale::locale;
  • replacement in fluent_embed_derive/tests/lifetimes.rs at line 20
    [4.1677][4.1677:1703]()
    langid!("en-US"),
    [4.1677]
    [4.1703]
    locale!("en-US"),
  • replacement in fluent_embed_derive/tests/lifetimes.rs at line 30
    [4.1864][4.1864:1890]()
    langid!("en-US"),
    [4.1864]
    [4.1890]
    locale!("en-US"),
  • replacement in fluent_embed_derive/tests/generics.rs at line 7
    [4.2083][4.2083:2107]()
    use icu_locale::langid;
    [4.2083]
    [4.2107]
    use icu_locale::locale;
  • replacement in fluent_embed_derive/tests/generics.rs at line 17
    [4.2237][4.2237:2312]()
    compare_message(Greeting { name }, "Hello, Ferris!", langid!("en-US"))
    [4.2237]
    [4.2312]
    compare_message(Greeting { name }, "Hello, Ferris!", locale!("en-US"))
  • replacement in fluent_embed_derive/tests/generics.rs at line 23
    [4.2355][4.2355:2434]()
    compare_message(Greeting { name }, format!("Hello, 2!"), langid!("en-US"))
    [4.2355]
    [4.2434]
    compare_message(Greeting { name }, format!("Hello, 2!"), locale!("en-US"))
  • replacement in fluent_embed_derive/tests/empty_fields.rs at line 7
    [4.2645][4.2645:2669]()
    use icu_locale::langid;
    [4.2645]
    [4.2669]
    use icu_locale::locale;
  • replacement in fluent_embed_derive/tests/empty_fields.rs at line 19
    [4.2833][4.2833:2897]()
    compare_message(Message, "Hello, world!", langid!("en-US"))
    [4.2833]
    [4.2897]
    compare_message(Message, "Hello, world!", locale!("en-US"))
  • replacement in fluent_embed_derive/tests/empty_fields.rs at line 24
    [4.2928][4.2928:2999]()
    compare_message(Empty::Message, "Hello, world!", langid!("en-US"))
    [4.2928]
    [4.2999]
    compare_message(Empty::Message, "Hello, world!", locale!("en-US"))
  • replacement in fluent_embed_derive/tests/common/mod.rs at line 2
    [4.3082][4.3082:3118]()
    use icu_locale::LanguageIdentifier;
    [4.3082]
    [4.3118]
    use icu_locale::Locale;
  • replacement in fluent_embed_derive/tests/common/mod.rs at line 4
    [4.3119][4.0:52](),[4.52][4.3180:3249](),[4.3180][4.3180:3249]()
    pub fn compare_message<L: Localize, S: AsRef<str>>(
    message: L,
    expected: S,
    locale: LanguageIdentifier,
    ) {
    [4.3119]
    [4.1028]
    pub fn compare_message<L: Localize, S: AsRef<str>>(message: L, expected: S, locale: Locale) {
  • replacement in fluent_embed_derive/src/macro_impl/mod.rs at line 171
    [4.282][4.236:398]()
    fn canonical_locale(&self) -> ::fluent_embed::icu_locale::LanguageIdentifier {
    ::fluent_embed::icu_locale::langid!(#canonical_locale)
    [4.282]
    [4.398]
    fn canonical_locale(&self) -> ::fluent_embed::icu_locale::Locale {
    ::fluent_embed::icu_locale::locale!(#canonical_locale)
  • replacement in fluent_embed_derive/src/macro_impl/mod.rs at line 175
    [4.1714][4.255:352]()
    fn available_locales(&self) -> Vec<::fluent_embed::icu_locale::LanguageIdentifier> {
    [4.1714]
    [4.383]
    fn available_locales(&self) -> Vec<::fluent_embed::icu_locale::Locale> {
  • replacement in fluent_embed_derive/src/macro_impl/mod.rs at line 181
    [4.509][4.353:426]()
    locale: &::fluent_embed::icu_locale::LanguageIdentifier,
    [4.477]
    [4.1177]
    locale: &::fluent_embed::icu_locale::Locale,
  • replacement in fluent_embed_derive/src/macro_impl/derive.rs at line 87
    [4.1776][4.413:503]()
    quote!(vec![self.canonical_locale(), #(::fluent_embed::langid!(#locale_literals)),*])
    [4.1776]
    [4.1841]
    quote!(vec![self.canonical_locale(), #(::fluent_embed::locale!(#locale_literals)),*])
  • replacement in fluent_embed_derive/src/lib.rs at line 17
    [4.5365][4.3445:3458]()
    [4.5365]
    [4.3458]
  • replacement in fluent_embed_derive/src/lib.rs at line 28
    [4.3721][2.54:128]()
    .write_to_out_dir(token_stream)
    .unwrap()
    [4.3721]
    [4.5450]
    .write_to_out_dir(token_stream)
    .unwrap()
  • replacement in fluent_embed_derive/src/lib.rs at line 44
    [4.2362][4.2362:2371]()
    [4.2362]
    [4.338]
  • edit in fluent_embed_derive/src/lib.rs at line 46
    [4.405][4.504:718](),[4.718][4.574:583](),[4.2641][4.574:583](),[4.574][4.574:583](),[4.583][4.2642:2886]()
    fn canonical_locale(&self) -> ::fluent_embed::icu_locale::LanguageIdentifier {
    ::fluent_embed::icu_locale::langid!("en-US")
    }
    fn available_locales(&self) -> Vec<::fluent_embed::icu_locale::LanguageIdentifier> {
    unimplemented!("Encountered error in derive macro")
    }
  • replacement in fluent_embed_derive/src/lib.rs at line 48
    [4.3024][4.3024:3113]()
    locale: &::fluent_embed::icu_locale::LanguageIdentifier,
    [4.2976]
    [4.1404]
    locale: &::fluent_embed::icu_locale::Locale,
  • replacement in fluent_embed_derive/src/lib.rs at line 54
    [4.5945][4.3335:3354]()
    },
    [4.5945]
    [4.3354]
    }
  • edit in fluent_embed_derive/src/lib.rs at line 58
    [4.5977][4.3506:3519]()
  • edit in fluent_embed_derive/src/lib.rs at line 62
    [4.951][4.852:853]()
  • replacement in fluent_embed/src/time.rs at line 7
    [4.221][4.719:755]()
    use icu_locale::LanguageIdentifier;
    [4.221]
    [4.1767]
    use icu_locale::Locale;
  • replacement in fluent_embed/src/time.rs at line 16
    [4.125][4.1822:1896]()
    fn message_for_locale(&self, locale: &LanguageIdentifier) -> String {
    [4.507]
    [4.990]
    fn message_for_locale(&self, locale: &Locale) -> String {
  • replacement in fluent_embed/src/string.rs at line 6
    [4.139][4.756:792]()
    use icu_locale::LanguageIdentifier;
    [4.139]
    [4.215]
    use icu_locale::Locale;
  • replacement in fluent_embed/src/string.rs at line 11
    [4.639][4.391:474]()
    fn message_for_locale(&self, _locale: &LanguageIdentifier) -> String {
    [4.95]
    [4.474]
    fn message_for_locale(&self, _locale: &Locale) -> String {
  • replacement in fluent_embed/src/lib.rs at line 9
    [4.2736][4.0:56]()
    pub use icu_locale::{self, LanguageIdentifier, langid};
    [4.2736]
    [4.2792]
    pub use icu_locale::{self, Locale, locale};
  • replacement in fluent_embed/src/lib.rs at line 18
    [4.730][4.793:866]()
    fn message_for_locale(&self, locale: &LanguageIdentifier) -> String;
    [4.730]
    [4.866]
    fn message_for_locale(&self, locale: &Locale) -> String;
  • replacement in fluent_embed/src/lib.rs at line 20
    [4.867][4.867:947]()
    fn canonical_locale(&self) -> LanguageIdentifier {
    langid!("en-US")
    [4.867]
    [4.947]
    fn canonical_locale(&self) -> Locale {
    locale!("en-US")
  • replacement in fluent_embed/src/lib.rs at line 24
    [4.512][4.954:1015]()
    fn available_locales(&self) -> Vec<LanguageIdentifier> {
    [4.512]
    [4.1015]
    fn available_locales(&self) -> Vec<Locale> {
  • replacement in fluent_embed/src/lib.rs at line 31
    [4.2219][4.1143:1241](),[4.1241][4.460:737](),[4.2316][4.460:737](),[4.460][4.460:737](),[4.737][3.0:68]()
    env_preferences::get_locales_lossy().unwrap_or(vec![self.canonical_locale().into()]);
    // Lossily convert from a Locale to LanguageIdentifier for Fluent language negotiation
    let system_langids = system_locales
    .into_iter()
    .map(|icu_locale| icu_locale.id)
    .collect::<Vec<icu_locale_core::LanguageIdentifier>>();
    let requested_locales = old_locale_version(system_langids);
    [4.2219]
    [3.68]
    env_preferences::get_locales_lossy().unwrap_or(vec![self.canonical_locale()]);
    let requested_locales = old_locale_version(system_locales);
  • replacement in fluent_embed/src/lib.rs at line 34
    [3.146][4.3605:3683](),[4.3605][4.3605:3683](),[4.3683][4.1242:1302](),[4.1302][4.3742:3771](),[4.3742][4.3742:3771]()
    let canonical_locale = icu_locid::LanguageIdentifier::try_from_bytes(
    self.canonical_locale().to_string().as_bytes(),
    )
    .unwrap();
    [3.146]
    [4.287]
    let canonical_locale =
    icu_locid::Locale::try_from_bytes(self.canonical_locale().to_string().as_bytes())
    .unwrap();
  • replacement in fluent_embed/src/lib.rs at line 45
    [4.482][4.3772:3805](),[4.5246][4.3772:3805](),[4.508][4.3825:3914](),[4.3825][4.3825:3914](),[4.3914][4.2317:2327]()
    self.message_for_locale(
    &LanguageIdentifier::try_from_str(&selected_locale[0].to_string()).unwrap(),
    )
    [4.445]
    [4.5304]
    self.message_for_locale(&Locale::try_from_str(&selected_locale[0].to_string()).unwrap())
  • replacement in fluent_embed/src/lib.rs at line 50
    [3.176][3.176:300]()
    fn old_locale_version(
    new_locales: Vec<icu_locale_core::LanguageIdentifier>,
    ) -> Vec<icu_locid::LanguageIdentifier> {
    [3.176]
    [3.300]
    fn old_locale_version(new_locales: Vec<icu_locale_core::Locale>) -> Vec<icu_locid::Locale> {
  • replacement in fluent_embed/src/lib.rs at line 53
    [3.337][3.337:413]()
    // Convert new `icu_locale::LanguageIdentifier` to canonical string
    [3.337]
    [3.413]
    // Convert new `icu_locale::Locale` to canonical string
  • replacement in fluent_embed/src/lib.rs at line 56
    [3.539][3.539:635]()
    .map(|icu_langid| icu_locid::LanguageIdentifier::try_from_bytes(icu_langid.as_bytes()))
    [3.539]
    [3.635]
    .map(|icu_langid| icu_locid::Locale::try_from_bytes(icu_langid.as_bytes()))
  • replacement in fluent_embed/src/decimal.rs at line 8
    [4.846][4.1303:1339]()
    use icu_locale::LanguageIdentifier;
    [4.846]
    [4.892]
    use icu_locale::Locale;
  • replacement in fluent_embed/src/decimal.rs at line 13
    [4.2825][4.1287:1369]()
    fn message_for_locale(&self, locale: &LanguageIdentifier) -> String {
    [4.991]
    [4.1369]
    fn message_for_locale(&self, locale: &Locale) -> String {
  • replacement in fluent_embed/src/decimal.rs at line 24
    [4.4036][4.1910:1992]()
    fn message_for_locale(&self, locale: &LanguageIdentifier) -> String {
    [4.1614]
    [4.1992]
    fn message_for_locale(&self, locale: &Locale) -> String {
  • replacement in fluent_embed/src/decimal.rs at line 50
    [4.4621][4.2497:2571]()
    fn message_for_locale(&self, locale: &LanguageIdentifier) -> String {
    [4.1016]
    [4.4824]
    fn message_for_locale(&self, locale: &Locale) -> String {