Skip to main content

lib_humus/headers/
accept_language_header.rs

1// SPDX-FileCopyrightText: 2026 Slatian <baschdel@disroot.org>
2//
3// SPDX-License-Identifier: AGPL-3.0-or-later
4
5use std::str::FromStr;
6
7use axum::extract::OptionalFromRequestParts;
8
9use crate::headers::parser::HeaderParser;
10
11/// Represents the two kinds of language identifies in an [AcceptLanguageHeader].
12#[derive(Debug, Clone, PartialEq, Eq)]
13pub enum AcceptLanguageHeaderLanguage {
14	/// Parsed from a `*`
15	Wildcard,
16	/// Parsed from everything else
17	Code(String),
18}
19
20/// A parsed [`Accept-Language` header](https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Accept-Language) that can also be used as an optional axum extractor
21#[derive(Debug, Clone, PartialEq)]
22pub struct AcceptLanguageHeader {
23	/// Languages in decending order of preference
24	pub languages: Vec<(AcceptLanguageHeaderLanguage, f32)>,
25}
26
27impl AcceptLanguageHeader {
28	/// Creates a new Parsed header from header text. The parser will stop when it encounterrs syntax it doesn't understand.
29	pub fn new(header_text: &str) -> Self {
30		HeaderParser::new(header_text).parse_accept_language()
31	}
32}
33
34impl FromStr for AcceptLanguageHeader {
35	type Err = ();
36
37	fn from_str(s: &str) -> Result<Self, Self::Err> {
38		Ok(HeaderParser::new(s).parse_accept_language())
39	}
40}
41
42impl<S> OptionalFromRequestParts<S> for AcceptLanguageHeader
43where
44	S: Sync,
45{
46	type Rejection = ();
47
48	async fn from_request_parts(
49		parts: &mut axum::http::request::Parts,
50		_state: &S,
51	) -> Result<Option<Self>, Self::Rejection> {
52		Ok(parts
53			.headers
54			.get("accept-language")
55			.and_then(|v| Some(AcceptLanguageHeader::new(v.to_str().ok()?))))
56	}
57}