use url::Url;
#[derive(PartialEq, Eq, Debug)]
pub(super) enum Section {
SameHost,
Subsite,
}
pub(super) fn section(url: &Url, anchor: Option<&str>) -> Option<Section> {
let mut segs: Vec<&str> = url.path().split('/').filter(|s| !s.is_empty()).collect();
if segs
.first()
.is_some_and(|s| is_language_code(s) || is_language_name(s))
{
segs.remove(0);
}
let segments = segs.len();
let short = anchor.is_some_and(|a| (1..=4).contains(&a.split_whitespace().count()));
if !short || url.query().is_some() {
return None;
}
match segments {
0 => Some(Section::Subsite),
1 => Some(Section::SameHost),
_ => None,
}
}
pub(super) fn foreign_language_segment(url: &Url) -> bool {
const CODES: &[&str] = &[
"de", "fr", "es", "it", "nl", "pt", "ru", "ja", "jp", "zh", "zh-cn", "zh-tw", "zh-hans",
"zh-hant", "ko", "kr", "ar", "sv", "fi", "da", "no", "nb", "pl", "tr", "cs", "el", "he",
"hi", "th", "vi", "id", "hu", "ro", "uk", "ca", "eu", "gl", "cy", "ga", "mi",
];
url.path()
.split('/')
.filter(|s| !s.is_empty())
.any(|seg| CODES.contains(&language_code(seg).as_str()))
}
pub(super) fn language_portal(url: &Url, anchor: Option<&str>) -> bool {
let anchor = anchor.unwrap_or_default().trim().to_ascii_lowercase();
if matches!(
anchor.as_str(),
"english"
| "en"
| "eng"
| "in english"
| "english site"
| "english version"
| "english page"
| "english top"
| "english home"
) {
return true;
}
url.path()
.split('/')
.rfind(|seg| !seg.is_empty())
.is_some_and(|seg| {
matches!(
language_code(seg).as_str(),
"en" | "english" | "en-us" | "en-gb"
)
})
}
pub(super) fn is_language_name(seg: &str) -> bool {
matches!(language_code(seg).as_str(), "english" | "eng")
}
pub(super) fn is_english(lang: &str) -> bool {
let primary = lang.split(['-', '_']).next().unwrap_or_default();
primary.eq_ignore_ascii_case("en")
}
pub(super) fn is_language_code(seg: &str) -> bool {
let code = language_code(seg);
let two = |p: &str| p.len() == 2 && p.bytes().all(|b| b.is_ascii_alphabetic());
two(&code)
|| code
.split_once('-')
.is_some_and(|(a, b)| two(a) && (2..=4).contains(&b.len()))
}
fn language_code(seg: &str) -> String {
seg.split_once('.')
.map_or(seg, |(s, _)| s)
.to_ascii_lowercase()
}
pub(super) fn locator(url: &Url) -> String {
let mut s = String::with_capacity(url.as_str().len());
if let Some(host) = url.host_str() {
for label in host.split('.') {
if label != "www" {
s.push_str(label);
s.push(' ');
}
}
}
s.push_str(url.path());
if let Some(q) = url.query() {
s.push(' ');
s.push_str(q);
}
s
}