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//! Options to define fallback behaviour.
6//!
7//! These options are consumed by the `LocaleFallbacker` in the `icu_locid_transforms` crate
8//! (or the `icu::locid_transforms` module), but are defined here because they are used by `DataKey`.
9
10use icu_locid::extensions::unicode::Key;
11
12/// Hint for which subtag to prioritize during fallback.
13///
14/// For example, `"en-US"` might fall back to either `"en"` or `"und-US"` depending
15/// on this enum.
16#[derive(Debug, PartialEq, Eq, Copy, Clone, PartialOrd, Ord)]
17#[non_exhaustive]
18pub enum LocaleFallbackPriority {
19 /// Prioritize the language. This is the default behavior.
20 ///
21 /// For example, `"en-US"` should go to `"en"` and then `"und"`.
22 Language,
23 /// Prioritize the region.
24 ///
25 /// For example, `"en-US"` should go to `"und-US"` and then `"und"`.
26 Region,
27 /// Collation-specific fallback rules. Similar to language priority.
28 ///
29 /// For example, `"zh-Hant"` goes to `"zh"` before `"und"`.
30 Collation,
31}
32
33impl LocaleFallbackPriority {
34 /// Const-friendly version of [`Default::default`].
35 pub const fn const_default() -> Self {
36 Self::Language
37 }
38}
39
40impl Default for LocaleFallbackPriority {
41 fn default() -> Self {
42 Self::const_default()
43 }
44}
45
46/// What additional data is required to load when performing fallback.
47#[derive(Debug, PartialEq, Eq, Copy, Clone, PartialOrd, Ord)]
48#[non_exhaustive]
49pub enum LocaleFallbackSupplement {
50 /// Collation supplement
51 Collation,
52}
53
54/// Configuration settings for a particular fallback operation.
55#[derive(Debug, Clone, PartialEq, Eq, Copy)]
56#[non_exhaustive]
57pub struct LocaleFallbackConfig {
58 /// Strategy for choosing which subtags to drop during locale fallback.
59 ///
60 /// # Examples
61 ///
62 /// Retain the language and script subtags until the final step:
63 ///
64 /// ```
65 /// use icu_locid::locale;
66 /// use icu_locid_transform::fallback::LocaleFallbackConfig;
67 /// use icu_locid_transform::fallback::LocaleFallbackPriority;
68 /// use icu_locid_transform::LocaleFallbacker;
69 ///
70 /// // Set up the fallback iterator.
71 /// let fallbacker = LocaleFallbacker::new();
72 /// let mut config = LocaleFallbackConfig::default();
73 /// config.priority = LocaleFallbackPriority::Language;
74 /// let mut fallback_iterator = fallbacker
75 /// .for_config(config)
76 /// .fallback_for(locale!("ca-ES-valencia").into());
77 ///
78 /// // Run the algorithm and check the results.
79 /// assert_eq!(fallback_iterator.get(), &locale!("ca-ES-valencia").into());
80 /// fallback_iterator.step();
81 /// assert_eq!(fallback_iterator.get(), &locale!("ca-ES").into());
82 /// fallback_iterator.step();
83 /// assert_eq!(fallback_iterator.get(), &locale!("ca-valencia").into());
84 /// fallback_iterator.step();
85 /// assert_eq!(fallback_iterator.get(), &locale!("ca").into());
86 /// fallback_iterator.step();
87 /// assert_eq!(fallback_iterator.get(), &locale!("und").into());
88 /// ```
89 ///
90 /// Retain the region subtag until the final step:
91 ///
92 /// ```
93 /// use icu_locid::locale;
94 /// use icu_locid_transform::fallback::LocaleFallbackConfig;
95 /// use icu_locid_transform::fallback::LocaleFallbackPriority;
96 /// use icu_locid_transform::LocaleFallbacker;
97 ///
98 /// // Set up the fallback iterator.
99 /// let fallbacker = LocaleFallbacker::new();
100 /// let mut config = LocaleFallbackConfig::default();
101 /// config.priority = LocaleFallbackPriority::Region;
102 /// let mut fallback_iterator = fallbacker
103 /// .for_config(config)
104 /// .fallback_for(locale!("ca-ES-valencia").into());
105 ///
106 /// // Run the algorithm and check the results.
107 /// assert_eq!(fallback_iterator.get(), &locale!("ca-ES-valencia").into());
108 /// fallback_iterator.step();
109 /// assert_eq!(fallback_iterator.get(), &locale!("ca-ES").into());
110 /// fallback_iterator.step();
111 /// assert_eq!(fallback_iterator.get(), &locale!("und-ES-valencia").into());
112 /// fallback_iterator.step();
113 /// assert_eq!(fallback_iterator.get(), &locale!("und-ES").into());
114 /// fallback_iterator.step();
115 /// assert_eq!(fallback_iterator.get(), &locale!("und").into());
116 /// ```
117 pub priority: LocaleFallbackPriority,
118 /// An extension keyword to retain during locale fallback.
119 ///
120 /// # Examples
121 ///
122 /// ```
123 /// use icu_locid::locale;
124 /// use icu_locid_transform::fallback::LocaleFallbackConfig;
125 /// use icu_locid_transform::LocaleFallbacker;
126 ///
127 /// // Set up the fallback iterator.
128 /// let fallbacker = LocaleFallbacker::new();
129 /// let mut config = LocaleFallbackConfig::default();
130 /// config.extension_key = Some(icu_locid::extensions::unicode::key!("nu"));
131 /// let mut fallback_iterator = fallbacker
132 /// .for_config(config)
133 /// .fallback_for(locale!("ar-EG-u-nu-latn").into());
134 ///
135 /// // Run the algorithm and check the results.
136 /// assert_eq!(fallback_iterator.get(), &locale!("ar-EG-u-nu-latn").into());
137 /// fallback_iterator.step();
138 /// assert_eq!(fallback_iterator.get(), &locale!("ar-EG").into());
139 /// fallback_iterator.step();
140 /// assert_eq!(fallback_iterator.get(), &locale!("ar-u-nu-latn").into());
141 /// fallback_iterator.step();
142 /// assert_eq!(fallback_iterator.get(), &locale!("ar").into());
143 /// fallback_iterator.step();
144 /// assert_eq!(fallback_iterator.get(), &locale!("und").into());
145 /// ```
146 pub extension_key: Option<Key>,
147 /// Fallback supplement data key to customize fallback rules.
148 ///
149 /// For example, most data keys for collation add additional parent locales, such as
150 /// "yue" to "zh-Hant", and data used for the `"-u-co"` extension keyword fallback.
151 ///
152 /// Currently the only supported fallback supplement is `LocaleFallbackSupplement::Collation`, but more may be
153 /// added in the future.
154 ///
155 /// # Examples
156 ///
157 /// ```
158 /// use icu_locid::locale;
159 /// use icu_locid_transform::fallback::LocaleFallbackConfig;
160 /// use icu_locid_transform::fallback::LocaleFallbackPriority;
161 /// use icu_locid_transform::fallback::LocaleFallbackSupplement;
162 /// use icu_locid_transform::LocaleFallbacker;
163 ///
164 /// // Set up the fallback iterator.
165 /// let fallbacker = LocaleFallbacker::new();
166 /// let mut config = LocaleFallbackConfig::default();
167 /// config.priority = LocaleFallbackPriority::Collation;
168 /// config.fallback_supplement = Some(LocaleFallbackSupplement::Collation);
169 /// let mut fallback_iterator = fallbacker
170 /// .for_config(config)
171 /// .fallback_for(locale!("yue-HK").into());
172 ///
173 /// // Run the algorithm and check the results.
174 /// // TODO(#1964): add "zh" as a target.
175 /// assert_eq!(fallback_iterator.get(), &locale!("yue-HK").into());
176 /// fallback_iterator.step();
177 /// assert_eq!(fallback_iterator.get(), &locale!("yue").into());
178 /// fallback_iterator.step();
179 /// assert_eq!(fallback_iterator.get(), &locale!("zh-Hant").into());
180 /// fallback_iterator.step();
181 /// assert_eq!(fallback_iterator.get(), &locale!("und").into());
182 /// ```
183 pub fallback_supplement: Option<LocaleFallbackSupplement>,
184}
185
186impl LocaleFallbackConfig {
187 /// Const version of [`Default::default`].
188 pub const fn const_default() -> Self {
189 Self {
190 priority: LocaleFallbackPriority::const_default(),
191 extension_key: None,
192 fallback_supplement: None,
193 }
194 }
195}
196
197impl Default for LocaleFallbackConfig {
198 fn default() -> Self {
199 Self::const_default()
200 }
201}
202