1#![doc = include_str!("../README.md")]
2#[cfg(any(doc, feature = "build"))]
3mod build;
4mod l10n_bundle;
5mod l10n_language_vec;
6mod structured;
7
8#[cfg(all(test, feature = "build"))]
9mod tests;
10
11#[cfg(any(doc, feature = "build"))]
12pub use build::{
13 BuildError, BuildOptions, FtlOutputOptions, LintLevel, build_from_locales_folder,
14 try_build_from_locales_folder,
15};
16
17#[cfg(feature = "bench-internals")]
20pub use build::bench_internals;
21
22pub mod prelude {
23 pub use crate::l10n_bundle::L10nBundle;
24 pub use crate::l10n_language_vec::L10nLanguageVec;
25 pub use crate::structured::{ElementGap, Segment};
26 pub use fluent_bundle::{FluentArgs, FluentValue, types::FluentNumber};
27 #[cfg(feature = "langneg")]
28 pub use icu_locale_core::{LanguageIdentifier, langid};
29
30 #[cfg(feature = "langneg")]
31 pub fn negotiate_languages<'a, A>(accept_language: &str, available: &'a [A]) -> A
32 where
33 A: 'a + AsRef<LanguageIdentifier> + PartialEq + Default + Copy,
34 {
35 let mut requested: Vec<(LanguageIdentifier, u16)> = accept_language
37 .split(',')
38 .filter_map(|entry| {
39 let entry = entry.trim();
40 if entry.is_empty() {
41 return None;
42 }
43 let (tag, quality) = if let Some((tag, params)) = entry.split_once(';') {
44 let q = params
45 .trim()
46 .strip_prefix("q=")
47 .and_then(|v| v.parse::<f32>().ok())
48 .unwrap_or(1.0);
49 (tag.trim(), (q * 1000.0) as u16)
50 } else {
51 (entry, 1000)
52 };
53 tag.parse::<LanguageIdentifier>()
54 .ok()
55 .map(|lid| (lid, quality))
56 })
57 .collect();
58 requested.sort_by_key(|entry| std::cmp::Reverse(entry.1));
59
60 for (req, _) in &requested {
62 for avail in available {
63 if avail.as_ref().language == req.language {
64 return *avail;
65 }
66 }
67 }
68 A::default()
69 }
70}