lib-humus 0.6.0

Helps creating configurable frontends for humans and computers using axum, Tera and toml.
Documentation
// SPDX-FileCopyrightText: 2026 Slatian <baschdel@disroot.org>
//
// SPDX-License-Identifier: AGPL-3.0-or-later

//! Helpers for turning a request into a [UnicodeLanguageIdentifier].
//!
//! They are supposed to be used inside a [tower::Service]. For a ready to use implementation see [TemplateSettingsLayer][crate::middleware::TemplateSettingsLayer] and [TemplateSettingsService][crate::middleware::TemplateSettingsService].

use axum::{body::Body, http::Request};
use axum_extra::headers::Cookie;
use axum_extra::headers::Header;

use crate::headers::AcceptLanguageHeader;
use crate::language::LanguageManifest;
use crate::language::UnicodeLanguageIdentifier;

/// Contains the name of the cookie that stores the language setting `lib_humus_language`
pub static LANGUAGE_COOKIE_NAME: &str = "lib_humus_language";

/// Extracts the language from the cookie `lib_humus_language` (see [LANGUAGE_COOKIE_NAME]);.
pub fn language_from_cookie(
	req: &Request<Body>,
	language_manifest: &LanguageManifest,
) -> Option<UnicodeLanguageIdentifier> {
	let cookie_header_values = req.headers().get_all(Cookie::name());

	// Extract from language cookie
	let mut language = Cookie::decode(&mut cookie_header_values.iter())
		.ok()?
		.get(LANGUAGE_COOKIE_NAME)?
		.parse()
		.ok()?;
	if language_manifest.languages.contains_key(&language) {
		Some(language)
	} else {
		language.script = None;
		language.region = None;
		if language_manifest.languages.contains_key(&language) {
			Some(language)
		} else {
			None
		}
	}
}

/// Extracts the language from the `Accept-Language` HTTP header using the language manifest to select the best fitting language.
pub fn language_from_accept_language_header(
	req: &Request<Body>,
	language_manifest: &LanguageManifest,
) -> Option<UnicodeLanguageIdentifier> {
	let language_header = req.headers().get("accept-language")?.to_str().ok()?;
	let language_header = AcceptLanguageHeader::new(language_header);
	language_manifest.get_best_fitting_language(&language_header)
}