use unic_langid::LanguageIdentifier;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Direction {
Ltr,
Rtl,
}
impl Direction {
#[must_use]
pub fn as_str(self) -> &'static str {
match self {
Direction::Ltr => "ltr",
Direction::Rtl => "rtl",
}
}
#[must_use]
pub fn is_rtl(self) -> bool {
self == Direction::Rtl
}
}
impl std::fmt::Display for Direction {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_str(self.as_str())
}
}
const RTL_SCRIPTS: [&str; 5] = ["Arab", "Hebr", "Thaa", "Nkoo", "Adlm"];
const RTL_LANGUAGES: [&str; 9] = ["ar", "he", "fa", "ur", "ps", "sd", "yi", "dv", "ckb"];
#[must_use]
pub fn direction(locale: &LanguageIdentifier) -> Direction {
if let Some(script) = locale.script {
return if RTL_SCRIPTS.contains(&script.as_str()) {
Direction::Rtl
} else {
Direction::Ltr
};
}
if RTL_LANGUAGES.contains(&locale.language.as_str()) {
Direction::Rtl
} else {
Direction::Ltr
}
}
#[cfg(test)]
mod tests {
use super::*;
fn dir(tag: &str) -> Direction {
direction(&tag.parse::<LanguageIdentifier>().expect("a language tag"))
}
#[test]
fn the_right_to_left_languages_are_right_to_left() {
for tag in [
"ar", "ar-EG", "he", "he-IL", "fa", "fa-IR", "ur", "ur-PK", "ps", "sd", "yi", "dv",
"ckb",
] {
assert_eq!(dir(tag), Direction::Rtl, "{tag} runs right to left");
}
}
#[test]
fn everything_else_is_left_to_right() {
for tag in [
"en", "en-GB", "id", "id-ID", "is", "de", "zh-Hans", "ja", "ko", "ru", "hi", "th",
"az", "ku", "ms", "sw",
] {
assert_eq!(dir(tag), Direction::Ltr, "{tag} runs left to right");
}
}
#[test]
fn a_script_subtag_overrules_the_language_in_both_directions() {
assert_eq!(
dir("az-Arab"),
Direction::Rtl,
"Arabic script, Latin-script language"
);
assert_eq!(dir("pa-Arab"), Direction::Rtl);
assert_eq!(dir("sr-Cyrl"), Direction::Ltr);
assert_eq!(
dir("ku-Latn"),
Direction::Ltr,
"Kurdish written in Latin runs left to right"
);
}
#[test]
fn the_attribute_value_is_what_html_takes() {
assert_eq!(Direction::Rtl.as_str(), "rtl");
assert_eq!(Direction::Ltr.as_str(), "ltr");
assert!(Direction::Rtl.is_rtl());
assert!(!Direction::Ltr.is_rtl());
assert_eq!(Direction::Rtl.to_string(), "rtl");
}
}