Remove 'default' property on languages, use book.language instead
This commit is contained in:
parent
a042cfc72b
commit
ee740aceff
@ -15,7 +15,7 @@ pub fn load_book<P: AsRef<Path>>(
|
||||
cfg: &Config,
|
||||
build_opts: &BuildOpts,
|
||||
) -> Result<LoadedBook> {
|
||||
if cfg.language.has_localized_dir_structure() {
|
||||
if cfg.has_localized_dir_structure() {
|
||||
match build_opts.language_ident {
|
||||
// Build a single book's translation.
|
||||
Some(_) => Ok(LoadedBook::Single(load_single_book_translation(
|
||||
|
@ -14,18 +14,18 @@ pub struct BookBuilder {
|
||||
create_gitignore: bool,
|
||||
config: Config,
|
||||
copy_theme: bool,
|
||||
language_ident: String
|
||||
language_ident: String,
|
||||
}
|
||||
|
||||
fn add_default_language(cfg: &mut Config, language_ident: String) {
|
||||
let language = Language {
|
||||
name: String::from("English"),
|
||||
default: true,
|
||||
title: None,
|
||||
authors: None,
|
||||
description: None,
|
||||
};
|
||||
cfg.language.0.insert(language_ident, language);
|
||||
cfg.language.0.insert(language_ident.clone(), language);
|
||||
cfg.book.language = Some(language_ident);
|
||||
}
|
||||
|
||||
impl BookBuilder {
|
||||
@ -41,13 +41,16 @@ impl BookBuilder {
|
||||
create_gitignore: false,
|
||||
config: cfg,
|
||||
copy_theme: false,
|
||||
language_ident: language_ident
|
||||
language_ident: language_ident,
|
||||
}
|
||||
}
|
||||
|
||||
/// Get the output source directory of the builder.
|
||||
pub fn source_dir(&self) -> PathBuf {
|
||||
let src = self.config.get_localized_src_path(Some(&self.language_ident)).unwrap();
|
||||
let src = self
|
||||
.config
|
||||
.get_localized_src_path(Some(&self.language_ident))
|
||||
.unwrap();
|
||||
self.root.join(src)
|
||||
}
|
||||
|
||||
@ -125,8 +128,8 @@ impl BookBuilder {
|
||||
|
||||
File::create(book_toml)
|
||||
.with_context(|| "Couldn't create book.toml")?
|
||||
.write_all(&cfg)
|
||||
.with_context(|| "Unable to write config to book.toml")?;
|
||||
.write_all(&cfg)
|
||||
.with_context(|| "Unable to write config to book.toml")?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
@ -19,7 +19,7 @@ pub fn make_subcommand<'a, 'b>() -> App<'a, 'b> {
|
||||
.arg_from_usage("-o, --open 'Opens the compiled book in a web browser'")
|
||||
.arg_from_usage(
|
||||
"-l, --language=[language] 'Language to render the compiled book in.{n}\
|
||||
Only valid if the [languages] table in the config is not empty.{n}\
|
||||
Only valid if the [language] table in the config is not empty.{n}\
|
||||
If omitted, builds all translations and provides a menu in the generated output for switching between them.'",
|
||||
)
|
||||
}
|
||||
|
@ -20,7 +20,7 @@ pub fn make_subcommand<'a, 'b>() -> App<'a, 'b> {
|
||||
)
|
||||
.arg_from_usage(
|
||||
"-l, --language=[language] 'Language to render the compiled book in.{n}\
|
||||
Only valid if the [languages] table in the config is not empty.{n}\
|
||||
Only valid if the [language] table in the config is not empty.{n}\
|
||||
If omitted, builds all translations and provides a menu in the generated output for switching between them.'",
|
||||
)
|
||||
}
|
||||
|
@ -52,7 +52,7 @@ pub fn make_subcommand<'a, 'b>() -> App<'a, 'b> {
|
||||
.arg_from_usage("-o, --open 'Opens the book server in a web browser'")
|
||||
.arg_from_usage(
|
||||
"-l, --language=[language] 'Language to render the compiled book in.{n}\
|
||||
Only valid if the [languages] table in the config is not empty.{n}\
|
||||
Only valid if the [language] table in the config is not empty.{n}\
|
||||
If omitted, builds all translations and provides a menu in the generated output for switching between them.'",
|
||||
)
|
||||
}
|
||||
@ -86,7 +86,7 @@ pub fn execute(args: &ArgMatches) -> Result<()> {
|
||||
let language: Option<String> = match build_opts.language_ident {
|
||||
// index.html will be at the root directory.
|
||||
Some(_) => None,
|
||||
None => match book.config.language.default_language() {
|
||||
None => match book.config.default_language() {
|
||||
// If book has translations, index.html will be under src/en/ or
|
||||
// similar.
|
||||
Some(lang_ident) => Some(lang_ident.clone()),
|
||||
|
@ -26,7 +26,7 @@ pub fn make_subcommand<'a, 'b>() -> App<'a, 'b> {
|
||||
.empty_values(false)
|
||||
.help("A comma-separated list of directories to add to {n}the crate search path when building tests"))
|
||||
.arg_from_usage("-l, --language=[language] 'Language to render the compiled book in.{n}\
|
||||
Only valid if the [languages] table in the config is not empty.{n}\
|
||||
Only valid if the [language] table in the config is not empty.{n}\
|
||||
If omitted, builds all translations and provides a menu in the generated output for switching between them.'")
|
||||
}
|
||||
|
||||
|
@ -25,7 +25,7 @@ pub fn make_subcommand<'a, 'b>() -> App<'a, 'b> {
|
||||
.arg_from_usage("-o, --open 'Open the compiled book in a web browser'")
|
||||
.arg_from_usage(
|
||||
"-l, --language=[language] 'Language to render the compiled book in.{n}\
|
||||
Only valid if the [languages] table in the config is not empty.{n}\
|
||||
Only valid if the [language] table in the config is not empty.{n}\
|
||||
If omitted, builds all translations and provides a menu in the generated output for switching between them.'",
|
||||
)
|
||||
}
|
||||
|
100
src/config.rs
100
src/config.rs
@ -255,7 +255,7 @@ impl Config {
|
||||
|
||||
/// Gets the language configured for a book.
|
||||
pub fn get_language<I: AsRef<str>>(&self, index: Option<I>) -> Result<Option<String>> {
|
||||
match self.language.default_language() {
|
||||
match self.default_language() {
|
||||
// Languages have been specified, assume directory structure with
|
||||
// language subfolders.
|
||||
Some(ref default) => match index {
|
||||
@ -342,7 +342,7 @@ impl Config {
|
||||
/// missing in a localization, any links to them will gracefully degrade to
|
||||
/// the files that exist in this directory.
|
||||
pub fn get_fallback_src_path(&self) -> PathBuf {
|
||||
match self.language.default_language() {
|
||||
match self.default_language() {
|
||||
// Languages have been specified, assume directory structure with
|
||||
// language subfolders.
|
||||
Some(default) => {
|
||||
@ -358,6 +358,31 @@ impl Config {
|
||||
}
|
||||
}
|
||||
|
||||
/// If true, mdBook should assume there are subdirectories under src/
|
||||
/// corresponding to the localizations in the config. If false, src/ is a
|
||||
/// single directory containing the summary file and the rest.
|
||||
pub fn has_localized_dir_structure(&self) -> bool {
|
||||
!self.language.0.is_empty()
|
||||
}
|
||||
|
||||
/// Obtains the default language for this config.
|
||||
pub fn default_language(&self) -> Option<String> {
|
||||
if self.has_localized_dir_structure() {
|
||||
let language_ident = self
|
||||
.book
|
||||
.language
|
||||
.clone()
|
||||
.expect("Config has [language] table, but `book.language` not was declared");
|
||||
self.language.0.get(&language_ident).expect(&format!(
|
||||
"Expected [language.{}] to be declared in book.toml",
|
||||
language_ident
|
||||
));
|
||||
Some(language_ident)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
fn from_legacy(mut table: Value) -> Config {
|
||||
let mut cfg = Config::default();
|
||||
|
||||
@ -455,12 +480,28 @@ impl<'de> Deserialize<'de> for Config {
|
||||
|
||||
if !language.0.is_empty() {
|
||||
let default_languages = language.0.iter().filter(|(_, lang)| lang.default).count();
|
||||
|
||||
if default_languages != 1 {
|
||||
if default_languages != 1 {
|
||||
return Err(D::Error::custom(
|
||||
"If [languages] table is specified, exactly one entry must be set as 'default'",
|
||||
"If the [language] table is specified, then `book.language` must be declared",
|
||||
));
|
||||
}
|
||||
let language_ident = book.language.clone().unwrap();
|
||||
if language.0.get(&language_ident).is_none() {
|
||||
use serde::de::Error;
|
||||
return Err(D::Error::custom(format!(
|
||||
"Expected [language.{}] to be declared in book.toml",
|
||||
language_ident
|
||||
)));
|
||||
}
|
||||
for (ident, language) in language.0.iter() {
|
||||
if language.name.is_empty() {
|
||||
use serde::de::Error;
|
||||
return Err(D::Error::custom(format!(
|
||||
"`name` property for [language.{}] must be non-empty",
|
||||
ident
|
||||
)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(Config {
|
||||
@ -492,7 +533,8 @@ impl Serialize for Config {
|
||||
}
|
||||
|
||||
if !self.language.0.is_empty() {
|
||||
let language_config = Value::try_from(&self.language).expect("should always be serializable");
|
||||
let language_config =
|
||||
Value::try_from(&self.language).expect("should always be serializable");
|
||||
table.insert("language", language_config);
|
||||
}
|
||||
|
||||
@ -543,9 +585,7 @@ pub struct BookConfig {
|
||||
pub description: Option<String>,
|
||||
/// Location of the book source relative to the book's root directory.
|
||||
pub src: PathBuf,
|
||||
/// Does this book support more than one language? (Deprecated.)
|
||||
pub multilingual: bool,
|
||||
/// The main language of the book. (Deprecated.)
|
||||
/// The main language of the book.
|
||||
pub language: Option<String>,
|
||||
}
|
||||
|
||||
@ -556,7 +596,6 @@ impl Default for BookConfig {
|
||||
authors: Vec::new(),
|
||||
description: None,
|
||||
src: PathBuf::from("src"),
|
||||
multilingual: true,
|
||||
language: Some(String::from("en")),
|
||||
}
|
||||
}
|
||||
@ -830,9 +869,6 @@ pub struct LanguageConfig(pub HashMap<String, Language>);
|
||||
pub struct Language {
|
||||
/// Human-readable name of the language.
|
||||
pub name: String,
|
||||
/// 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<String>,
|
||||
/// The authors of the translation.
|
||||
@ -841,22 +877,7 @@ pub struct Language {
|
||||
pub description: Option<String>,
|
||||
}
|
||||
|
||||
impl LanguageConfig {
|
||||
/// If true, mdBook should assume there are subdirectories under src/
|
||||
/// corresponding to the localizations in the config. If false, src/ is a
|
||||
/// single directory containing the summary file and the rest.
|
||||
pub fn has_localized_dir_structure(&self) -> bool {
|
||||
self.default_language().is_some()
|
||||
}
|
||||
|
||||
/// Returns the default language specified in the config.
|
||||
pub fn default_language(&self) -> Option<&String> {
|
||||
self.0
|
||||
.iter()
|
||||
.find(|(_, lang)| lang.default)
|
||||
.map(|(lang_ident, _)| lang_ident)
|
||||
}
|
||||
}
|
||||
impl LanguageConfig {}
|
||||
|
||||
/// Allows you to "update" any arbitrary field in a struct by round-tripping via
|
||||
/// a `toml::Value`.
|
||||
@ -923,7 +944,6 @@ mod tests {
|
||||
|
||||
[language.en]
|
||||
name = "English"
|
||||
default = true
|
||||
|
||||
[language.ja]
|
||||
name = "日本語"
|
||||
@ -940,7 +960,6 @@ mod tests {
|
||||
title: Some(String::from("Some Book")),
|
||||
authors: vec![String::from("Michael-F-Bryan <michaelfbryan@gmail.com>")],
|
||||
description: Some(String::from("A completely useless book")),
|
||||
multilingual: true,
|
||||
src: PathBuf::from("source"),
|
||||
language: Some(String::from("ja")),
|
||||
};
|
||||
@ -981,7 +1000,6 @@ mod tests {
|
||||
String::from("en"),
|
||||
Language {
|
||||
name: String::from("English"),
|
||||
default: true,
|
||||
title: None,
|
||||
description: None,
|
||||
authors: None,
|
||||
@ -991,7 +1009,6 @@ mod tests {
|
||||
String::from("ja"),
|
||||
Language {
|
||||
name: String::from("日本語"),
|
||||
default: false,
|
||||
title: Some(String::from("なんかの本")),
|
||||
description: Some(String::from("何の役にも立たない本")),
|
||||
authors: Some(vec![String::from("Ruin0x11")]),
|
||||
@ -1354,10 +1371,10 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
#[should_panic(expected = "Invalid configuration file")]
|
||||
fn validate_default_language() {
|
||||
fn validate_config_default_language_must_exist_in_languages_table() {
|
||||
let src = r#"
|
||||
[language.en]
|
||||
name = "English"
|
||||
[language.ja]
|
||||
name = "日本語"
|
||||
"#;
|
||||
|
||||
Config::from_str(src).unwrap();
|
||||
@ -1365,15 +1382,12 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
#[should_panic(expected = "Invalid configuration file")]
|
||||
fn validate_default_language_2() {
|
||||
fn validate_language_config_must_have_name() {
|
||||
let src = r#"
|
||||
[language.en]
|
||||
name = "English"
|
||||
default = true
|
||||
[book]
|
||||
language = "en"
|
||||
|
||||
[language.fr]
|
||||
name = "Français"
|
||||
default = true
|
||||
[language.en]
|
||||
"#;
|
||||
|
||||
Config::from_str(src).unwrap();
|
||||
|
@ -10,7 +10,13 @@ use tempfile::Builder as TempFileBuilder;
|
||||
/// are created.
|
||||
#[test]
|
||||
fn base_mdbook_init_should_create_default_content() {
|
||||
let created_files = vec!["book", "src", "src/en", "src/en/SUMMARY.md", "src/en/chapter_1.md"];
|
||||
let created_files = vec![
|
||||
"book",
|
||||
"src",
|
||||
"src/en",
|
||||
"src/en/SUMMARY.md",
|
||||
"src/en/chapter_1.md",
|
||||
];
|
||||
|
||||
let temp = TempFileBuilder::new().prefix("mdbook").tempdir().unwrap();
|
||||
for file in &created_files {
|
||||
@ -28,7 +34,7 @@ fn base_mdbook_init_should_create_default_content() {
|
||||
let contents = fs::read_to_string(temp.path().join("book.toml")).unwrap();
|
||||
assert_eq!(
|
||||
contents,
|
||||
"[book]\nauthors = []\nlanguage = \"en\"\nmultilingual = true\nsrc = \"src\"\n[language.en]\ndefault = true\nname = \"English\"\n"
|
||||
"[book]\nauthors = []\nlanguage = \"en\"\nsrc = \"src\"\n[language.en]\nname = \"English\"\n"
|
||||
);
|
||||
}
|
||||
|
||||
@ -66,7 +72,13 @@ fn run_mdbook_init_should_create_content_from_summary() {
|
||||
/// files, then call `mdbook init`.
|
||||
#[test]
|
||||
fn run_mdbook_init_with_custom_book_and_src_locations() {
|
||||
let created_files = vec!["out", "in", "in/en", "in/en/SUMMARY.md", "in/en/chapter_1.md"];
|
||||
let created_files = vec![
|
||||
"out",
|
||||
"in",
|
||||
"in/en",
|
||||
"in/en/SUMMARY.md",
|
||||
"in/en/chapter_1.md",
|
||||
];
|
||||
|
||||
let temp = TempFileBuilder::new().prefix("mdbook").tempdir().unwrap();
|
||||
for file in &created_files {
|
||||
|
Loading…
Reference in New Issue
Block a user