@@ -411,6 +411,9 @@ pub struct BookConfig {
411
411
pub multilingual : bool ,
412
412
/// The main language of the book.
413
413
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 > ,
414
417
}
415
418
416
419
impl Default for BookConfig {
@@ -422,6 +425,44 @@ impl Default for BookConfig {
422
425
src : PathBuf :: from ( "src" ) ,
423
426
multilingual : false ,
424
427
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 ,
425
466
}
426
467
}
427
468
}
@@ -788,6 +829,7 @@ mod tests {
788
829
multilingual : true ,
789
830
src : PathBuf :: from ( "source" ) ,
790
831
language : Some ( String :: from ( "ja" ) ) ,
832
+ text_direction : None ,
791
833
} ;
792
834
let build_should_be = BuildConfig {
793
835
build_dir : PathBuf :: from ( "outputs" ) ,
@@ -1140,6 +1182,184 @@ mod tests {
1140
1182
assert_eq ! ( & get_404_output_file( & html_config. input_404) , "missing.html" ) ;
1141
1183
}
1142
1184
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
+
1143
1363
#[ test]
1144
1364
#[ should_panic( expected = "Invalid configuration file" ) ]
1145
1365
fn invalid_language_type_error ( ) {
0 commit comments