diff options
author | cN3rd <subs.in.tokyo@gmail.com> | 2021-09-03 18:31:39 +0300 |
---|---|---|
committer | Eric Huss <eric@huss.org> | 2023-09-02 07:49:28 -0700 |
commit | 819a108f073c84d835407ea0fe1ff322bd1cf238 (patch) | |
tree | 0a8171d499645597c4dfbe77461c14c8c4f475f9 /src/config.rs | |
parent | 3a998991141417e4b4d1671c90c8ff9a9398788b (diff) |
Add `text_direction` property in general book metadata
Text direction can selected in the config via the `text_direction` attribute in `book.toml`,
or be derived from the book's language.
Diffstat (limited to 'src/config.rs')
-rw-r--r-- | src/config.rs | 220 |
1 files changed, 220 insertions, 0 deletions
diff --git a/src/config.rs b/src/config.rs index 4641d1a2..8a20e4f3 100644 --- a/src/config.rs +++ b/src/config.rs @@ -411,6 +411,9 @@ pub struct BookConfig { pub multilingual: bool, /// The main language of the book. pub language: Option<String>, + /// The direction of text in the book: Left-to-right (LTR) or Right-to-left (RTL). + /// When not specified, the correct text direction is derived from [BookConfig::language]. + pub text_direction: Option<TextDirection>, } impl Default for BookConfig { @@ -422,6 +425,44 @@ impl Default for BookConfig { src: PathBuf::from("src"), multilingual: false, language: Some(String::from("en")), + text_direction: None, + } + } +} + +impl BookConfig { + /// Gets the realized text direction, either from [BookConfig::text_direction] + /// or derived from [BookConfig::language], to be used by templating engines. + pub fn realized_text_direction(&self) -> TextDirection { + if let Some(direction) = self.text_direction { + direction + } else { + TextDirection::from_lang_code(&self.language.clone().unwrap_or_default()) + } + } +} + +/// Text direction to use for HTML output +#[derive(Debug, Copy, Clone, PartialEq, Serialize, Deserialize)] +pub enum TextDirection { + /// Left to right. + #[serde(rename = "ltr")] + LeftToRight, + /// Right to left + #[serde(rename = "rtl")] + RightToLeft, +} + +impl TextDirection { + /// Gets the text direction from language code + pub fn from_lang_code(code: &str) -> Self { + match code { + // list sourced from here: https://github.com/abarrak/rtl/blob/master/lib/rtl/core.rb#L16 + "ar" | "ara" | "arc" | "ae" | "ave" | "egy" | "he" | "heb" | "nqo" | "pal" | "phn" + | "sam" | "syc" | "syr" | "fa" | "per" | "fas" | "ku" | "kur" | "ur" | "urd" => { + TextDirection::RightToLeft + } + _ => TextDirection::LeftToRight, } } } @@ -788,6 +829,7 @@ mod tests { multilingual: true, src: PathBuf::from("source"), language: Some(String::from("ja")), + text_direction: None, }; let build_should_be = BuildConfig { build_dir: PathBuf::from("outputs"), @@ -1141,6 +1183,184 @@ mod tests { } #[test] + fn text_direction_ltr() { + let src = r#" + [book] + text-direction = "ltr" + "#; + + let got = Config::from_str(src).unwrap(); + assert_eq!(got.book.text_direction, Some(TextDirection::LeftToRight)); + } + + #[test] + fn text_direction_rtl() { + let src = r#" + [book] + text-direction = "rtl" + "#; + + let got = Config::from_str(src).unwrap(); + assert_eq!(got.book.text_direction, Some(TextDirection::RightToLeft)); + } + + #[test] + fn text_direction_none() { + let src = r#" + [book] + "#; + + let got = Config::from_str(src).unwrap(); + assert_eq!(got.book.text_direction, None); + } + + #[test] + fn test_text_direction() { + let mut cfg = BookConfig::default(); + + // test deriving the text direction from language codes + cfg.language = Some("ar".into()); + assert_eq!(cfg.realized_text_direction(), TextDirection::RightToLeft); + + cfg.language = Some("he".into()); + assert_eq!(cfg.realized_text_direction(), TextDirection::RightToLeft); + + cfg.language = Some("en".into()); + assert_eq!(cfg.realized_text_direction(), TextDirection::LeftToRight); + + cfg.language = Some("ja".into()); + assert_eq!(cfg.realized_text_direction(), TextDirection::LeftToRight); + + // test forced direction + cfg.language = Some("ar".into()); + cfg.text_direction = Some(TextDirection::LeftToRight); + assert_eq!(cfg.realized_text_direction(), TextDirection::LeftToRight); + + cfg.language = Some("ar".into()); + cfg.text_direction = Some(TextDirection::RightToLeft); + assert_eq!(cfg.realized_text_direction(), TextDirection::RightToLeft); + + cfg.language = Some("en".into()); + cfg.text_direction = Some(TextDirection::LeftToRight); + assert_eq!(cfg.realized_text_direction(), TextDirection::LeftToRight); + + cfg.language = Some("en".into()); + cfg.text_direction = Some(TextDirection::RightToLeft); + assert_eq!(cfg.realized_text_direction(), TextDirection::RightToLeft); + } + + #[test] + fn text_drection_from_lang_code() { + // test all right-to-left languages + assert_eq!( + TextDirection::from_lang_code("ar"), + TextDirection::RightToLeft + ); + assert_eq!( + TextDirection::from_lang_code("ara"), + TextDirection::RightToLeft + ); + assert_eq!( + TextDirection::from_lang_code("arc"), + TextDirection::RightToLeft + ); + assert_eq!( + TextDirection::from_lang_code("ae"), + TextDirection::RightToLeft + ); + assert_eq!( + TextDirection::from_lang_code("ave"), + TextDirection::RightToLeft + ); + assert_eq!( + TextDirection::from_lang_code("egy"), + TextDirection::RightToLeft + ); + assert_eq!( + TextDirection::from_lang_code("he"), + TextDirection::RightToLeft + ); + assert_eq!( + TextDirection::from_lang_code("heb"), + TextDirection::RightToLeft + ); + assert_eq!( + TextDirection::from_lang_code("nqo"), + TextDirection::RightToLeft + ); + assert_eq!( + TextDirection::from_lang_code("pal"), + TextDirection::RightToLeft + ); + assert_eq!( + TextDirection::from_lang_code("phn"), + TextDirection::RightToLeft + ); + assert_eq!( + TextDirection::from_lang_code("sam"), + TextDirection::RightToLeft + ); + assert_eq!( + TextDirection::from_lang_code("syc"), + TextDirection::RightToLeft + ); + assert_eq!( + TextDirection::from_lang_code("syr"), + TextDirection::RightToLeft + ); + assert_eq!( + TextDirection::from_lang_code("fa"), + TextDirection::RightToLeft + ); + assert_eq!( + TextDirection::from_lang_code("per"), + TextDirection::RightToLeft + ); + assert_eq!( + TextDirection::from_lang_code("fas"), + TextDirection::RightToLeft + ); + assert_eq!( + TextDirection::from_lang_code("ku"), + TextDirection::RightToLeft + ); + assert_eq!( + TextDirection::from_lang_code("kur"), + TextDirection::RightToLeft + ); + assert_eq!( + TextDirection::from_lang_code("ur"), + TextDirection::RightToLeft + ); + assert_eq!( + TextDirection::from_lang_code("urd"), + TextDirection::RightToLeft + ); + + // test some left-to-right languages + assert_eq!( + TextDirection::from_lang_code("de"), + TextDirection::LeftToRight + ); + assert_eq!( + TextDirection::from_lang_code("en"), + TextDirection::LeftToRight + ); + assert_eq!( + TextDirection::from_lang_code("es"), + TextDirection::LeftToRight + ); + assert_eq!( + TextDirection::from_lang_code("ja"), + TextDirection::LeftToRight + ); + assert_eq!( + TextDirection::from_lang_code("sv"), + TextDirection::LeftToRight + ); + } + + #[test] #[should_panic(expected = "Invalid configuration file")] fn invalid_language_type_error() { let src = r#" |