Add language config section

Referencing https://github.com/rust-lang/mdBook/issues/5#issuecomment-323573492.
This commit is contained in:
Ruin0x11 2020-08-27 13:27:47 -07:00
parent 93008cf20b
commit e4b443cd4a

View File

@ -72,6 +72,8 @@ pub struct Config {
pub build: BuildConfig, pub build: BuildConfig,
/// Information about Rust language support. /// Information about Rust language support.
pub rust: RustConfig, pub rust: RustConfig,
/// Information about localizations of this book.
pub language: LanguageConfig,
rest: Value, rest: Value,
} }
@ -290,6 +292,7 @@ impl Default for Config {
book: BookConfig::default(), book: BookConfig::default(),
build: BuildConfig::default(), build: BuildConfig::default(),
rust: RustConfig::default(), rust: RustConfig::default(),
language: LanguageConfig::default(),
rest: Value::Table(Table::default()), rest: Value::Table(Table::default()),
} }
} }
@ -339,9 +342,29 @@ impl<'de> Deserialize<'de> for Config {
.transpose()? .transpose()?
.unwrap_or_default(); .unwrap_or_default();
let language: LanguageConfig = table
.remove("language")
.and_then(|value| value.try_into().ok())
.unwrap_or_default();
if !language.0.is_empty() {
let default_languages = language.0
.iter()
.filter(|(_, lang)| lang.default)
.count();
if default_languages != 1 {
use serde::de::Error;
return Err(D::Error::custom(
"If languages are specified, exactly one must be set as 'default'"
));
}
}
Ok(Config { Ok(Config {
book, book,
build, build,
language,
rust, rust,
rest: Value::Table(table), rest: Value::Table(table),
}) })
@ -689,6 +712,28 @@ impl Default for Search {
} }
} }
/// Configuration for localizations of this book
#[derive(Debug, Default, Clone, PartialEq, Serialize, Deserialize)]
#[serde(transparent)]
pub struct LanguageConfig(HashMap<String, Language>);
/// Configuration for a single localization
#[derive(Debug, Default, Clone, PartialEq, Serialize, Deserialize)]
#[serde(default, rename_all = "kebab-case")]
pub struct Language {
name: String,
default: bool,
}
impl LanguageConfig {
/// Returns the default language specified in the config.
pub fn default_language(&self) -> Option<&Language> {
self.0.iter()
.find(|(_, lang)| lang.default)
.map(|(_, lang)| lang)
}
}
/// Allows you to "update" any arbitrary field in a struct by round-tripping via /// Allows you to "update" any arbitrary field in a struct by round-tripping via
/// a `toml::Value`. /// a `toml::Value`.
/// ///
@ -751,6 +796,13 @@ mod tests {
[preprocessor.first] [preprocessor.first]
[preprocessor.second] [preprocessor.second]
[language.en]
name = "English"
default = true
[language.fr]
name = "Français"
"#; "#;
#[test] #[test]
@ -797,6 +849,9 @@ mod tests {
.collect(), .collect(),
..Default::default() ..Default::default()
}; };
let mut language_should_be = LanguageConfig::default();
language_should_be.0.insert(String::from("en"), Language { name: String::from("English"), default: true });
language_should_be.0.insert(String::from("fr"), Language { name: String::from("Français"), default: false });
let got = Config::from_str(src).unwrap(); let got = Config::from_str(src).unwrap();
@ -804,6 +859,7 @@ mod tests {
assert_eq!(got.build, build_should_be); assert_eq!(got.build, build_should_be);
assert_eq!(got.rust, rust_should_be); assert_eq!(got.rust, rust_should_be);
assert_eq!(got.html_config().unwrap(), html_should_be); assert_eq!(got.html_config().unwrap(), html_should_be);
assert_eq!(got.language, language_should_be);
} }
#[test] #[test]
@ -1150,4 +1206,31 @@ mod tests {
Config::from_str(src).unwrap(); Config::from_str(src).unwrap();
} }
#[test]
#[should_panic(expected = "Invalid configuration file")]
fn validate_default_language() {
let src = r#"
[language.en]
name = "English"
"#;
Config::from_str(src).unwrap();
}
#[test]
#[should_panic(expected = "Invalid configuration file")]
fn validate_default_language_2() {
let src = r#"
[language.en]
name = "English"
default = true
[language.fr]
name = "Français"
default = true
"#;
Config::from_str(src).unwrap();
}
} }