diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 6b284498..660fbf98 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -104,7 +104,6 @@ jobs: language: ${{ fromJSON(needs.find-translations.outputs.languages) }} env: MDBOOK_BOOK__LANGUAGE: ${{ matrix.language }} - MDBOOK_PREPROCESSOR__GETTEXT__PO_FILE: po/${{ matrix.language }}.po steps: - name: Checkout uses: actions/checkout@v3 diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index e7221520..814fc4cd 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -44,7 +44,6 @@ jobs: run: | for po_lang in ${{ env.LANGUAGES }}; do MDBOOK_BOOK__LANGUAGE=$po_lang \ - MDBOOK_PREPROCESSOR__GETTEXT__PO_FILE=po/$po_lang.po \ MDBOOK_OUTPUT__HTML__SITE_URL=/comprehensive-rust/$po_lang/ \ mdbook build -d book/$po_lang done diff --git a/Cargo.lock b/Cargo.lock index 8f2decde..06d2897f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -783,6 +783,7 @@ dependencies = [ "regex", "semver", "serde_json", + "toml", ] [[package]] diff --git a/README.md b/README.md index 238268e1..5eb4a9b5 100644 --- a/README.md +++ b/README.md @@ -22,13 +22,17 @@ trigger when going through the code samples. We hope to improve on this via ## Building -The course is built using [mdBook](https://github.com/rust-lang/mdBook) and its -[Svgbob plugin](https://github.com/boozook/mdbook-svgbob). Install both tools -with +The course is built using a few tools: +- [mdBook](https://github.com/rust-lang/mdBook) +- [Svgbob plugin](https://github.com/boozook/mdbook-svgbob) +- [i18n-helpers](TRANSLATIONS.md#i18n-helpers) + +Install these tools with ```shell $ cargo install mdbook $ cargo install mdbook-svgbob +$ cargo install --path i18n-helpers ``` Then run diff --git a/TRANSLATIONS.md b/TRANSLATIONS.md index 1b00c657..2648852c 100644 --- a/TRANSLATIONS.md +++ b/TRANSLATIONS.md @@ -95,11 +95,7 @@ output. To use the `po/xx.po` file for your output, run the following command: ```shell -$ MDBOOK_BOOK__LANGUAGE='xx' \ - MDBOOK_PREPROCESSOR__GETTEXT__PO_FILE='po/xx.po' \ - MDBOOK_PREPROCESSOR__GETTEXT__RENDERERS='["html"]' \ - MDBOOK_PREPROCESSOR__GETTEXT__BEFORE='["svgbob"]' \ - mdbook build -d book/xx +$ MDBOOK_BOOK__LANGUAGE=xx mdbook build -d book/xx ``` This will update the book's language to `xx`, it will make the `mdbook-gettext` @@ -109,11 +105,8 @@ it will redirect the output to `book/xx`. ## Serving a Translation Like normal, you can use `mdbook serve` to view your translation as you work on -it. You use the same command as with `mdbook build` above, but additionally -we'll tell `mdbook` to watch the `po/` directory for changes: +it. You use the same command as with `mdbook build` above: ```shell -$ MDBOOK_BOOK__LANGUAGE=xx \ - MDBOOK_PREPROCESSOR__GETTEXT__PO_FILE=po/xx.po \ - mdbook serve -d book/xx +$ MDBOOK_BOOK__LANGUAGE=xx mdbook serve -d book/xx ``` diff --git a/book.toml b/book.toml index 2c0852af..da99fda6 100644 --- a/book.toml +++ b/book.toml @@ -13,14 +13,14 @@ extra-watch-dirs = ["po"] [preprocessor.links] renderers = ["html"] -before = ["gettext"] + +[preprocessor.gettext] [preprocessor.index] renderers = ["html"] [preprocessor.svgbob] renderers = ["html"] -after = ["gettext"] class = "bob" # Enable this preprocessor to overlay a large red rectangle on the diff --git a/i18n-helpers/Cargo.toml b/i18n-helpers/Cargo.toml index adc75029..29118b25 100644 --- a/i18n-helpers/Cargo.toml +++ b/i18n-helpers/Cargo.toml @@ -12,3 +12,4 @@ polib = "0.1.0" regex = "1.7.0" semver = "1.0.16" serde_json = "1.0.91" +toml = "0.5.1" diff --git a/i18n-helpers/src/bin/mdbook-gettext.rs b/i18n-helpers/src/bin/mdbook-gettext.rs index 921b1a76..2325d674 100644 --- a/i18n-helpers/src/bin/mdbook-gettext.rs +++ b/i18n-helpers/src/bin/mdbook-gettext.rs @@ -17,9 +17,11 @@ //! This program works like `gettext`, meaning it will translate //! strings in your book. //! -//! The translations come from GNU Gettext `xx.po` files. You must set -//! preprocessor.gettext.po-file to the PO file to use. If unset, a -//! warning is issued while building the book. +//! The translations come from GNU Gettext `xx.po` files. The PO file is +//! is found under `po` directory based on the `book.language`. +//! For example, `book.langauge` is set to `ko`, then `po/ko.po` is used. +//! You can set `preprocessor.gettext.po-dir` to specify where to find PO +//! files. If the PO file is not found, you'll get the untranslated book. //! //! See `TRANSLATIONS.md` in the repository root for more information. @@ -32,8 +34,8 @@ use polib::catalog::Catalog; use polib::po_file; use semver::{Version, VersionReq}; use std::io; -use std::path::Path; use std::process; +use toml::Value; fn translate(text: &str, catalog: &Catalog) -> String { let mut output = String::with_capacity(text.len()); @@ -66,19 +68,30 @@ fn translate(text: &str, catalog: &Catalog) -> String { } fn translate_book(ctx: &PreprocessorContext, mut book: Book) -> anyhow::Result { + // no-op when the target language is not set + if ctx.config.book.language.is_none() { + return Ok(book); + } + + // the target language + let language = ctx.config.book.language.as_ref().unwrap(); + + // Find PO file for the target language let cfg = ctx .config .get_preprocessor("gettext") .ok_or_else(|| anyhow!("Could not read preprocessor.gettext configuration"))?; - let path = cfg - .get("po-file") - .ok_or_else(|| anyhow!("Missing preprocessor.gettext.po-file config value"))? - .as_str() - .ok_or_else(|| anyhow!("Expected a string for preprocessor.gettext.po-file"))?; - let catalog = po_file::parse(Path::new(path)) - .map_err(|err| anyhow!("{err}")) - .with_context(|| format!("Could not parse {path} as PO file"))?; + let po_dir = cfg.get("po-dir").and_then(Value::as_str).unwrap_or("po"); + let path = ctx.root.join(po_dir).join(format!("{language}.po")); + // no-op when PO file is missing + if !path.exists() { + return Ok(book); + } + + let catalog = po_file::parse(&path) + .map_err(|err| anyhow!("{err}")) + .with_context(|| format!("Could not parse {:?} as PO file", path))?; book.for_each_mut(|item| match item { BookItem::Chapter(ch) => { ch.content = translate(&ch.content, &catalog); @@ -115,8 +128,12 @@ fn preprocess() -> anyhow::Result<()> { fn main() -> anyhow::Result<()> { if std::env::args().len() == 3 { assert_eq!(std::env::args().nth(1).as_deref(), Some("supports")); - // Signal that we support all renderers. - process::exit(0); + if let Some("xgettext") = std::env::args().nth(2).as_deref() { + process::exit(1) + } else { + // Signal that we support all other renderers. + process::exit(0); + } } preprocess()