Skip to content

Commit 5e223e0

Browse files
committed
Support localizing book title/description
1 parent e17ce64 commit 5e223e0

File tree

3 files changed

+91
-26
lines changed

3 files changed

+91
-26
lines changed

src/config.rs

Lines changed: 80 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -253,37 +253,26 @@ impl Config {
253253
self.get(&key).and_then(Value::as_table)
254254
}
255255

256-
/// Get the source directory of a localized book corresponding to language ident `index`.
257-
pub fn get_localized_src_path<I: AsRef<str>>(&self, index: Option<I>) -> Result<PathBuf> {
256+
/// Gets the language configured for a book.
257+
pub fn get_language<I: AsRef<str>>(&self, index: Option<I>) -> Result<Option<String>> {
258258
match self.language.default_language() {
259259
// Languages have been specified, assume directory structure with
260260
// language subfolders.
261-
Some(default) => match index {
261+
Some(ref default) => match index {
262262
// Make sure that the language we passed was actually
263263
// declared in the config, and return `None` if not.
264264
Some(lang_ident) => match self.language.0.get(lang_ident.as_ref()) {
265-
Some(_) => {
266-
let mut buf = PathBuf::new();
267-
buf.push(self.book.src.clone());
268-
buf.push(lang_ident.as_ref());
269-
Ok(buf)
270-
}
265+
Some(_) => Ok(Some(lang_ident.as_ref().into())),
271266
None => Err(anyhow!(
272267
"Expected [language.{}] to be declared in book.toml",
273268
lang_ident.as_ref()
274269
)),
275270
},
276271
// Use the default specified in book.toml.
277-
None => {
278-
let mut buf = PathBuf::new();
279-
buf.push(self.book.src.clone());
280-
buf.push(default);
281-
Ok(buf)
282-
}
272+
None => Ok(Some(default.to_string())),
283273
},
284274

285-
// No default language was configured in book.toml. Preserve
286-
// backwards compatibility by just returning `src`.
275+
// No default language was configured in book.toml.
287276
None => match index {
288277
// We passed in a language from the frontend, but the config
289278
// offers no languages.
@@ -292,11 +281,63 @@ impl Config {
292281
lang_ident.as_ref()
293282
)),
294283
// Default to previous non-localized behavior.
295-
None => Ok(self.book.src.clone()),
284+
None => Ok(None),
296285
},
297286
}
298287
}
299288

289+
/// Get the source directory of a localized book corresponding to language ident `index`.
290+
pub fn get_localized_src_path<I: AsRef<str>>(&self, index: Option<I>) -> Result<PathBuf> {
291+
let language = self.get_language(index)?;
292+
293+
match language {
294+
Some(lang_ident) => {
295+
let mut buf = PathBuf::new();
296+
buf.push(self.book.src.clone());
297+
buf.push(lang_ident);
298+
Ok(buf)
299+
}
300+
301+
// No default language was configured in book.toml. Preserve
302+
// backwards compatibility by just returning `src`.
303+
None => Ok(self.book.src.clone()),
304+
}
305+
}
306+
307+
/// Gets the localized title of the book.
308+
pub fn get_localized_title<I: AsRef<str>>(&self, index: Option<I>) -> Option<String> {
309+
let language = self.get_language(index).unwrap();
310+
311+
match language {
312+
Some(lang_ident) => self
313+
.language
314+
.0
315+
.get(&lang_ident)
316+
.unwrap()
317+
.title
318+
.clone()
319+
.or(self.book.title.clone()),
320+
None => self.book.title.clone(),
321+
}
322+
}
323+
324+
/// Gets the localized description of the book.
325+
pub fn get_localized_description<I: AsRef<str>>(&self, index: Option<I>) -> Option<String> {
326+
let language = self.get_language(index).unwrap();
327+
328+
match language {
329+
Some(lang_ident) => self
330+
.language
331+
.0
332+
.get(&lang_ident)
333+
.unwrap()
334+
.description
335+
.clone()
336+
.or(self.book.description.clone()),
337+
None => self.book.description.clone(),
338+
}
339+
}
340+
300341
/// Get the fallback source directory of a book. If chapters/sections are
301342
/// missing in a localization, any links to them will gracefully degrade to
302343
/// the files that exist in this directory.
@@ -497,9 +538,9 @@ pub struct BookConfig {
497538
pub description: Option<String>,
498539
/// Location of the book source relative to the book's root directory.
499540
pub src: PathBuf,
500-
/// Does this book support more than one language?
541+
/// Does this book support more than one language? (Deprecated.)
501542
pub multilingual: bool,
502-
/// The main language of the book.
543+
/// The main language of the book. (Deprecated.)
503544
pub language: Option<String>,
504545
}
505546

@@ -787,6 +828,12 @@ pub struct Language {
787828
/// If true, this language is the default. There must be exactly one default
788829
/// language in the config.
789830
pub default: bool,
831+
/// Localized title of the book.
832+
pub title: Option<String>,
833+
/// The authors of the translation.
834+
pub authors: Option<Vec<String>>,
835+
/// Localized description of the book.
836+
pub description: Option<String>,
790837
}
791838

792839
impl LanguageConfig {
@@ -873,8 +920,11 @@ mod tests {
873920
name = "English"
874921
default = true
875922
876-
[language.fr]
877-
name = "Français"
923+
[language.ja]
924+
name = "日本語"
925+
title = "なんかの本"
926+
description = "何の役にも立たない本"
927+
authors = ["Ruin0x11"]
878928
"#;
879929

880930
#[test]
@@ -927,13 +977,19 @@ mod tests {
927977
Language {
928978
name: String::from("English"),
929979
default: true,
980+
title: None,
981+
description: None,
982+
authors: None,
930983
},
931984
);
932985
language_should_be.0.insert(
933-
String::from("fr"),
986+
String::from("ja"),
934987
Language {
935-
name: String::from("Français"),
988+
name: String::from("日本語"),
936989
default: false,
990+
title: Some(String::from("なんかの本")),
991+
description: Some(String::from("何の役にも立たない本")),
992+
authors: Some(vec![String::from("Ruin0x11")]),
937993
},
938994
);
939995

src/renderer/html_handlebars/hbs_renderer.rs

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ impl HtmlHandlebars {
4545
&localized_src_dir,
4646
&localized_destination,
4747
&localized_build_dir,
48+
&Some(lang_ident.to_string()),
4849
html_config,
4950
handlebars,
5051
theme,
@@ -74,6 +75,7 @@ impl HtmlHandlebars {
7475
&extra_file_dir,
7576
&ctx.destination,
7677
&ctx.config.build.build_dir,
78+
&ctx.build_opts.language_ident,
7779
html_config,
7880
handlebars,
7981
theme,
@@ -92,6 +94,7 @@ impl HtmlHandlebars {
9294
extra_file_dir: &PathBuf,
9395
destination: &PathBuf,
9496
build_dir: &PathBuf,
97+
language_ident: &Option<String>,
9598
html_config: &HtmlConfig,
9699
handlebars: &mut Handlebars<'a>,
97100
theme: &Theme,
@@ -102,6 +105,7 @@ impl HtmlHandlebars {
102105
&book,
103106
&ctx.book,
104107
&ctx.config,
108+
language_ident,
105109
&html_config,
106110
&theme,
107111
)?;
@@ -746,23 +750,25 @@ fn make_data(
746750
book: &Book,
747751
loaded_book: &LoadedBook,
748752
config: &Config,
753+
language_ident: &Option<String>,
749754
html_config: &HtmlConfig,
750755
theme: &Theme,
751756
) -> Result<serde_json::Map<String, serde_json::Value>> {
752757
trace!("make_data");
753758

754759
let mut data = serde_json::Map::new();
760+
755761
data.insert(
756762
"language".to_owned(),
757763
json!(config.book.language.clone().unwrap_or_default()),
758764
);
759765
data.insert(
760766
"book_title".to_owned(),
761-
json!(config.book.title.clone().unwrap_or_default()),
767+
json!(config.get_localized_title(language_ident.as_ref())),
762768
);
763769
data.insert(
764770
"description".to_owned(),
765-
json!(config.book.description.clone().unwrap_or_default()),
771+
json!(config.get_localized_description(language_ident.as_ref())),
766772
);
767773
if theme.favicon_png.is_some() {
768774
data.insert("favicon_png".to_owned(), json!("favicon.png"));

tests/localized_book/book.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,3 +30,6 @@ default = true
3030

3131
[language.ja]
3232
name = "日本語"
33+
title = "翻訳された本"
34+
description = "mdBookの翻訳機能のテスト用の本"
35+
authors = ["Ruin0x11"]

0 commit comments

Comments
 (0)