Skip to content

Commit 819a108

Browse files
cN3rdehuss
authored andcommitted
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.
1 parent 3a99899 commit 819a108

File tree

2 files changed

+224
-0
lines changed

2 files changed

+224
-0
lines changed

guide/src/format/configuration/general.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,9 @@ This is general information about your book.
4646
`src` directly under the root folder. But this is configurable with the `src`
4747
key in the configuration file.
4848
- **language:** The main language of the book, which is used as a language attribute `<html lang="en">` for example.
49+
This is also used to derive the direction of text (RTL, LTR) within the book.
50+
- **text_direction**: The direction of text in the book: Left-to-right (LTR) or Right-to-left (RTL). Possible values: `ltr`, `rtl`.
51+
When not specified, the correct text direction is derived from the book's `language` attribute.
4952

5053
**book.toml**
5154
```toml
@@ -55,6 +58,7 @@ authors = ["John Doe", "Jane Doe"]
5558
description = "The example book covers examples."
5659
src = "my-src" # the source files will be found in `root/my-src` instead of `root/src`
5760
language = "en"
61+
text-direction = "ltr"
5862
```
5963

6064
### Rust options

src/config.rs

Lines changed: 220 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -411,6 +411,9 @@ pub struct BookConfig {
411411
pub multilingual: bool,
412412
/// The main language of the book.
413413
pub language: Option<String>,
414+
/// The direction of text in the book: Left-to-right (LTR) or Right-to-left (RTL).
415+
/// When not specified, the correct text direction is derived from [BookConfig::language].
416+
pub text_direction: Option<TextDirection>,
414417
}
415418

416419
impl Default for BookConfig {
@@ -422,6 +425,44 @@ impl Default for BookConfig {
422425
src: PathBuf::from("src"),
423426
multilingual: false,
424427
language: Some(String::from("en")),
428+
text_direction: None,
429+
}
430+
}
431+
}
432+
433+
impl BookConfig {
434+
/// Gets the realized text direction, either from [BookConfig::text_direction]
435+
/// or derived from [BookConfig::language], to be used by templating engines.
436+
pub fn realized_text_direction(&self) -> TextDirection {
437+
if let Some(direction) = self.text_direction {
438+
direction
439+
} else {
440+
TextDirection::from_lang_code(&self.language.clone().unwrap_or_default())
441+
}
442+
}
443+
}
444+
445+
/// Text direction to use for HTML output
446+
#[derive(Debug, Copy, Clone, PartialEq, Serialize, Deserialize)]
447+
pub enum TextDirection {
448+
/// Left to right.
449+
#[serde(rename = "ltr")]
450+
LeftToRight,
451+
/// Right to left
452+
#[serde(rename = "rtl")]
453+
RightToLeft,
454+
}
455+
456+
impl TextDirection {
457+
/// Gets the text direction from language code
458+
pub fn from_lang_code(code: &str) -> Self {
459+
match code {
460+
// list sourced from here: https://github.com/abarrak/rtl/blob/master/lib/rtl/core.rb#L16
461+
"ar" | "ara" | "arc" | "ae" | "ave" | "egy" | "he" | "heb" | "nqo" | "pal" | "phn"
462+
| "sam" | "syc" | "syr" | "fa" | "per" | "fas" | "ku" | "kur" | "ur" | "urd" => {
463+
TextDirection::RightToLeft
464+
}
465+
_ => TextDirection::LeftToRight,
425466
}
426467
}
427468
}
@@ -788,6 +829,7 @@ mod tests {
788829
multilingual: true,
789830
src: PathBuf::from("source"),
790831
language: Some(String::from("ja")),
832+
text_direction: None,
791833
};
792834
let build_should_be = BuildConfig {
793835
build_dir: PathBuf::from("outputs"),
@@ -1140,6 +1182,184 @@ mod tests {
11401182
assert_eq!(&get_404_output_file(&html_config.input_404), "missing.html");
11411183
}
11421184

1185+
#[test]
1186+
fn text_direction_ltr() {
1187+
let src = r#"
1188+
[book]
1189+
text-direction = "ltr"
1190+
"#;
1191+
1192+
let got = Config::from_str(src).unwrap();
1193+
assert_eq!(got.book.text_direction, Some(TextDirection::LeftToRight));
1194+
}
1195+
1196+
#[test]
1197+
fn text_direction_rtl() {
1198+
let src = r#"
1199+
[book]
1200+
text-direction = "rtl"
1201+
"#;
1202+
1203+
let got = Config::from_str(src).unwrap();
1204+
assert_eq!(got.book.text_direction, Some(TextDirection::RightToLeft));
1205+
}
1206+
1207+
#[test]
1208+
fn text_direction_none() {
1209+
let src = r#"
1210+
[book]
1211+
"#;
1212+
1213+
let got = Config::from_str(src).unwrap();
1214+
assert_eq!(got.book.text_direction, None);
1215+
}
1216+
1217+
#[test]
1218+
fn test_text_direction() {
1219+
let mut cfg = BookConfig::default();
1220+
1221+
// test deriving the text direction from language codes
1222+
cfg.language = Some("ar".into());
1223+
assert_eq!(cfg.realized_text_direction(), TextDirection::RightToLeft);
1224+
1225+
cfg.language = Some("he".into());
1226+
assert_eq!(cfg.realized_text_direction(), TextDirection::RightToLeft);
1227+
1228+
cfg.language = Some("en".into());
1229+
assert_eq!(cfg.realized_text_direction(), TextDirection::LeftToRight);
1230+
1231+
cfg.language = Some("ja".into());
1232+
assert_eq!(cfg.realized_text_direction(), TextDirection::LeftToRight);
1233+
1234+
// test forced direction
1235+
cfg.language = Some("ar".into());
1236+
cfg.text_direction = Some(TextDirection::LeftToRight);
1237+
assert_eq!(cfg.realized_text_direction(), TextDirection::LeftToRight);
1238+
1239+
cfg.language = Some("ar".into());
1240+
cfg.text_direction = Some(TextDirection::RightToLeft);
1241+
assert_eq!(cfg.realized_text_direction(), TextDirection::RightToLeft);
1242+
1243+
cfg.language = Some("en".into());
1244+
cfg.text_direction = Some(TextDirection::LeftToRight);
1245+
assert_eq!(cfg.realized_text_direction(), TextDirection::LeftToRight);
1246+
1247+
cfg.language = Some("en".into());
1248+
cfg.text_direction = Some(TextDirection::RightToLeft);
1249+
assert_eq!(cfg.realized_text_direction(), TextDirection::RightToLeft);
1250+
}
1251+
1252+
#[test]
1253+
fn text_drection_from_lang_code() {
1254+
// test all right-to-left languages
1255+
assert_eq!(
1256+
TextDirection::from_lang_code("ar"),
1257+
TextDirection::RightToLeft
1258+
);
1259+
assert_eq!(
1260+
TextDirection::from_lang_code("ara"),
1261+
TextDirection::RightToLeft
1262+
);
1263+
assert_eq!(
1264+
TextDirection::from_lang_code("arc"),
1265+
TextDirection::RightToLeft
1266+
);
1267+
assert_eq!(
1268+
TextDirection::from_lang_code("ae"),
1269+
TextDirection::RightToLeft
1270+
);
1271+
assert_eq!(
1272+
TextDirection::from_lang_code("ave"),
1273+
TextDirection::RightToLeft
1274+
);
1275+
assert_eq!(
1276+
TextDirection::from_lang_code("egy"),
1277+
TextDirection::RightToLeft
1278+
);
1279+
assert_eq!(
1280+
TextDirection::from_lang_code("he"),
1281+
TextDirection::RightToLeft
1282+
);
1283+
assert_eq!(
1284+
TextDirection::from_lang_code("heb"),
1285+
TextDirection::RightToLeft
1286+
);
1287+
assert_eq!(
1288+
TextDirection::from_lang_code("nqo"),
1289+
TextDirection::RightToLeft
1290+
);
1291+
assert_eq!(
1292+
TextDirection::from_lang_code("pal"),
1293+
TextDirection::RightToLeft
1294+
);
1295+
assert_eq!(
1296+
TextDirection::from_lang_code("phn"),
1297+
TextDirection::RightToLeft
1298+
);
1299+
assert_eq!(
1300+
TextDirection::from_lang_code("sam"),
1301+
TextDirection::RightToLeft
1302+
);
1303+
assert_eq!(
1304+
TextDirection::from_lang_code("syc"),
1305+
TextDirection::RightToLeft
1306+
);
1307+
assert_eq!(
1308+
TextDirection::from_lang_code("syr"),
1309+
TextDirection::RightToLeft
1310+
);
1311+
assert_eq!(
1312+
TextDirection::from_lang_code("fa"),
1313+
TextDirection::RightToLeft
1314+
);
1315+
assert_eq!(
1316+
TextDirection::from_lang_code("per"),
1317+
TextDirection::RightToLeft
1318+
);
1319+
assert_eq!(
1320+
TextDirection::from_lang_code("fas"),
1321+
TextDirection::RightToLeft
1322+
);
1323+
assert_eq!(
1324+
TextDirection::from_lang_code("ku"),
1325+
TextDirection::RightToLeft
1326+
);
1327+
assert_eq!(
1328+
TextDirection::from_lang_code("kur"),
1329+
TextDirection::RightToLeft
1330+
);
1331+
assert_eq!(
1332+
TextDirection::from_lang_code("ur"),
1333+
TextDirection::RightToLeft
1334+
);
1335+
assert_eq!(
1336+
TextDirection::from_lang_code("urd"),
1337+
TextDirection::RightToLeft
1338+
);
1339+
1340+
// test some left-to-right languages
1341+
assert_eq!(
1342+
TextDirection::from_lang_code("de"),
1343+
TextDirection::LeftToRight
1344+
);
1345+
assert_eq!(
1346+
TextDirection::from_lang_code("en"),
1347+
TextDirection::LeftToRight
1348+
);
1349+
assert_eq!(
1350+
TextDirection::from_lang_code("es"),
1351+
TextDirection::LeftToRight
1352+
);
1353+
assert_eq!(
1354+
TextDirection::from_lang_code("ja"),
1355+
TextDirection::LeftToRight
1356+
);
1357+
assert_eq!(
1358+
TextDirection::from_lang_code("sv"),
1359+
TextDirection::LeftToRight
1360+
);
1361+
}
1362+
11431363
#[test]
11441364
#[should_panic(expected = "Invalid configuration file")]
11451365
fn invalid_language_type_error() {

0 commit comments

Comments
 (0)