• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // This file is part of ICU4X. For terms of use, please see the file
2 // called LICENSE at the top level of the ICU4X source tree
3 // (online at: https://github.com/unicode-org/icu4x/blob/main/LICENSE ).
4 
5 #[cfg(feature = "alloc")]
6 use crate::subtags::Variants;
7 use crate::subtags::{Language, Region, Script, Subtag, Variant};
8 use crate::DataLocale;
9 
10 /// The structure storing locale subtags used in preferences.
11 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
12 pub struct LocalePreferences {
13     /// Preference of Language
14     pub(crate) language: Language,
15     /// Preference of Script
16     pub(crate) script: Option<Script>,
17     /// Preference of Region
18     pub(crate) region: Option<Region>,
19     /// Preference of Variant
20     pub(crate) variant: Option<Variant>,
21     /// Preference of Regional Subdivision
22     pub(crate) subdivision: Option<Subtag>,
23     /// Preference of Unicode Extension Region
24     pub(crate) ue_region: Option<Region>,
25 }
26 
27 impl LocalePreferences {
to_data_locale_maybe_region_priority(self, region_priority: bool) -> DataLocale28     fn to_data_locale_maybe_region_priority(self, region_priority: bool) -> DataLocale {
29         DataLocale {
30             language: self.language,
31             script: self.script,
32             region: match (self.region, self.ue_region) {
33                 (Some(_), Some(r)) if region_priority => Some(r),
34                 (r, _) => r,
35             },
36             variant: self.variant,
37             subdivision: self.subdivision,
38         }
39     }
40 
41     /// Convert to a DataLocale, with region-based fallback priority
42     ///
43     /// Most users should use `icu_provider::marker::make_locale()` instead.
to_data_locale_region_priority(self) -> DataLocale44     pub fn to_data_locale_region_priority(self) -> DataLocale {
45         self.to_data_locale_maybe_region_priority(true)
46     }
47 
48     /// Convert to a DataLocale, with language-based fallback priority
49     ///
50     /// Most users should use `icu_provider::marker::make_locale()` instead.
to_data_locale_language_priority(self) -> DataLocale51     pub fn to_data_locale_language_priority(self) -> DataLocale {
52         self.to_data_locale_maybe_region_priority(false)
53     }
54 }
55 impl Default for LocalePreferences {
default() -> Self56     fn default() -> Self {
57         Self::default()
58     }
59 }
60 
61 impl From<&crate::Locale> for LocalePreferences {
from(loc: &crate::Locale) -> Self62     fn from(loc: &crate::Locale) -> Self {
63         let sd = loc
64             .extensions
65             .unicode
66             .keywords
67             .get(&crate::extensions::unicode::key!("sd"))
68             .and_then(|v| v.as_single_subtag().copied());
69         let ue_region = loc
70             .extensions
71             .unicode
72             .keywords
73             .get(&crate::extensions::unicode::key!("rg"))
74             .and_then(|v| {
75                 v.as_single_subtag()
76                     .and_then(|s| Region::try_from_str(s.as_str()).ok())
77             });
78         Self {
79             language: loc.id.language,
80             script: loc.id.script,
81             region: loc.id.region,
82             variant: loc.id.variants.iter().copied().next(),
83             subdivision: sd,
84             ue_region,
85         }
86     }
87 }
88 
89 impl From<&crate::LanguageIdentifier> for LocalePreferences {
from(lid: &crate::LanguageIdentifier) -> Self90     fn from(lid: &crate::LanguageIdentifier) -> Self {
91         Self {
92             language: lid.language,
93             script: lid.script,
94             region: lid.region,
95             variant: lid.variants.iter().copied().next(),
96             subdivision: None,
97             ue_region: None,
98         }
99     }
100 }
101 
102 #[cfg(feature = "alloc")]
103 impl From<LocalePreferences> for crate::Locale {
from(prefs: LocalePreferences) -> Self104     fn from(prefs: LocalePreferences) -> Self {
105         Self {
106             id: crate::LanguageIdentifier {
107                 language: prefs.language,
108                 script: prefs.script,
109                 region: prefs.region,
110                 variants: prefs
111                     .variant
112                     .map(Variants::from_variant)
113                     .unwrap_or_default(),
114             },
115             extensions: {
116                 let mut extensions = crate::extensions::Extensions::default();
117                 if let Some(sd) = prefs.subdivision {
118                     extensions.unicode.keywords.set(
119                         crate::extensions::unicode::key!("sd"),
120                         crate::extensions::unicode::Value::from_subtag(Some(sd)),
121                     );
122                 }
123                 if let Some(rg) = prefs.ue_region {
124                     #[allow(clippy::unwrap_used)] // Region is a valid Subtag
125                     extensions.unicode.keywords.set(
126                         crate::extensions::unicode::key!("rg"),
127                         crate::extensions::unicode::Value::try_from_str(rg.as_str()).unwrap(),
128                     );
129                 }
130                 extensions
131             },
132         }
133     }
134 }
135 
136 impl LocalePreferences {
137     /// Constructs a new [`LocalePreferences`] struct with the defaults.
default() -> Self138     pub const fn default() -> Self {
139         Self {
140             language: Language::default(),
141             script: None,
142             region: None,
143             variant: None,
144             subdivision: None,
145             ue_region: None,
146         }
147     }
148 
149     /// Preference of Language
language(&self) -> Language150     pub const fn language(&self) -> Language {
151         self.language
152     }
153 
154     /// Extends the preferences with the values from another set of preferences.
extend(&mut self, other: LocalePreferences)155     pub fn extend(&mut self, other: LocalePreferences) {
156         if !other.language.is_default() {
157             self.language = other.language;
158         }
159         if let Some(script) = other.script {
160             self.script = Some(script);
161         }
162         if let Some(region) = other.region {
163             self.region = Some(region);
164         }
165         if let Some(variant) = other.variant {
166             self.variant = Some(variant);
167         }
168         if let Some(sd) = other.subdivision {
169             self.subdivision = Some(sd);
170         }
171         if let Some(ue_region) = other.ue_region {
172             self.ue_region = Some(ue_region);
173         }
174     }
175 }
176