rustbasic_translatable/
middleware.rs1use rustbasic_core::requests::Request;
2use rustbasic_core::middleware::Next;
3use rustbasic_core::router::Response;
4use crate::translator::TRANSLATOR;
5
6rustbasic_core::tokio::task_local! {
8 pub static CURRENT_LOCALE: String;
9}
10
11pub async fn translatable_middleware(
13 req: Request,
14 next: Next,
15) -> Response {
16 let extracted_locale = detect_locale(&req);
17
18 CURRENT_LOCALE.scope(extracted_locale, next.run(req)).await
20}
21
22pub fn get_locale() -> String {
24 CURRENT_LOCALE.try_with(|l| l.clone()).unwrap_or_else(|_| TRANSLATOR.get_default_locale())
25}
26
27fn detect_locale(req: &Request) -> String {
29 if let Some(q_locale) = req.input_as_str("lang").or_else(|| req.input_as_str("locale")) {
31 let trimmed = q_locale.trim().to_lowercase();
32 if !trimmed.is_empty() {
33 return trimmed;
34 }
35 }
36
37 if let Some(s_locale) = req.session.get::<String>("locale") {
39 let trimmed = s_locale.trim().to_lowercase();
40 if !trimmed.is_empty() {
41 return trimmed;
42 }
43 }
44
45 if let Some(cookie_header) = req.headers.get("cookie") {
47 for cookie in cookie_header.split(';') {
48 let parts: Vec<&str> = cookie.splitn(2, '=').collect();
49 if parts.len() == 2 {
50 let name = parts[0].trim();
51 if name == "lang" || name == "locale" {
52 let val = parts[1].trim();
53 if !val.is_empty() {
54 return val.to_lowercase();
55 }
56 }
57 }
58 }
59 }
60
61 if let Some(accept_lang) = req.headers.get("accept-language")
63 && let Some(first_part) = accept_lang.split(',').next()
64 && let Some(lang_code) = first_part.split(';').next() {
65 let primary_code = lang_code.trim().split('-').next().unwrap_or("").trim();
66 if primary_code.len() == 2 {
67 return primary_code.to_lowercase();
68 }
69 }
70
71 TRANSLATOR.get_default_locale()
73}