From 5e223e074e11a8ab6de0376d96829936eeca99a2 Mon Sep 17 00:00:00 2001 From: Ruin0x11 Date: Fri, 28 Aug 2020 03:17:26 -0700 Subject: [PATCH] Support localizing book title/description --- src/config.rs | 104 ++++++++++++++----- src/renderer/html_handlebars/hbs_renderer.rs | 10 +- tests/localized_book/book.toml | 3 + 3 files changed, 91 insertions(+), 26 deletions(-) diff --git a/src/config.rs b/src/config.rs index fa49677c..8eeced25 100644 --- a/src/config.rs +++ b/src/config.rs @@ -253,37 +253,26 @@ impl Config { self.get(&key).and_then(Value::as_table) } - /// Get the source directory of a localized book corresponding to language ident `index`. - pub fn get_localized_src_path>(&self, index: Option) -> Result { + /// Gets the language configured for a book. + pub fn get_language>(&self, index: Option) -> Result> { match self.language.default_language() { // Languages have been specified, assume directory structure with // language subfolders. - Some(default) => match index { + Some(ref default) => match index { // Make sure that the language we passed was actually // declared in the config, and return `None` if not. Some(lang_ident) => match self.language.0.get(lang_ident.as_ref()) { - Some(_) => { - let mut buf = PathBuf::new(); - buf.push(self.book.src.clone()); - buf.push(lang_ident.as_ref()); - Ok(buf) - } + Some(_) => Ok(Some(lang_ident.as_ref().into())), None => Err(anyhow!( "Expected [language.{}] to be declared in book.toml", lang_ident.as_ref() )), }, // Use the default specified in book.toml. - None => { - let mut buf = PathBuf::new(); - buf.push(self.book.src.clone()); - buf.push(default); - Ok(buf) - } + None => Ok(Some(default.to_string())), }, - // No default language was configured in book.toml. Preserve - // backwards compatibility by just returning `src`. + // No default language was configured in book.toml. None => match index { // We passed in a language from the frontend, but the config // offers no languages. @@ -292,11 +281,63 @@ impl Config { lang_ident.as_ref() )), // Default to previous non-localized behavior. - None => Ok(self.book.src.clone()), + None => Ok(None), }, } } + /// Get the source directory of a localized book corresponding to language ident `index`. + pub fn get_localized_src_path>(&self, index: Option) -> Result { + let language = self.get_language(index)?; + + match language { + Some(lang_ident) => { + let mut buf = PathBuf::new(); + buf.push(self.book.src.clone()); + buf.push(lang_ident); + Ok(buf) + } + + // No default language was configured in book.toml. Preserve + // backwards compatibility by just returning `src`. + None => Ok(self.book.src.clone()), + } + } + + /// Gets the localized title of the book. + pub fn get_localized_title>(&self, index: Option) -> Option { + let language = self.get_language(index).unwrap(); + + match language { + Some(lang_ident) => self + .language + .0 + .get(&lang_ident) + .unwrap() + .title + .clone() + .or(self.book.title.clone()), + None => self.book.title.clone(), + } + } + + /// Gets the localized description of the book. + pub fn get_localized_description>(&self, index: Option) -> Option { + let language = self.get_language(index).unwrap(); + + match language { + Some(lang_ident) => self + .language + .0 + .get(&lang_ident) + .unwrap() + .description + .clone() + .or(self.book.description.clone()), + None => self.book.description.clone(), + } + } + /// Get the fallback source directory of a book. If chapters/sections are /// missing in a localization, any links to them will gracefully degrade to /// the files that exist in this directory. @@ -497,9 +538,9 @@ pub struct BookConfig { pub description: Option, /// Location of the book source relative to the book's root directory. pub src: PathBuf, - /// Does this book support more than one language? + /// Does this book support more than one language? (Deprecated.) pub multilingual: bool, - /// The main language of the book. + /// The main language of the book. (Deprecated.) pub language: Option, } @@ -787,6 +828,12 @@ pub struct Language { /// If true, this language is the default. There must be exactly one default /// language in the config. pub default: bool, + /// Localized title of the book. + pub title: Option, + /// The authors of the translation. + pub authors: Option>, + /// Localized description of the book. + pub description: Option, } impl LanguageConfig { @@ -873,8 +920,11 @@ mod tests { name = "English" default = true - [language.fr] - name = "Français" + [language.ja] + name = "日本語" + title = "なんかの本" + description = "何の役にも立たない本" + authors = ["Ruin0x11"] "#; #[test] @@ -927,13 +977,19 @@ mod tests { Language { name: String::from("English"), default: true, + title: None, + description: None, + authors: None, }, ); language_should_be.0.insert( - String::from("fr"), + String::from("ja"), Language { - name: String::from("Français"), + name: String::from("日本語"), default: false, + title: Some(String::from("なんかの本")), + description: Some(String::from("何の役にも立たない本")), + authors: Some(vec![String::from("Ruin0x11")]), }, ); diff --git a/src/renderer/html_handlebars/hbs_renderer.rs b/src/renderer/html_handlebars/hbs_renderer.rs index a44e64d1..0eb3a76f 100644 --- a/src/renderer/html_handlebars/hbs_renderer.rs +++ b/src/renderer/html_handlebars/hbs_renderer.rs @@ -45,6 +45,7 @@ impl HtmlHandlebars { &localized_src_dir, &localized_destination, &localized_build_dir, + &Some(lang_ident.to_string()), html_config, handlebars, theme, @@ -74,6 +75,7 @@ impl HtmlHandlebars { &extra_file_dir, &ctx.destination, &ctx.config.build.build_dir, + &ctx.build_opts.language_ident, html_config, handlebars, theme, @@ -92,6 +94,7 @@ impl HtmlHandlebars { extra_file_dir: &PathBuf, destination: &PathBuf, build_dir: &PathBuf, + language_ident: &Option, html_config: &HtmlConfig, handlebars: &mut Handlebars<'a>, theme: &Theme, @@ -102,6 +105,7 @@ impl HtmlHandlebars { &book, &ctx.book, &ctx.config, + language_ident, &html_config, &theme, )?; @@ -746,23 +750,25 @@ fn make_data( book: &Book, loaded_book: &LoadedBook, config: &Config, + language_ident: &Option, html_config: &HtmlConfig, theme: &Theme, ) -> Result> { trace!("make_data"); let mut data = serde_json::Map::new(); + data.insert( "language".to_owned(), json!(config.book.language.clone().unwrap_or_default()), ); data.insert( "book_title".to_owned(), - json!(config.book.title.clone().unwrap_or_default()), + json!(config.get_localized_title(language_ident.as_ref())), ); data.insert( "description".to_owned(), - json!(config.book.description.clone().unwrap_or_default()), + json!(config.get_localized_description(language_ident.as_ref())), ); if theme.favicon_png.is_some() { data.insert("favicon_png".to_owned(), json!("favicon.png")); diff --git a/tests/localized_book/book.toml b/tests/localized_book/book.toml index c513aade..03199a0c 100644 --- a/tests/localized_book/book.toml +++ b/tests/localized_book/book.toml @@ -30,3 +30,6 @@ default = true [language.ja] name = "日本語" +title = "翻訳された本" +description = "mdBookの翻訳機能のテスト用の本" +authors = ["Ruin0x11"]