From 4b0f3e7fa485975c9c83104aa52841e2589a7ece Mon Sep 17 00:00:00 2001 From: Denis Rouzaud Date: Mon, 19 Feb 2024 15:13:13 +0100 Subject: [PATCH] translate MkDocs navigation content on Transifex --- .github/workflows/doc.yml | 21 +++-- docs/requirements-dev.txt | 2 + docs/scripts/mkdocs_tx.py | 133 +++++++++++++++++++++++++++++++ docs/scripts/mkdocs_tx_commit.sh | 31 +++++++ docs/scripts/transifex_utils.py | 11 +++ 5 files changed, 193 insertions(+), 5 deletions(-) create mode 100644 docs/requirements-dev.txt create mode 100755 docs/scripts/mkdocs_tx.py create mode 100755 docs/scripts/mkdocs_tx_commit.sh diff --git a/.github/workflows/doc.yml b/.github/workflows/doc.yml index 360b2e77b..b600f1aa5 100644 --- a/.github/workflows/doc.yml +++ b/.github/workflows/doc.yml @@ -8,15 +8,13 @@ on: - '.github/workflows/doc.yml' push: branches: + - docx # TODO: remove - master paths: - 'docs/**' - '.github/workflows/doc.yml' workflow_dispatch: # useful for testing tx pushes - workflow_call: -permissions: - contents: write defaults: run: @@ -37,13 +35,18 @@ jobs: python-version: '3.10' - name: Install Python requirements - run: pip install -r requirements.txt + run: | + pip install -r requirements.txt + pip install -r requirements-dev.txt - name: Install Transifex client run: | curl -OL https://github.com/transifex/cli/releases/download/v1.6.10/tx-linux-amd64.tar.gz tar -xvzf tx-linux-amd64.tar.gz + - name: Extract translatable content from mkdocs.yml config + run: ./scripts/mkdocs_tx.py create_source + - name: Configure Transifex run: scripts/transifex_utils.py env: @@ -56,13 +59,21 @@ jobs: TX_TOKEN: ${{ secrets.TX_TOKEN }} - name: Pull translations from Transifex - if: ${{ github.event_name == 'push' || github.event.pull_request.head.repo.full_name == 'opengisch/QgisModelBaker' && github.actor != 'dependabot[bot]' }} + if: ${{ github.event_name == 'push' || github.event_name == 'workflow_dispatch' || github.event.pull_request.head.repo.full_name == 'opengisch/QgisModelBaker' && github.actor != 'dependabot[bot]' }} run: | ./tx pull --translations --all --minimum-perc 10 ./tx status env: TX_TOKEN: ${{ secrets.TX_TOKEN }} + - name: Translate Mkdocs config + if: ${{ github.event_name == 'push' || github.event_name == 'workflow_dispatch' || github.event.pull_request.head.repo.full_name == 'opengisch/QgisModelBaker' && github.actor != 'dependabot[bot]' }} + run: | + ./scripts/mkdocs_tx.py -s fr update_config + ./scripts/mkdocs_tx_commit.sh + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + - name: Build documentation run: mkdocs build diff --git a/docs/requirements-dev.txt b/docs/requirements-dev.txt new file mode 100644 index 000000000..f3d7632ed --- /dev/null +++ b/docs/requirements-dev.txt @@ -0,0 +1,2 @@ +ruamel.yaml==0.18.6 +pre-commit==3.6.2 diff --git a/docs/scripts/mkdocs_tx.py b/docs/scripts/mkdocs_tx.py new file mode 100755 index 000000000..6712514ab --- /dev/null +++ b/docs/scripts/mkdocs_tx.py @@ -0,0 +1,133 @@ +#!/usr/bin/env python + +import argparse +import copy + +from ruamel.yaml import YAML + +# This scripts helps with translatable content from mkdocs.yml +# It provides commands: +# * to create the YAML translatable file +# * to update the mkdocs.yml with the translated content + + +def read_config(file_path: str): + yaml = YAML(typ="rt") + yaml.preserve_quotes = True + with open(file_path) as f: + return yaml.load(f) + + +def create_translation_source(config_path, source_path): + config = read_config(config_path) + + nav_config = [] + for _entry in config["nav"]: + nav_config.append({v: k for k, v in _entry.items()}) + + tx_cfg = {"nav": nav_config} + + try: + tx_cfg["theme"] = {"palette": []} + for palette in config["theme"]["palette"]: + tx_cfg["theme"]["palette"].append( + {"toggle": {"name": palette["toggle"]["name"]}} + ) + except KeyError: + print("No theme/palette/toggle/name to translate") + + with open(source_path, "w") as f: + yaml = YAML() + yaml.dump(tx_cfg, f) + + +def update_config(config_path, source_path, source_language): + config = read_config(config_path) + + nav_config = {} + for _entry in config["nav"]: + for title, page in _entry.items(): + nav_config[page] = title + + found = False + for plugin in config["plugins"]: + if type(plugin) != str and "i18n" in plugin: + found = True + for lang in plugin["i18n"]["languages"]: + ltx = lang["locale"] + print(f"language found: '{ltx}'") + + if ltx == source_language: + print("skipping source language") + continue + + tx_file = f'{source_path.removesuffix(".yml")}.{ltx}.yml' + with open(tx_file) as f: + yaml = YAML() + tx = yaml.load(f) + + for nav_entry in tx["nav"]: + for page, title in nav_entry.items(): + source_language_tile = nav_config[page] + if title: + lang["nav_translations"][source_language_tile] = title + + try: + lang["palette"] = copy.deepcopy(config["theme"]["palette"]) + i = 0 + for palette in tx["theme"]["palette"]: + lang["palette"][i]["toggle"]["name"] = palette["toggle"][ + "name" + ] + i += 1 + except KeyError: + print("No theme/palette/toggle/name to translate") + + assert found + + with open(config_path, "w") as f: + yaml = YAML() + yaml.indent(mapping=2, sequence=4, offset=2) + yaml.dump(config, f) + + +if __name__ == "__main__": + parser = argparse.ArgumentParser() + parser.add_argument( + "-c", "--config_path", default="mkdocs.yml", help="mkdocs.yml complete path" + ) + parser.add_argument( + "-s", "--source_language", default="en", help="source language of the config" + ) + parser.add_argument( + "-t", + "--translation_file_path", + default="mkdocs_tx.yml", + help="Translation file to create and translate", + ) + + subparsers = parser.add_subparsers(title="command", dest="command") + + # create the parser for the create_source command + parser_source = subparsers.add_parser( + "create_source", help="Creates the source file to be translated" + ) + + # create the parser for the update_config command + parser_update = subparsers.add_parser( + "update_config", + help="Updates the mkdocs.yml config file from the downloaded translated files", + ) + + args = parser.parse_args() + + if args.command == "create_source": + create_translation_source(args.config_path, args.translation_file_path) + + elif args.command == "update_config": + update_config( + args.config_path, args.translation_file_path, args.source_language + ) + + else: + raise ValueError diff --git a/docs/scripts/mkdocs_tx_commit.sh b/docs/scripts/mkdocs_tx_commit.sh new file mode 100755 index 000000000..88f78f773 --- /dev/null +++ b/docs/scripts/mkdocs_tx_commit.sh @@ -0,0 +1,31 @@ +#!/usr/bin/env bash + +set -e + +pre-commit install +pre-commit run --files mkdocs.yml || true + +if [[ $(git diff --exit-code mkdocs.yml) ]]; then + git config --global user.email "github-actions[bot]@users.noreply.github.com" + git config --global user.name "github-actions[bot]" + + echo "detected changes in mkdocs.yml" + if [[ ${GITHUB_EVENT_NAME} == "pull_request" ]]; then + # on PR push to the same branch + gh pr checkout $(echo "${GITHUB_REF_NAME}" | cut -d/ -f1) + git add mkdocs.yml + git commit -m "Update mkdocs.yml translation" --no-verify + git push + else + # on push/workflow_dispatch create a pull request + git checkout ${GITHUB_REF_NAME} + BRANCH="update-mkdocs-tx-$RANDOM" + git checkout -b ${BRANCH} + git add mkdocs.yml + git commit -m "Update mkdocs.yml translation" --no-verify + git push -u origin $BRANCH + gh pr create -B ${GITHUB_REF_NAME} -H ${BRANCH} --title 'Update mkdocs translations' --body 'run from mkdocs_tx' + fi +else + echo "no change mkdocs.yml" +fi diff --git a/docs/scripts/transifex_utils.py b/docs/scripts/transifex_utils.py index ca148f773..c0f5259b0 100755 --- a/docs/scripts/transifex_utils.py +++ b/docs/scripts/transifex_utils.py @@ -26,6 +26,17 @@ def create_transifex_config(): f.write("[main]\n") f.write("host = https://www.transifex.com\n\n") + if os.path.isfile(f"{root}/mkdocs_tx.yml"): + print(f"Found mkdocs config translated content") + f.write(f"[o:{TX_ORGANIZATION}:p:{TX_PROJECT}:r:site_navigation]\n") + f.write("resource_name = site navigation\n") + f.write("file_filter = mkdocs_tx..yml\n") + f.write(f"source_file = mkdocs_tx.yml\n") + f.write(f"source_lang = {TX_SOURCE_LANG}\n") + f.write(f"type = YAML_GENERIC\n\n") + else: + print("No translation of mkdocs config found") + for file in glob.iglob(current_dir + "/../docs/**/*.md", recursive=True): # Get relative path of file relative_path = os.path.relpath(file, start=root)