Merge default language data with section language data (#2039)
* Merge language data in config.toml
This commit is contained in:
parent
4aaed16c6d
commit
2d44fe81f6
@ -30,6 +30,91 @@ pub struct LanguageOptions {
|
|||||||
pub translations: HashMap<String, String>,
|
pub translations: HashMap<String, String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl LanguageOptions {
|
||||||
|
/// Merges self with another LanguageOptions, panicking if 2 equivalent fields are not None,
|
||||||
|
/// empty or of default value.
|
||||||
|
pub fn merge(&mut self, other: &LanguageOptions) -> Result<()> {
|
||||||
|
match &self.title {
|
||||||
|
None => self.title = other.title.clone(),
|
||||||
|
Some(self_title) => match &other.title {
|
||||||
|
Some(other_title) => bail!(
|
||||||
|
"`title` for default language is specified twice, as {:?} and {:?}.",
|
||||||
|
self_title,
|
||||||
|
other_title
|
||||||
|
),
|
||||||
|
None => (),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
match &self.description {
|
||||||
|
None => self.description = other.description.clone(),
|
||||||
|
Some(self_description) => match &other.description {
|
||||||
|
Some(other_description) => bail!(
|
||||||
|
"`description` for default language is specified twice, as {:?} and {:?}.",
|
||||||
|
self_description,
|
||||||
|
other_description
|
||||||
|
),
|
||||||
|
None => (),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
self.generate_feed = self.generate_feed || other.generate_feed;
|
||||||
|
|
||||||
|
match &self.feed_filename == "atom.xml" {
|
||||||
|
// "atom.xml" is default value.
|
||||||
|
true => self.feed_filename = other.feed_filename.clone(),
|
||||||
|
false => match &other.feed_filename.is_empty() {
|
||||||
|
false => bail!(
|
||||||
|
"`feed filename` for default language is specifiec twice, as {:?} and {:?}.",
|
||||||
|
self.feed_filename,
|
||||||
|
other.feed_filename
|
||||||
|
),
|
||||||
|
true => (),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
match &self.taxonomies.is_empty() {
|
||||||
|
true => self.taxonomies = other.taxonomies.clone(),
|
||||||
|
false => match &other.taxonomies.is_empty() {
|
||||||
|
false => bail!(
|
||||||
|
"`taxonomies` for default language is specifiec twice, as {:?} and {:?}.",
|
||||||
|
self.taxonomies,
|
||||||
|
other.taxonomies
|
||||||
|
),
|
||||||
|
true => (),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
self.build_search_index = self.build_search_index || other.build_search_index;
|
||||||
|
|
||||||
|
match self.search == search::Search::default() {
|
||||||
|
true => self.search = other.search.clone(),
|
||||||
|
false => match self.search == other.search {
|
||||||
|
false => bail!(
|
||||||
|
"`search` for default language is specified twice, as {:?} and {:?}.",
|
||||||
|
self.search,
|
||||||
|
other.search
|
||||||
|
),
|
||||||
|
true => (),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
match &self.translations.is_empty() {
|
||||||
|
true => self.translations = other.translations.clone(),
|
||||||
|
false => match &other.translations.is_empty() {
|
||||||
|
false => bail!(
|
||||||
|
"`translations` for default language is specified twice, as {:?} and {:?}.",
|
||||||
|
self.translations,
|
||||||
|
other.translations
|
||||||
|
),
|
||||||
|
true => (),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// We want to ensure the language codes are valid ones
|
/// We want to ensure the language codes are valid ones
|
||||||
pub fn validate_code(code: &str) -> Result<()> {
|
pub fn validate_code(code: &str) -> Result<()> {
|
||||||
if LanguageIdentifier::from_bytes(code.as_bytes()).is_err() {
|
if LanguageIdentifier::from_bytes(code.as_bytes()).is_err() {
|
||||||
@ -38,3 +123,65 @@ pub fn validate_code(code: &str) -> Result<()> {
|
|||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn merge_without_conflict() {
|
||||||
|
let mut base_default_language_options = LanguageOptions {
|
||||||
|
title: Some("Site's title".to_string()),
|
||||||
|
description: None,
|
||||||
|
generate_feed: true,
|
||||||
|
feed_filename: "atom.xml".to_string(),
|
||||||
|
taxonomies: vec![],
|
||||||
|
build_search_index: true,
|
||||||
|
search: search::Search::default(),
|
||||||
|
translations: HashMap::new(),
|
||||||
|
};
|
||||||
|
|
||||||
|
let section_default_language_options = LanguageOptions {
|
||||||
|
title: None,
|
||||||
|
description: Some("Site's description".to_string()),
|
||||||
|
generate_feed: false,
|
||||||
|
feed_filename: "rss.xml".to_string(),
|
||||||
|
taxonomies: vec![],
|
||||||
|
build_search_index: true,
|
||||||
|
search: search::Search::default(),
|
||||||
|
translations: HashMap::new(),
|
||||||
|
};
|
||||||
|
|
||||||
|
base_default_language_options.merge(§ion_default_language_options).unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[should_panic]
|
||||||
|
fn merge_with_conflict() {
|
||||||
|
let mut base_default_language_options = LanguageOptions {
|
||||||
|
title: Some("Site's title".to_string()),
|
||||||
|
description: Some("Duplicate site description".to_string()),
|
||||||
|
generate_feed: true,
|
||||||
|
feed_filename: "".to_string(),
|
||||||
|
taxonomies: vec![],
|
||||||
|
build_search_index: true,
|
||||||
|
search: search::Search::default(),
|
||||||
|
translations: HashMap::new(),
|
||||||
|
};
|
||||||
|
|
||||||
|
let section_default_language_options = LanguageOptions {
|
||||||
|
title: None,
|
||||||
|
description: Some("Site's description".to_string()),
|
||||||
|
generate_feed: false,
|
||||||
|
feed_filename: "Some feed_filename".to_string(),
|
||||||
|
taxonomies: vec![],
|
||||||
|
build_search_index: true,
|
||||||
|
search: search::Search::default(),
|
||||||
|
translations: HashMap::new(),
|
||||||
|
};
|
||||||
|
|
||||||
|
base_default_language_options
|
||||||
|
.merge(§ion_default_language_options)
|
||||||
|
.expect("This should lead to panic");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@ -130,8 +130,11 @@ impl Markdown {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
bail!("Highlight theme {} not available.\n\
|
bail!(
|
||||||
You can load custom themes by configuring `extra_syntaxes_and_themes` to include a list of folders containing '.tmTheme' files", self.highlight_theme)
|
"Highlight theme {} not available.\n\
|
||||||
|
You can load custom themes by configuring `extra_syntaxes_and_themes` to include a list of folders containing '.tmTheme' files",
|
||||||
|
self.highlight_theme
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -142,8 +145,11 @@ impl Markdown {
|
|||||||
// Check extra themes
|
// Check extra themes
|
||||||
if let Some(extra) = &*self.extra_theme_set {
|
if let Some(extra) = &*self.extra_theme_set {
|
||||||
if !extra.themes.contains_key(theme_name) {
|
if !extra.themes.contains_key(theme_name) {
|
||||||
bail!("Can't export highlight theme {}, as it does not exist.\n\
|
bail!(
|
||||||
Make sure it's spelled correctly, or your custom .tmTheme' is defined properly.", theme_name)
|
"Can't export highlight theme {}, as it does not exist.\n\
|
||||||
|
Make sure it's spelled correctly, or your custom .tmTheme' is defined properly.",
|
||||||
|
theme_name
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -127,7 +127,7 @@ impl Config {
|
|||||||
languages::validate_code(code)?;
|
languages::validate_code(code)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
config.add_default_language();
|
config.add_default_language()?;
|
||||||
config.slugify_taxonomies();
|
config.slugify_taxonomies();
|
||||||
|
|
||||||
if !config.ignored_content.is_empty() {
|
if !config.ignored_content.is_empty() {
|
||||||
@ -153,7 +153,7 @@ impl Config {
|
|||||||
|
|
||||||
pub fn default_for_test() -> Self {
|
pub fn default_for_test() -> Self {
|
||||||
let mut config = Config::default();
|
let mut config = Config::default();
|
||||||
config.add_default_language();
|
config.add_default_language().unwrap();
|
||||||
config.slugify_taxonomies();
|
config.slugify_taxonomies();
|
||||||
config
|
config
|
||||||
}
|
}
|
||||||
@ -206,26 +206,37 @@ impl Config {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Adds the default language to the list of languages if not present
|
/// Adds the default language to the list of languages if options for it are specified at base level of config.toml.
|
||||||
pub fn add_default_language(&mut self) {
|
/// If section for the same language also exists, the options at this section and base are merged and then adds it
|
||||||
|
/// to list.
|
||||||
|
pub fn add_default_language(&mut self) -> Result<()> {
|
||||||
// We automatically insert a language option for the default language *if* it isn't present
|
// We automatically insert a language option for the default language *if* it isn't present
|
||||||
// TODO: what to do if there is like an empty dict for the lang? merge it or use the language
|
// TODO: what to do if there is like an empty dict for the lang? merge it or use the language
|
||||||
// TODO: as source of truth?
|
// TODO: as source of truth?
|
||||||
if !self.languages.contains_key(&self.default_language) {
|
|
||||||
self.languages.insert(
|
let mut base_default_language_options = languages::LanguageOptions {
|
||||||
self.default_language.clone(),
|
title: self.title.clone(),
|
||||||
languages::LanguageOptions {
|
description: self.description.clone(),
|
||||||
title: self.title.clone(),
|
generate_feed: self.generate_feed,
|
||||||
description: self.description.clone(),
|
feed_filename: self.feed_filename.clone(),
|
||||||
generate_feed: self.generate_feed,
|
build_search_index: self.build_search_index,
|
||||||
feed_filename: self.feed_filename.clone(),
|
taxonomies: self.taxonomies.clone(),
|
||||||
build_search_index: self.build_search_index,
|
search: self.search.clone(),
|
||||||
taxonomies: self.taxonomies.clone(),
|
translations: self.translations.clone(),
|
||||||
search: self.search.clone(),
|
};
|
||||||
translations: self.translations.clone(),
|
|
||||||
},
|
if let Some(section_default_language_options) = self.languages.get(&self.default_language) {
|
||||||
);
|
if base_default_language_options != languages::LanguageOptions::default() {
|
||||||
|
println!("Warning: config.toml contains both default language specific information at base and under section `[languages.{}]`, \
|
||||||
|
which may cause merge conflicts. Please use only one to specify language specific information", self.default_language);
|
||||||
|
base_default_language_options.merge(section_default_language_options)?;
|
||||||
|
} else {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
self.languages.insert(self.default_language.clone(), base_default_language_options);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Merges the extra data from the theme with the config extra data
|
/// Merges the extra data from the theme with the config extra data
|
||||||
@ -390,6 +401,74 @@ mod tests {
|
|||||||
use super::*;
|
use super::*;
|
||||||
use utils::slugs::SlugifyStrategy;
|
use utils::slugs::SlugifyStrategy;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn can_add_default_language_with_data_only_at_base_section() {
|
||||||
|
let title_base = Some("Base section title".to_string());
|
||||||
|
let description_base = Some("Base section description".to_string());
|
||||||
|
|
||||||
|
let mut config = Config::default();
|
||||||
|
config.title = title_base.clone();
|
||||||
|
config.description = description_base.clone();
|
||||||
|
config.add_default_language().unwrap();
|
||||||
|
|
||||||
|
let default_language_options =
|
||||||
|
config.languages.get(&config.default_language).unwrap().clone();
|
||||||
|
assert_eq!(default_language_options.title, title_base);
|
||||||
|
assert_eq!(default_language_options.description, description_base);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn can_add_default_language_with_data_at_base_and_language_section() {
|
||||||
|
let title_base = Some("Base section title".to_string());
|
||||||
|
let description_lang_section = Some("Language section description".to_string());
|
||||||
|
|
||||||
|
let mut config = Config::default();
|
||||||
|
config.title = title_base.clone();
|
||||||
|
config.languages.insert(
|
||||||
|
config.default_language.clone(),
|
||||||
|
languages::LanguageOptions {
|
||||||
|
title: None,
|
||||||
|
description: description_lang_section.clone(),
|
||||||
|
generate_feed: true,
|
||||||
|
feed_filename: config.feed_filename.clone(),
|
||||||
|
taxonomies: config.taxonomies.clone(),
|
||||||
|
build_search_index: false,
|
||||||
|
search: search::Search::default(),
|
||||||
|
translations: config.translations.clone(),
|
||||||
|
},
|
||||||
|
);
|
||||||
|
config.add_default_language().unwrap();
|
||||||
|
|
||||||
|
let default_language_options =
|
||||||
|
config.languages.get(&config.default_language).unwrap().clone();
|
||||||
|
assert_eq!(default_language_options.title, title_base);
|
||||||
|
assert_eq!(default_language_options.description, description_lang_section);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn errors_when_same_field_present_at_base_and_language_section() {
|
||||||
|
let title_base = Some("Base section title".to_string());
|
||||||
|
let title_lang_section = Some("Language section title".to_string());
|
||||||
|
|
||||||
|
let mut config = Config::default();
|
||||||
|
config.title = title_base.clone();
|
||||||
|
config.languages.insert(
|
||||||
|
config.default_language.clone(),
|
||||||
|
languages::LanguageOptions {
|
||||||
|
title: title_lang_section.clone(),
|
||||||
|
description: None,
|
||||||
|
generate_feed: true,
|
||||||
|
feed_filename: config.feed_filename.clone(),
|
||||||
|
taxonomies: config.taxonomies.clone(),
|
||||||
|
build_search_index: false,
|
||||||
|
search: search::Search::default(),
|
||||||
|
translations: config.translations.clone(),
|
||||||
|
},
|
||||||
|
);
|
||||||
|
let result = config.add_default_language();
|
||||||
|
assert!(result.is_err());
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn can_import_valid_config() {
|
fn can_import_valid_config() {
|
||||||
let config = r#"
|
let config = r#"
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user