@@ -417,6 +417,9 @@ pub struct BookConfig {
417
417
pub multilingual : bool ,
418
418
/// The main language of the book.
419
419
pub language : Option < String > ,
420
+ /// The direction of text in the book: Left-to-right (LTR) or Right-to-left (RTL).
421
+ /// When not specified, the correct text direction is derived from [BookConfig::language].
422
+ pub text_direction : Option < TextDirection > ,
420
423
}
421
424
422
425
impl Default for BookConfig {
@@ -428,6 +431,44 @@ impl Default for BookConfig {
428
431
src : PathBuf :: from ( "src" ) ,
429
432
multilingual : false ,
430
433
language : Some ( String :: from ( "en" ) ) ,
434
+ text_direction : None ,
435
+ }
436
+ }
437
+ }
438
+
439
+ impl BookConfig {
440
+ /// Gets the realized text direction, either from [BookConfig::text_direction]
441
+ /// or derived from [BookConfig::language], to be used by templating engines.
442
+ pub fn realized_text_direction ( & self ) -> TextDirection {
443
+ if let Some ( direction) = self . text_direction {
444
+ direction
445
+ } else {
446
+ TextDirection :: from_lang_code ( & self . language . clone ( ) . unwrap_or_default ( ) )
447
+ }
448
+ }
449
+ }
450
+
451
+ /// Text direction to use for HTML output
452
+ #[ derive( Debug , Copy , Clone , PartialEq , Serialize , Deserialize ) ]
453
+ pub enum TextDirection {
454
+ /// Left to right.
455
+ #[ serde( rename = "ltr" ) ]
456
+ LeftToRight ,
457
+ /// Right to left
458
+ #[ serde( rename = "rtl" ) ]
459
+ RightToLeft ,
460
+ }
461
+
462
+ impl TextDirection {
463
+ /// Gets the text direction from language code
464
+ pub fn from_lang_code ( code : & str ) -> Self {
465
+ match code {
466
+ // list sourced from here: https://github.com/abarrak/rtl/blob/master/lib/rtl/core.rb#L16
467
+ "ar" | "ara" | "arc" | "ae" | "ave" | "egy" | "he" | "heb" | "nqo" | "pal" | "phn"
468
+ | "sam" | "syc" | "syr" | "fa" | "per" | "fas" | "ku" | "kur" | "ur" | "urd" => {
469
+ TextDirection :: RightToLeft
470
+ }
471
+ _ => TextDirection :: LeftToRight ,
431
472
}
432
473
}
433
474
}
@@ -764,6 +805,7 @@ mod tests {
764
805
multilingual : true ,
765
806
src : PathBuf :: from ( "source" ) ,
766
807
language : Some ( String :: from ( "ja" ) ) ,
808
+ text_direction : None ,
767
809
} ;
768
810
let build_should_be = BuildConfig {
769
811
build_dir : PathBuf :: from ( "outputs" ) ,
@@ -1098,6 +1140,184 @@ mod tests {
1098
1140
assert_eq ! ( & get_404_output_file( & html_config. input_404) , "missing.html" ) ;
1099
1141
}
1100
1142
1143
+ #[ test]
1144
+ fn text_direction_ltr ( ) {
1145
+ let src = r#"
1146
+ [book]
1147
+ text-direction = "ltr"
1148
+ "# ;
1149
+
1150
+ let got = Config :: from_str ( src) . unwrap ( ) ;
1151
+ assert_eq ! ( got. book. text_direction, Some ( TextDirection :: LeftToRight ) ) ;
1152
+ }
1153
+
1154
+ #[ test]
1155
+ fn text_direction_rtl ( ) {
1156
+ let src = r#"
1157
+ [book]
1158
+ text-direction = "rtl"
1159
+ "# ;
1160
+
1161
+ let got = Config :: from_str ( src) . unwrap ( ) ;
1162
+ assert_eq ! ( got. book. text_direction, Some ( TextDirection :: RightToLeft ) ) ;
1163
+ }
1164
+
1165
+ #[ test]
1166
+ fn text_direction_none ( ) {
1167
+ let src = r#"
1168
+ [book]
1169
+ "# ;
1170
+
1171
+ let got = Config :: from_str ( src) . unwrap ( ) ;
1172
+ assert_eq ! ( got. book. text_direction, None ) ;
1173
+ }
1174
+
1175
+ #[ test]
1176
+ fn test_text_direction ( ) {
1177
+ let mut cfg = BookConfig :: default ( ) ;
1178
+
1179
+ // test deriving the text direction from language codes
1180
+ cfg. language = Some ( "ar" . into ( ) ) ;
1181
+ assert_eq ! ( cfg. realized_text_direction( ) , TextDirection :: RightToLeft ) ;
1182
+
1183
+ cfg. language = Some ( "he" . into ( ) ) ;
1184
+ assert_eq ! ( cfg. realized_text_direction( ) , TextDirection :: RightToLeft ) ;
1185
+
1186
+ cfg. language = Some ( "en" . into ( ) ) ;
1187
+ assert_eq ! ( cfg. realized_text_direction( ) , TextDirection :: LeftToRight ) ;
1188
+
1189
+ cfg. language = Some ( "ja" . into ( ) ) ;
1190
+ assert_eq ! ( cfg. realized_text_direction( ) , TextDirection :: LeftToRight ) ;
1191
+
1192
+ // test forced direction
1193
+ cfg. language = Some ( "ar" . into ( ) ) ;
1194
+ cfg. text_direction = Some ( TextDirection :: LeftToRight ) ;
1195
+ assert_eq ! ( cfg. realized_text_direction( ) , TextDirection :: LeftToRight ) ;
1196
+
1197
+ cfg. language = Some ( "ar" . into ( ) ) ;
1198
+ cfg. text_direction = Some ( TextDirection :: RightToLeft ) ;
1199
+ assert_eq ! ( cfg. realized_text_direction( ) , TextDirection :: RightToLeft ) ;
1200
+
1201
+ cfg. language = Some ( "en" . into ( ) ) ;
1202
+ cfg. text_direction = Some ( TextDirection :: LeftToRight ) ;
1203
+ assert_eq ! ( cfg. realized_text_direction( ) , TextDirection :: LeftToRight ) ;
1204
+
1205
+ cfg. language = Some ( "en" . into ( ) ) ;
1206
+ cfg. text_direction = Some ( TextDirection :: RightToLeft ) ;
1207
+ assert_eq ! ( cfg. realized_text_direction( ) , TextDirection :: RightToLeft ) ;
1208
+ }
1209
+
1210
+ #[ test]
1211
+ fn text_drection_from_lang_code ( ) {
1212
+ // test all right-to-left languages
1213
+ assert_eq ! (
1214
+ TextDirection :: from_lang_code( "ar" ) ,
1215
+ TextDirection :: RightToLeft
1216
+ ) ;
1217
+ assert_eq ! (
1218
+ TextDirection :: from_lang_code( "ara" ) ,
1219
+ TextDirection :: RightToLeft
1220
+ ) ;
1221
+ assert_eq ! (
1222
+ TextDirection :: from_lang_code( "arc" ) ,
1223
+ TextDirection :: RightToLeft
1224
+ ) ;
1225
+ assert_eq ! (
1226
+ TextDirection :: from_lang_code( "ae" ) ,
1227
+ TextDirection :: RightToLeft
1228
+ ) ;
1229
+ assert_eq ! (
1230
+ TextDirection :: from_lang_code( "ave" ) ,
1231
+ TextDirection :: RightToLeft
1232
+ ) ;
1233
+ assert_eq ! (
1234
+ TextDirection :: from_lang_code( "egy" ) ,
1235
+ TextDirection :: RightToLeft
1236
+ ) ;
1237
+ assert_eq ! (
1238
+ TextDirection :: from_lang_code( "he" ) ,
1239
+ TextDirection :: RightToLeft
1240
+ ) ;
1241
+ assert_eq ! (
1242
+ TextDirection :: from_lang_code( "heb" ) ,
1243
+ TextDirection :: RightToLeft
1244
+ ) ;
1245
+ assert_eq ! (
1246
+ TextDirection :: from_lang_code( "nqo" ) ,
1247
+ TextDirection :: RightToLeft
1248
+ ) ;
1249
+ assert_eq ! (
1250
+ TextDirection :: from_lang_code( "pal" ) ,
1251
+ TextDirection :: RightToLeft
1252
+ ) ;
1253
+ assert_eq ! (
1254
+ TextDirection :: from_lang_code( "phn" ) ,
1255
+ TextDirection :: RightToLeft
1256
+ ) ;
1257
+ assert_eq ! (
1258
+ TextDirection :: from_lang_code( "sam" ) ,
1259
+ TextDirection :: RightToLeft
1260
+ ) ;
1261
+ assert_eq ! (
1262
+ TextDirection :: from_lang_code( "syc" ) ,
1263
+ TextDirection :: RightToLeft
1264
+ ) ;
1265
+ assert_eq ! (
1266
+ TextDirection :: from_lang_code( "syr" ) ,
1267
+ TextDirection :: RightToLeft
1268
+ ) ;
1269
+ assert_eq ! (
1270
+ TextDirection :: from_lang_code( "fa" ) ,
1271
+ TextDirection :: RightToLeft
1272
+ ) ;
1273
+ assert_eq ! (
1274
+ TextDirection :: from_lang_code( "per" ) ,
1275
+ TextDirection :: RightToLeft
1276
+ ) ;
1277
+ assert_eq ! (
1278
+ TextDirection :: from_lang_code( "fas" ) ,
1279
+ TextDirection :: RightToLeft
1280
+ ) ;
1281
+ assert_eq ! (
1282
+ TextDirection :: from_lang_code( "ku" ) ,
1283
+ TextDirection :: RightToLeft
1284
+ ) ;
1285
+ assert_eq ! (
1286
+ TextDirection :: from_lang_code( "kur" ) ,
1287
+ TextDirection :: RightToLeft
1288
+ ) ;
1289
+ assert_eq ! (
1290
+ TextDirection :: from_lang_code( "ur" ) ,
1291
+ TextDirection :: RightToLeft
1292
+ ) ;
1293
+ assert_eq ! (
1294
+ TextDirection :: from_lang_code( "urd" ) ,
1295
+ TextDirection :: RightToLeft
1296
+ ) ;
1297
+
1298
+ // test some left-to-right languages
1299
+ assert_eq ! (
1300
+ TextDirection :: from_lang_code( "de" ) ,
1301
+ TextDirection :: LeftToRight
1302
+ ) ;
1303
+ assert_eq ! (
1304
+ TextDirection :: from_lang_code( "en" ) ,
1305
+ TextDirection :: LeftToRight
1306
+ ) ;
1307
+ assert_eq ! (
1308
+ TextDirection :: from_lang_code( "es" ) ,
1309
+ TextDirection :: LeftToRight
1310
+ ) ;
1311
+ assert_eq ! (
1312
+ TextDirection :: from_lang_code( "ja" ) ,
1313
+ TextDirection :: LeftToRight
1314
+ ) ;
1315
+ assert_eq ! (
1316
+ TextDirection :: from_lang_code( "sv" ) ,
1317
+ TextDirection :: LeftToRight
1318
+ ) ;
1319
+ }
1320
+
1101
1321
#[ test]
1102
1322
#[ should_panic( expected = "Invalid configuration file" ) ]
1103
1323
fn invalid_language_type_error ( ) {
0 commit comments