use accept_language::parse;
use axum::{
extract::Request,
http::{header, HeaderMap},
middleware::Next,
response::Response,
};
use unic_langid::{langid, LanguageIdentifier};
pub const EN_US: LanguageIdentifier = langid!("en-US");
pub const DE_DE: LanguageIdentifier = langid!("de-DE");
pub const NL_NL: LanguageIdentifier = langid!("nl-NL");
pub const FR_FR: LanguageIdentifier = langid!("fr-FR");
pub const ES_ES: LanguageIdentifier = langid!("es-ES");
pub const EU_ES: LanguageIdentifier = langid!("eu-ES");
pub const SV_SE: LanguageIdentifier = langid!("sv-SE");
pub const SUPPORTED_LANGUAGES: &[LanguageIdentifier] =
&[EN_US, DE_DE, NL_NL, FR_FR, ES_ES, EU_ES, SV_SE];
pub fn parse_supported_language(s: &str) -> Option<LanguageIdentifier> {
let parsed: LanguageIdentifier = s.parse().ok()?;
if SUPPORTED_LANGUAGES.contains(&parsed) {
return Some(parsed);
}
let base = s.split('-').next().unwrap_or(s);
SUPPORTED_LANGUAGES
.iter()
.find(|l| l.language.as_str().eq_ignore_ascii_case(base))
.cloned()
}
pub fn get_preferred_language(headers: &HeaderMap) -> LanguageIdentifier {
if let Some(cookie_header) = headers.get(header::COOKIE) {
if let Ok(cookie_str) = cookie_header.to_str() {
for cookie in cookie_str.split(';') {
let parts: Vec<&str> = cookie.trim().splitn(2, '=').collect();
if parts.len() == 2 && parts[0] == "lang" {
if let Ok(lang) = parts[1].parse::<LanguageIdentifier>() {
if SUPPORTED_LANGUAGES.contains(&lang) {
return lang;
}
}
}
}
}
}
if let Some(accept_lang) = headers.get(header::ACCEPT_LANGUAGE) {
if let Ok(accept_lang_str) = accept_lang.to_str() {
let user_langs = parse(accept_lang_str);
for user_lang in &user_langs {
if let Ok(lang) = user_lang.parse::<LanguageIdentifier>() {
if SUPPORTED_LANGUAGES.contains(&lang) {
return lang;
}
}
let base_lang = user_lang.split('-').next().unwrap_or(user_lang);
for supported_lang in SUPPORTED_LANGUAGES {
let supported_str = supported_lang.to_string();
let supported_base = supported_str.split('-').next().unwrap_or(&supported_str);
if base_lang.eq_ignore_ascii_case(supported_base) {
return supported_lang.clone();
}
}
}
}
}
EN_US
}
pub async fn language_middleware(mut req: Request, next: Next) -> Response {
let lang = get_preferred_language(req.headers());
req.extensions_mut().insert(lang);
next.run(req).await
}