rocket_accept_language/
lib.rs1pub extern crate rocket;
10pub extern crate unic_langid;
11
12mod macros;
13
14use rocket::{
15 outcome::Outcome,
16 request::{self, FromRequest, Request},
17};
18pub use unic_langid::LanguageIdentifier;
19use unic_langid::{
20 parser::parse_language_identifier,
21 subtags::{Language, Region},
22};
23
24#[derive(Debug, Clone)]
26pub struct AcceptLanguage {
27 pub accept_language: Vec<LanguageIdentifier>,
28}
29
30#[inline]
31fn from_request(request: &Request<'_>) -> AcceptLanguage {
32 let raw_accept_language: Option<&str> = request.headers().get("accept-language").next(); let accept_language = raw_accept_language
35 .map(|raw_accept_language| {
36 accept_language::parse(raw_accept_language)
37 .iter()
38 .filter_map(|al| parse_language_identifier(al.as_bytes()).ok())
39 .collect()
40 })
41 .unwrap_or_default();
42
43 AcceptLanguage {
44 accept_language,
45 }
46}
47
48#[rocket::async_trait]
49impl<'r> FromRequest<'r> for AcceptLanguage {
50 type Error = ();
51
52 async fn from_request(request: &'r Request<'_>) -> request::Outcome<Self, Self::Error> {
53 Outcome::Success(from_request(request))
54 }
55}
56
57#[rocket::async_trait]
58impl<'r> FromRequest<'r> for &'r AcceptLanguage {
59 type Error = ();
60
61 async fn from_request(request: &'r Request<'_>) -> request::Outcome<Self, Self::Error> {
62 Outcome::Success(request.local_cache(|| from_request(request)))
63 }
64}
65
66impl AcceptLanguage {
67 pub fn get_first_region(&self) -> Option<Region> {
69 for locale in &self.accept_language {
70 let region = locale.region;
71
72 if region.is_some() {
73 return region;
74 }
75 }
76
77 None
78 }
79
80 pub fn get_first_language(&self) -> Option<Language> {
82 self.accept_language.get(0).map(|locale| locale.language)
83 }
84
85 pub fn get_first_language_region(&self) -> Option<(Language, Option<Region>)> {
87 if let Some(locale) = self.accept_language.get(0) {
88 let language = locale.language;
89
90 let region = locale.region;
91
92 Some((language, region))
93 } else {
94 None
95 }
96 }
97
98 pub fn get_appropriate_language_region(
100 &self,
101 locales: &[LanguageIdentifier],
102 ) -> Option<(Language, Option<Region>)> {
103 let mut filtered_language = None;
104
105 for locale in &self.accept_language {
106 let language = locale.language;
107
108 for t_locale in locales {
109 let t_language = t_locale.language;
110
111 if language == t_language {
112 let region = locale.region;
113 let t_region = t_locale.region;
114
115 if region == t_region {
116 return Some((language, region));
117 } else if filtered_language.is_none() {
118 filtered_language = Some((language, None));
119 }
120 }
121 }
122 }
123
124 filtered_language
125 }
126}