From bb7a18410f8c8da7089c86fbe2d97235941fe811 Mon Sep 17 00:00:00 2001 From: Rafael Fontenelle Date: Mon, 3 Nov 2025 07:53:39 -0300 Subject: [PATCH 1/9] Add generate_txconfig.py --- scripts/generate_txconfig.py | 115 +++++++++++++++++++++++++++++++++++ 1 file changed, 115 insertions(+) create mode 100755 scripts/generate_txconfig.py diff --git a/scripts/generate_txconfig.py b/scripts/generate_txconfig.py new file mode 100755 index 000000000..b1fee12bf --- /dev/null +++ b/scripts/generate_txconfig.py @@ -0,0 +1,115 @@ +#!/usr/bin/env python3 +""" +Generate the .tx/config file based on the existing projects +in Python docs Transifex project. Takes an project slug as +positional argument, e.g. python-newest or python-313 +""" + +import argparse +import re +import subprocess +import sys +from pathlib import Path + +def reset_tx_config(txconfig: Path): + """Create or reset the .tx/config file with basic header.""" + txconfig.parent.mkdir(exist_ok=True) + txconfig.write_text("[main]\nhost = https://www.transifex.com\n", encoding="utf-8") + print("Initialized .tx/config.") + + +def populate_resources_from_remote(config_file: Path, tx_project: str): + """Add the remote resources from the Transifex project to .tx/config.""" + result = subprocess.run([ + "tx", "--config", str(config_file), "add", "remote", + "--file-filter", "/.", + f"https://app.transifex.com/python-doc/{tx_project}/" + ], check=True) + if result.returncode != 0: + print("Failed to add the resources from remote:") + print(result.stderr.strip()) + sys.exit(result.returncode) + print("Added remote resources to Transifex.") + + +def patch_config(txconfig: Path): + """Patch .tx/config to fixing PO filenames to match the expected.""" + content = txconfig.read_text(encoding="utf-8").splitlines() + new_lines = [] + + text_to_replace = { + "2_": "2.", + "3_": "3.", + "glossary_": "glossary", + "collections_": "collections.", + "compression_": "compression.", + "concurrent_": "concurrent.", + "curses_": "curses.", + "email_": "email.", + "html_": "html.", + "http_": "http.", + "importlib_resources_": "importlib.resources.", + "importlib_": "importlib.", + "logging_": "logging.", + "multiprocessing_": "multiprocessing.", + "os_": "os.", + "string_": "string.", + "sys_monitoring": "sys.monitoring", + "tkinter_": "tkinter.", + "unittest_": "unittest.", + "urllib_": "urllib.", + "xml_dom_": "xml.dom.", + "xml_etree_": "xml.etree.", + "xmlrpc_": "xmlrpc.", + "xml_sax_": "xml.sax.", + "xml_": "xml." + } + + for line in content: + if line.startswith(("source_file", "source_lang")): + continue + + if line.startswith("file_filter"): + line = line.replace("/", "") + line = line.replace("--", "/") + + for pattern, replacement in text_to_replace.items(): + if pattern in line: + line = line.replace(pattern, replacement) + break + + new_lines.append(line) + + text = "\n".join(new_lines) + + txconfig.write_text(text + "\n", encoding="utf-8") + print("Updated .tx/config with character substitutions") + + +def parse_args(): + parser = argparse.ArgumentParser(description=__doc__) + parser.add_argument( + "--root-path", + "-p", + default=Path("."), + help="Path to the translation files, and also the .tx/config" + ) + parser.add_argument( + "tx_project", + help="Name of the Transifex project to query resources from (e.g. python-newest or python-313)" + ) + return parser.parse_args() + + +def main(): + args = parse_args() + TX_CONFIG = Path(".tx/config") + if args.root_path: + TX_CONFIG = args.root_path / TX_CONFIG + reset_tx_config(TX_CONFIG) + populate_resources_from_remote(TX_CONFIG, args.tx_project) + patch_config(TX_CONFIG) + + +if __name__ == "__main__": + main() From b0b931194d5e318008fae900636fe50f8d4508a2 Mon Sep 17 00:00:00 2001 From: Rafael Fontenelle Date: Mon, 3 Nov 2025 12:44:34 -0300 Subject: [PATCH 2/9] Move TEXT_TO_REPLACE outside function, move parse_args first --- scripts/generate_txconfig.py | 101 ++++++++++++++++++----------------- 1 file changed, 51 insertions(+), 50 deletions(-) diff --git a/scripts/generate_txconfig.py b/scripts/generate_txconfig.py index b1fee12bf..945f23afb 100755 --- a/scripts/generate_txconfig.py +++ b/scripts/generate_txconfig.py @@ -11,6 +11,51 @@ import sys from pathlib import Path +# Replaces required to fix the default values set by 'tx add remote' command. +# Add or remove +TEXT_TO_REPLACE = { + "2_": "2.", + "3_": "3.", + "glossary_": "glossary", + "collections_": "collections.", + "compression_": "compression.", + "concurrent_": "concurrent.", + "curses_": "curses.", + "email_": "email.", + "html_": "html.", + "http_": "http.", + "importlib_resources_": "importlib.resources.", + "importlib_": "importlib.", + "logging_": "logging.", + "multiprocessing_": "multiprocessing.", + "os_": "os.", + "string_": "string.", + "sys_monitoring": "sys.monitoring", + "tkinter_": "tkinter.", + "unittest_": "unittest.", + "urllib_": "urllib.", + "xml_dom_": "xml.dom.", + "xml_etree_": "xml.etree.", + "xmlrpc_": "xmlrpc.", + "xml_sax_": "xml.sax.", + "xml_": "xml." +} + +def parse_args(): + parser = argparse.ArgumentParser(description=__doc__) + parser.add_argument( + "--root-path", + "-p", + default=Path("."), + help="Path to the translation files, and also the .tx/config (defaults to current directory)" + ) + parser.add_argument( + "tx_project", + help="Slug of the Transifex project to query resources from" + ) + return parser.parse_args() + + def reset_tx_config(txconfig: Path): """Create or reset the .tx/config file with basic header.""" txconfig.parent.mkdir(exist_ok=True) @@ -37,34 +82,6 @@ def patch_config(txconfig: Path): content = txconfig.read_text(encoding="utf-8").splitlines() new_lines = [] - text_to_replace = { - "2_": "2.", - "3_": "3.", - "glossary_": "glossary", - "collections_": "collections.", - "compression_": "compression.", - "concurrent_": "concurrent.", - "curses_": "curses.", - "email_": "email.", - "html_": "html.", - "http_": "http.", - "importlib_resources_": "importlib.resources.", - "importlib_": "importlib.", - "logging_": "logging.", - "multiprocessing_": "multiprocessing.", - "os_": "os.", - "string_": "string.", - "sys_monitoring": "sys.monitoring", - "tkinter_": "tkinter.", - "unittest_": "unittest.", - "urllib_": "urllib.", - "xml_dom_": "xml.dom.", - "xml_etree_": "xml.etree.", - "xmlrpc_": "xmlrpc.", - "xml_sax_": "xml.sax.", - "xml_": "xml." - } - for line in content: if line.startswith(("source_file", "source_lang")): continue @@ -73,7 +90,7 @@ def patch_config(txconfig: Path): line = line.replace("/", "") line = line.replace("--", "/") - for pattern, replacement in text_to_replace.items(): + for pattern, replacement in TEXT_TO_REPLACE.items(): if pattern in line: line = line.replace(pattern, replacement) break @@ -85,30 +102,14 @@ def patch_config(txconfig: Path): txconfig.write_text(text + "\n", encoding="utf-8") print("Updated .tx/config with character substitutions") - -def parse_args(): - parser = argparse.ArgumentParser(description=__doc__) - parser.add_argument( - "--root-path", - "-p", - default=Path("."), - help="Path to the translation files, and also the .tx/config" - ) - parser.add_argument( - "tx_project", - help="Name of the Transifex project to query resources from (e.g. python-newest or python-313)" - ) - return parser.parse_args() - - def main(): args = parse_args() - TX_CONFIG = Path(".tx/config") + config_path = Path(".tx/config") if args.root_path: - TX_CONFIG = args.root_path / TX_CONFIG - reset_tx_config(TX_CONFIG) - populate_resources_from_remote(TX_CONFIG, args.tx_project) - patch_config(TX_CONFIG) + config_path = args.root_path / config_path + reset_tx_config(config_path) + populate_resources_from_remote(config_path, args.tx_project) + patch_config(config_path) if __name__ == "__main__": From 4e910c70532bae40ca594c68f20519c3ce69e9d8 Mon Sep 17 00:00:00 2001 From: Rafael Fontenelle Date: Tue, 4 Nov 2025 20:32:05 -0300 Subject: [PATCH 3/9] Drop cpython checkout and change language dir --- .github/workflows/sync.yml | 43 ++++++++++-------------------------- scripts/commit.sh | 6 ++++- scripts/pull_translations.sh | 6 ++++- 3 files changed, 22 insertions(+), 33 deletions(-) diff --git a/.github/workflows/sync.yml b/.github/workflows/sync.yml index b428fc10a..d7f91355e 100644 --- a/.github/workflows/sync.yml +++ b/.github/workflows/sync.yml @@ -32,41 +32,22 @@ jobs: - name: Check out this repository uses: actions/checkout@v5 - - name: Checkout CPython ${{ env.PYDOC_VERSION }} - uses: actions/checkout@v5 - with: - repository: 'python/cpython' - ref: ${{ env.PYDOC_VERSION }} - path: cpython - - name: Set language dir variable run: - echo "LANGUAGE_DIR=cpython/Doc/locales/${{ env.PYDOC_LANGUAGE }}/LC_MESSAGES" >> $GITHUB_ENV + echo "PYDOC_LANG_DIR=${{ env.PYDOC_VERSION }}" >> $GITHUB_ENV - name: Checkout this repository ${{ env.PYDOC_VERSION }} uses: actions/checkout@v5 with: ref: ${{ env.PYDOC_VERSION }} - path: ${{ env.LANGUAGE_DIR }} + path: ${{ env.PYDOC_LANG_DIR }} - uses: actions/setup-python@v6 with: python-version: ${{ inputs.version }} allow-prereleases: true cache: 'pip' - cache-dependency-path: | - requirements.txt - cpython/Doc/requirements.txt - - - name: Check for Transifex API Token availability - id: secret-check - # perform secret check & put boolean result as an output - shell: bash - run: | - available=false - [[ "${{ secrets.TX_TOKEN }}" != '' ]] && available=true - echo "available=$available" >> $GITHUB_OUTPUT - echo "available=$available" + cache-dependency-path: requirements.txt # 2- Install dependencies @@ -81,19 +62,19 @@ jobs: - name: Install Python dependencies run: | pip install -r requirements.txt - make -C cpython/Doc venv # 3- Pull translations - - name: Generate template files and Transifex config file - run: ./scripts/generate_templates.sh + - name: Generate updated .tx/config + if: ${{ contains(fromJSON('["schedule", "workflow_dispatch"]'), github.event_name) }} + run: python scripts/generate_txconfig.py -p ./${{ env.PYDOC_LANG_DIR }} ${{ env.PYDOC_TX_PROJECT }} - name: Pull translations from Transifex id: pull if: ${{ contains(fromJSON('["schedule", "workflow_dispatch"]'), github.event_name) }} run: | # Clean up obsolete files - find ./${{ env.LANGUAGE_DIR }} -name '*.po' -exec rm {} \; + find ./${{ env.PYDOC_LANG_DIR }} -name '*.po' -exec rm {} \; ./scripts/pull_translations.sh env: TX_TOKEN: ${{ secrets.TX_TOKEN }} @@ -103,26 +84,26 @@ jobs: run: | newer_branch=${PYDOC_VERSION%%.*}.$((${PYDOC_VERSION##*.}+1)) git clone --depth 1 --single-branch --branch $newer_branch https://github.com/python/python-docs-pt-br ${newer_branch}-dir - pomerge --from ./${newer_branch}-dir/{**/,}*.po --to ./${{ env.LANGUAGE_DIR }}/{**/,}*.po + pomerge --from ./${newer_branch}-dir/{**/,}*.po --to ./${{ env.PYDOC_LANG_DIR }}/{**/,}*.po rm -rf ./${newer_branch}-dir - name: powrap if: steps.pull.outcome == 'success' run: | - cd ./${{ env.LANGUAGE_DIR }} + cd ./${{ env.PYDOC_LANG_DIR }} powrap *.po **/*.po - name: Update statistics if: always() run: | ./scripts/stats.py - git -C ./${{ env.LANGUAGE_DIR }} diff stats.json + git -C ./${{ env.PYDOC_LANG_DIR }} diff stats.json - name: Update potodo.md if: always() run: | ./scripts/potodo.sh - git diff ./${{ env.LANGUAGE_DIR }}/potodo.md + git -C ./${{ env.PYDOC_LANG_DIR }} diff potodo.md # 4- Commit and push translations @@ -132,7 +113,7 @@ jobs: - name: Push if: ${{ contains(fromJSON('["schedule", "workflow_dispatch"]'), github.event_name) }} run: | - cd ./${{ env.LANGUAGE_DIR }} + cd ./${{ env.PYDOC_LANG_DIR }} git push diff --git a/scripts/commit.sh b/scripts/commit.sh index 06f265534..99f18bdd3 100755 --- a/scripts/commit.sh +++ b/scripts/commit.sh @@ -5,8 +5,12 @@ set -eu +test -n ${PYDOC_LANGUAGE+x} + rootdir=$(realpath $(dirname $0)) -cd $rootdir/../cpython/Doc/locales/${PYDOC_LANGUAGE}/LC_MESSAGES +language_dir="${PYDOC_LANG_DIR:-$rootdir/../cpython/Doc/locales/${PYDOC_LANGUAGE}/LC_MESSAGES}" + +cd "$language_dir" extra_files=".tx/config stats.json potodo.md" diff --git a/scripts/pull_translations.sh b/scripts/pull_translations.sh index d1fd34b0c..ebd4fa09d 100755 --- a/scripts/pull_translations.sh +++ b/scripts/pull_translations.sh @@ -20,8 +20,12 @@ set -xeu test -n ${PYDOC_TX_PROJECT+x} +test -n ${PYDOC_LANGUAGE+x} -cd "$(dirname $0)/../cpython/Doc/locales/${PYDOC_LANGUAGE}/LC_MESSAGES/" +rootdir=$(realpath $(dirname $0)) +language_dir="${PYDOC_LANG_DIR:-$rootdir/../cpython/Doc/locales/${PYDOC_LANGUAGE}/LC_MESSAGES}" + +cd "$language_dir" # If a PO file is provided as input, convert it into Transifex resource # and add it be pulled (instead of pulling all translations files). From d2e46f33db6ccca06c099c9e862abf96288c7730 Mon Sep 17 00:00:00 2001 From: Rafael Fontenelle Date: Tue, 4 Nov 2025 20:39:30 -0300 Subject: [PATCH 4/9] Make environment variable available --- .github/workflows/sync.yml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/.github/workflows/sync.yml b/.github/workflows/sync.yml index d7f91355e..d187462bc 100644 --- a/.github/workflows/sync.yml +++ b/.github/workflows/sync.yml @@ -98,17 +98,23 @@ jobs: run: | ./scripts/stats.py git -C ./${{ env.PYDOC_LANG_DIR }} diff stats.json + env: + PYDOC_LANG_DIR: ${{ env.PYDOC_LANG_DIR }} - name: Update potodo.md if: always() run: | ./scripts/potodo.sh git -C ./${{ env.PYDOC_LANG_DIR }} diff potodo.md + env: + PYDOC_LANG_DIR: ${{ env.PYDOC_LANG_DIR }} # 4- Commit and push translations - name: Commit run: ./scripts/commit.sh + env: + PYDOC_LANG_DIR: ${{ env.PYDOC_LANG_DIR }} - name: Push if: ${{ contains(fromJSON('["schedule", "workflow_dispatch"]'), github.event_name) }} From 028dee764e3d1286ec7e26b7359875929ea53f81 Mon Sep 17 00:00:00 2001 From: Rafael Fontenelle Date: Tue, 4 Nov 2025 20:48:08 -0300 Subject: [PATCH 5/9] Handle new path in potodo.sh --- scripts/commit.sh | 4 ++-- scripts/potodo.sh | 3 ++- scripts/pull_translations.sh | 4 ++-- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/scripts/commit.sh b/scripts/commit.sh index 99f18bdd3..2081b163f 100755 --- a/scripts/commit.sh +++ b/scripts/commit.sh @@ -7,8 +7,8 @@ set -eu test -n ${PYDOC_LANGUAGE+x} -rootdir=$(realpath $(dirname $0)) -language_dir="${PYDOC_LANG_DIR:-$rootdir/../cpython/Doc/locales/${PYDOC_LANGUAGE}/LC_MESSAGES}" +rootdir=$(realpath $(dirname $0)/..) +language_dir="${PYDOC_LANG_DIR:-$rootdir/cpython/Doc/locales/${PYDOC_LANGUAGE}/LC_MESSAGES}" cd "$language_dir" diff --git a/scripts/potodo.sh b/scripts/potodo.sh index 0d7e1e2c2..6b343e0da 100755 --- a/scripts/potodo.sh +++ b/scripts/potodo.sh @@ -10,8 +10,9 @@ test -n ${PYDOC_VERSION+x} test -n ${PYDOC_LANGUAGE+x} rootdir=$(realpath $(dirname $0)/..) +language_dir="${PYDOC_LANG_DIR:-$rootdir/cpython/Doc/locales/${PYDOC_LANGUAGE}/LC_MESSAGES}" -cd "$rootdir"/cpython/Doc/locales/${PYDOC_LANGUAGE}/LC_MESSAGES +cd "$language_dir" potodo --no-cache > potodo.md diff --git a/scripts/pull_translations.sh b/scripts/pull_translations.sh index ebd4fa09d..a85d79b69 100755 --- a/scripts/pull_translations.sh +++ b/scripts/pull_translations.sh @@ -22,8 +22,8 @@ set -xeu test -n ${PYDOC_TX_PROJECT+x} test -n ${PYDOC_LANGUAGE+x} -rootdir=$(realpath $(dirname $0)) -language_dir="${PYDOC_LANG_DIR:-$rootdir/../cpython/Doc/locales/${PYDOC_LANGUAGE}/LC_MESSAGES}" +rootdir=$(realpath $(dirname $0)/..) +language_dir="${PYDOC_LANG_DIR:-$rootdir/cpython/Doc/locales/${PYDOC_LANGUAGE}/LC_MESSAGES}" cd "$language_dir" From 27625412236487a3508fe0770fefe60ac7639646 Mon Sep 17 00:00:00 2001 From: Rafael Fontenelle Date: Tue, 4 Nov 2025 20:57:15 -0300 Subject: [PATCH 6/9] Fix script dir in commit.sh --- scripts/commit.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/commit.sh b/scripts/commit.sh index 2081b163f..a5c5d742d 100755 --- a/scripts/commit.sh +++ b/scripts/commit.sh @@ -48,5 +48,5 @@ set -u # Commit only if there is any cached file if ! git diff-index --cached --quiet HEAD; then git add -v $extra_files - git commit -vm "$($rootdir/generate_commit_msg.py)" + git commit -vm "$($rootdir/scripts/generate_commit_msg.py)" fi From 7e19c403129253ff8913d49b2231f8f585c9771c Mon Sep 17 00:00:00 2001 From: Rafael Fontenelle Date: Tue, 4 Nov 2025 21:10:17 -0300 Subject: [PATCH 7/9] Handle lang_dir in stats.py --- scripts/stats.py | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/scripts/stats.py b/scripts/stats.py index 81fe1aed5..37a3528aa 100755 --- a/scripts/stats.py +++ b/scripts/stats.py @@ -17,11 +17,16 @@ def main() -> None: """Main function to generate translation stats.""" - language = os.environ.get("PYDOC_LANGUAGE") - if not language: - raise ValueError("Environment variable PYDOC_LANGUAGE is not set.") - pofiles_path = Path(f"cpython/Doc/locales/{language}/LC_MESSAGES") + lang_dir = os.environ.get("PYDOC_LANG_DIR") + if lang_dir: + pofiles_path = lang_dir + else: + language = os.environ.get("PYDOC_LANGUAGE") + if not language: + raise ValueError("Environment variable PYDOC_LANGUAGE is not set.") + pofiles_path = Path(f"cpython/Doc/locales/{language}/LC_MESSAGES") + if not pofiles_path.exists(): raise FileNotFoundError(f"Path does not exist: {pofiles_path}") From 52fefb8d9f103170aa0fc45f2cb7f7af95a310a1 Mon Sep 17 00:00:00 2001 From: Rafael Fontenelle Date: Tue, 4 Nov 2025 21:15:59 -0300 Subject: [PATCH 8/9] Use Path to str --- scripts/stats.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/stats.py b/scripts/stats.py index 37a3528aa..ace2ced0b 100755 --- a/scripts/stats.py +++ b/scripts/stats.py @@ -20,7 +20,7 @@ def main() -> None: lang_dir = os.environ.get("PYDOC_LANG_DIR") if lang_dir: - pofiles_path = lang_dir + pofiles_path = Path(lang_dir) else: language = os.environ.get("PYDOC_LANGUAGE") if not language: From 78db6b8833a94b05fbac4ee737c74ea304cb870a Mon Sep 17 00:00:00 2001 From: Rafael Fontenelle Date: Tue, 4 Nov 2025 21:31:34 -0300 Subject: [PATCH 9/9] black --- scripts/generate_txconfig.py | 35 ++++++++++++++++++++++------------- scripts/stats.py | 8 ++++---- 2 files changed, 26 insertions(+), 17 deletions(-) diff --git a/scripts/generate_txconfig.py b/scripts/generate_txconfig.py index 945f23afb..727f9b5a4 100755 --- a/scripts/generate_txconfig.py +++ b/scripts/generate_txconfig.py @@ -12,7 +12,7 @@ from pathlib import Path # Replaces required to fix the default values set by 'tx add remote' command. -# Add or remove +# Add or remove TEXT_TO_REPLACE = { "2_": "2.", "3_": "3.", @@ -38,20 +38,20 @@ "xml_etree_": "xml.etree.", "xmlrpc_": "xmlrpc.", "xml_sax_": "xml.sax.", - "xml_": "xml." + "xml_": "xml.", } + def parse_args(): parser = argparse.ArgumentParser(description=__doc__) parser.add_argument( "--root-path", "-p", default=Path("."), - help="Path to the translation files, and also the .tx/config (defaults to current directory)" + help="Path to the translation files, and also the .tx/config (defaults to current directory)", ) parser.add_argument( - "tx_project", - help="Slug of the Transifex project to query resources from" + "tx_project", help="Slug of the Transifex project to query resources from" ) return parser.parse_args() @@ -65,11 +65,19 @@ def reset_tx_config(txconfig: Path): def populate_resources_from_remote(config_file: Path, tx_project: str): """Add the remote resources from the Transifex project to .tx/config.""" - result = subprocess.run([ - "tx", "--config", str(config_file), "add", "remote", - "--file-filter", "/.", - f"https://app.transifex.com/python-doc/{tx_project}/" - ], check=True) + result = subprocess.run( + [ + "tx", + "--config", + str(config_file), + "add", + "remote", + "--file-filter", + "/.", + f"https://app.transifex.com/python-doc/{tx_project}/", + ], + check=True, + ) if result.returncode != 0: print("Failed to add the resources from remote:") print(result.stderr.strip()) @@ -91,9 +99,9 @@ def patch_config(txconfig: Path): line = line.replace("--", "/") for pattern, replacement in TEXT_TO_REPLACE.items(): - if pattern in line: - line = line.replace(pattern, replacement) - break + if pattern in line: + line = line.replace(pattern, replacement) + break new_lines.append(line) @@ -102,6 +110,7 @@ def patch_config(txconfig: Path): txconfig.write_text(text + "\n", encoding="utf-8") print("Updated .tx/config with character substitutions") + def main(): args = parse_args() config_path = Path(".tx/config") diff --git a/scripts/stats.py b/scripts/stats.py index ace2ced0b..4dde51b18 100755 --- a/scripts/stats.py +++ b/scripts/stats.py @@ -22,10 +22,10 @@ def main() -> None: if lang_dir: pofiles_path = Path(lang_dir) else: - language = os.environ.get("PYDOC_LANGUAGE") - if not language: - raise ValueError("Environment variable PYDOC_LANGUAGE is not set.") - pofiles_path = Path(f"cpython/Doc/locales/{language}/LC_MESSAGES") + language = os.environ.get("PYDOC_LANGUAGE") + if not language: + raise ValueError("Environment variable PYDOC_LANGUAGE is not set.") + pofiles_path = Path(f"cpython/Doc/locales/{language}/LC_MESSAGES") if not pofiles_path.exists(): raise FileNotFoundError(f"Path does not exist: {pofiles_path}")