diff --git a/Cargo.lock b/Cargo.lock index f606ef73..0c5fdeee 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -444,8 +444,10 @@ dependencies = [ "pulldown-cmark-to-cmark", "regex", "semver", + "serde", "serde_json", "tempfile", + "toml", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index 898c91d6..1a61ad44 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -17,7 +17,9 @@ pulldown-cmark = { version = "0.9.2", default-features = false } pulldown-cmark-to-cmark = "10.0.4" regex = "1.9.4" semver = "1.0.16" +serde = "1.0.130" serde_json = "1.0.91" +toml = "0.5.8" [dev-dependencies] pretty_assertions = "1.3.0" diff --git a/src/main.rs b/src/main.rs new file mode 100644 index 00000000..77d85241 --- /dev/null +++ b/src/main.rs @@ -0,0 +1,80 @@ +use mdbook::renderer::RenderContext; +use serde::Deserialize; +use std::collections::BTreeMap; +use std::io; + +#[derive(Deserialize)] +struct I18nConfiguration { + languages: BTreeMap, + default_language: Option, + + #[serde(default)] + translate_all_languages: bool, + #[serde(default)] + move_translations_to_html_directory: bool, +} + +fn main() { + let mut stdin = io::stdin(); + + // Get the configs + let ctx = RenderContext::from_json(&mut stdin).unwrap(); + let i18n_config: I18nConfiguration = ctx + .config + .get_deserialized_opt("output.i18n-helpers") + .unwrap() + .unwrap(); + + if !i18n_config.translate_all_languages { + return; + } + + let mut mdbook = mdbook::MDBook::load(&ctx.root).expect("Failed to load book"); + // Overwrite with current values from stdin. + mdbook.book = ctx.book.clone(); + mdbook.config = ctx.config.clone(); + mdbook.root = ctx.root.clone(); + + let book_config = mdbook + .config + .get_mut("output.i18n-helpers") + .expect("No output.i18n-helpers config in book.toml"); + // Set translate_all_languages to false for nested builds to prevent infinite recursion. + book_config + .as_table_mut() + .expect("output.i18n-helpers config in book.toml is not a table") + .insert( + String::from("translate_all_languages"), + toml::Value::Boolean(false), + ); + + let output_directory = ctx.destination.parent().unwrap(); + let default_language = &i18n_config.default_language; + + for language in i18n_config.languages.keys() { + // Skip current language and default language. + if Some(language) == ctx.config.book.language.as_ref() { + continue; + } + if let Some(default_language) = default_language { + if default_language == language { + continue; + } + } + let translation_path = output_directory.join(language); + + // Book doesn't implement clone, so we just mutate in place. + mdbook.config.book.language = Some(language.clone()); + mdbook.config.book.multilingual = true; + mdbook.config.build.build_dir = translation_path; + mdbook.build().unwrap_or_else(|_| panic!("Failed to build translation for language: {}", + language)); + if i18n_config.move_translations_to_html_directory { + std::fs::rename( + output_directory.join(language).join("html"), + output_directory.join("html").join(language), + ) + .unwrap_or_else(|_| panic!("Failed to move translation for language {language} to output directory")); + } + } +}