Skip to content

Commit bd49b56

Browse files
committed
Add --po-dir to be used by build_docs(), add generate_templates() target
1 parent ed63a34 commit bd49b56

File tree

1 file changed

+103
-30
lines changed

1 file changed

+103
-30
lines changed

scripts/manage_translations.py

Lines changed: 103 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,17 @@
66
import contextlib
77
import logging
88
import os
9+
import re
910
import shutil
1011
import subprocess
1112
import sys
1213
from pathlib import Path
1314
from typing import Optional
1415

16+
from sphinx_intl.transifex import create_txconfig, update_txconfig_resources
17+
1518
ROOTDIR = Path(__file__).resolve().parent.parent
16-
COMMANDS = ["build"]
19+
COMMANDS = ["build", 'generate_templates']
1720

1821
logging.basicConfig(level=logging.INFO, format="%(asctime)s - %(levelname)s - %(message)s")
1922
logger = logging.getLogger(__name__)
@@ -25,81 +28,151 @@ def configure_parser() -> argparse.ArgumentParser:
2528
parser.add_argument("command", choices=COMMANDS, help="The command to execute")
2629
parser.add_argument("-l", "--language", help="Language for the translated documentation")
2730
parser.add_argument("-v", "--python-version", help="Python version to be used")
28-
parser.add_argument("-L", "--logs-dir", default=ROOTDIR / "logs", type=Path, help="Directory for logs")
29-
parser.add_argument("-c", "--cpython-path", default=ROOTDIR / "cpython", type=Path, help="Path to the CPython repository")
31+
parser.add_argument("-L", "--logs-dir", default=ROOTDIR / "logs", type=Path, help="Directory for logs (default: 'logs' in root directory")
32+
parser.add_argument("-c", "--cpython-path", default=ROOTDIR / "cpython", type=Path, help="Path to the CPython repository (default: 'cpython' in root directory")
33+
parser.add_argument("-p", "--po-dir", type=Path, help="Path to the language team repository containing PO files (default: CPYTHON_PATH/Doc/locales/LANGUAGE/LC_MESSAGES")
34+
parser.add_argument('-t', '--tx-project', help="Name of the Transifex project under python-doc Transifex organization")
3035
return parser
3136

3237

33-
def get_value(env_var_name: str, arg_value: Optional[str]) -> str:
38+
def get_value(arg_value: Optional[str], arg_name: str, env_var_name: str) -> str:
3439
"""Return a CLI argument or environment variable value."""
3540
value = arg_value or os.getenv(env_var_name)
3641
if not value:
37-
logger.error(f"The environment variable {env_var_name} is not defined, and no value was provided.")
42+
logger.error(f"'{arg_name}' not provided and the environment variable {env_var_name} is not set.")
3843
sys.exit(1)
3944
return value
4045

4146

42-
def get_minor_version(version: str) -> int:
43-
"""Return the minor version number from a version string (e.g., '3.13')."""
44-
try:
45-
return int(version.split(".")[1])
46-
except (IndexError, ValueError) as e:
47-
logger.error(f"Invalid version format '{version}': {e}")
47+
def validate_cpython_path(cpython_path: Path) -> None:
48+
if not (cpython_path / "Doc" / "conf.py").exists():
49+
logger.error(f"Missing conf.py in {cpython_path}. Invalid CPython directory.")
4850
sys.exit(1)
4951

5052

51-
def build_docs(language: str, version: str, logs_dir: Path, cpython_path: Path) -> None:
52-
"""Build the documentation using Sphinx."""
53-
minor_version = get_minor_version(version)
54-
warning_log = logs_dir / "sphinxwarnings.txt"
53+
def validate_po_dir(po_dir: Path) -> None:
54+
if not po_dir.exists() or not list(po_dir.glob("*.po")):
55+
logger.error(f"Invalid locale directory '{po_dir}'. No PO files found.")
56+
sys.exit(1)
57+
5558

56-
sphinx_opts = f"-E -D language={language} --keep-going -w {warning_log}"
57-
if minor_version < 12:
58-
sphinx_opts += "-D gettext_compact=False"
59+
def validate_tx_config(tx_config: str) -> None:
60+
if not re.match(r"python-(newest|\d+)", tx_config):
61+
logger.error(f"Invalid Transifex project name: {tx_config}")
62+
sys.exit(1)
63+
64+
65+
# contextlib implemented chdir since Python 3.11
66+
@contextlib.contextmanager
67+
def chdir(path: Path):
68+
"""Temporarily change the working directory."""
69+
original_dir = Path.cwd()
70+
logger.info(path)
71+
os.chdir(path)
72+
try:
73+
yield
74+
finally:
75+
os.chdir(original_dir)
76+
77+
78+
def build_docs(language: str, version: str, po_dir: Path, logs_dir: Path, cpython_path: Path) -> None:
79+
"""Build the documentation using Sphinx."""
80+
warning_log = logs_dir / "sphinx_warnings_build_docs.txt"
81+
sphinx_opts = ["-E", "-Dgettext_compact=0", f"-Dlanguage={language}", "--keep-going", "-w", f"{warning_log}"]
82+
locale_dirs = cpython_path / "Doc/locales"
83+
target_locale_dir = cpython_path / "Doc/locales" / language / "LC_MESSAGES"
84+
85+
# TODO Fix symlinking when po_dir is not equal to target_locale_dir
86+
#if not po_dir.relative_to(locale_dirs) and
87+
# not target_locale_dir.readlink() == po_dir:
88+
# if target_locale_dir.is_symlink():
89+
# target_locale_dir.unlink() # remove only if it is a symlink
90+
# if not target_locale_dir.exists() and not target_locale_dir.is_symlink():
91+
# (locale_dirs / language).mkdir(parents=True, exist_ok=True)
92+
# os.symlink(po_dir, target_locale_dir)
5993

6094
try:
6195
logger.info(f"Building documentation for {language}, Python {version}.")
6296
subprocess.run([
63-
"make", "-C", str(cpython_path / "Doc"), "html", f"SPHINXOPTS={sphinx_opts}"
97+
"make", "-C", str(cpython_path / "Doc"), "html", f"SPHINXOPTS={' '.join(sphinx_opts)}"
6498
], check=True)
6599

66100
if warning_log.exists() and not warning_log.stat().st_size:
67101
warning_log.unlink()
68-
logger.info("Empty warning log file removed.")
102+
logger.info("Removed empty warning log file.")
69103

70104
except subprocess.CalledProcessError as e:
71105
logger.error(f"Make command failed: {e}")
72106
sys.exit(1)
73107

74108

75-
def validate_paths(cpython_path: Path) -> None:
76-
"""Validate necessary paths for handling documentation."""
77-
if not (cpython_path / "Doc" / "conf.py").exists():
78-
logger.error(f"Missing conf.py in {cpython_path}. Invalid CPython directory.")
109+
def generate_templates(logs_dir: Path, cpython_path: Path, tx_project: str) -> None:
110+
"""Generate translation template files (a.k.a. POT files) with Sphinx"""
111+
warning_log = logs_dir / "sphinx_warnings_generate_templates.txt"
112+
all_sphinx_opts = [
113+
"-E", "-b", "gettext", "-Dgettext_compact=0", "--keep-going",
114+
"-w", f"{warning_log}", "-d", "build/.doctrees-gettext", ".", "build/gettext"
115+
]
116+
117+
try:
118+
logger.info("Generating template files for Python docs.")
119+
subprocess.run([
120+
"make", "-C", str(cpython_path / "Doc"), "build", f"ALLSPHINXOPTS={' '.join(all_sphinx_opts)}"
121+
], check=True)
122+
123+
if warning_log.exists() and not warning_log.stat().st_size:
124+
warning_log.unlink()
125+
logger.info("Removed empty warning log file.")
126+
127+
except subprocess.CalledProcessError as e:
128+
logger.error(f"Make command failed: {e}")
79129
sys.exit(1)
80130

131+
with chdir(cpython_path / "Doc/locales"):
132+
logger.info("Updating Transifex's resources configuration file")
133+
Path(".tx/config").unlink(missing_ok=True)
134+
create_txconfig()
135+
update_txconfig_resources(
136+
transifex_organization_name='python-doc',
137+
transifex_project_name=tx_project,
138+
locale_dir=Path("."),
139+
pot_dir=Path("../build/gettext")
140+
)
141+
81142

82143
def main() -> None:
83144
parser = configure_parser()
84145
args = parser.parse_args()
85146

86-
language = get_value("PYDOC_LANGUAGE", args.language)
87-
version = get_value("PYDOC_VERSION", args.python_version)
88-
logs_dir = Path(get_value("PYDOC_LOGS", str(args.logs_dir)))
147+
# Set and require variable depending on the command issued by the user
89148
cpython_path = args.cpython_path
149+
logs_dir = Path(get_value(str(args.logs_dir), "--logs-dir", "PYDOC_LOGS"))
90150

91-
validate_paths(cpython_path)
151+
if args.command == "generate_templates":
152+
tx_project = get_value(args.tx_project, "--tx-project", "PYDOC_TX_PROJECT")
92153

93154
if args.command == "build":
155+
language = get_value(args.language, "--language", "PYDOC_LANGUAGE")
156+
version = get_value(args.python_version, "--python-version", "PYDOC_VERSION")
157+
po_dir = args.po_dir.absolute() or cpython_path / f"Doc/locales/{language}/LC_MESSAGES"
158+
159+
if args.command in ["build", "generate_templates"]:
94160
if not shutil.which("make"):
95161
logger.error("'make' not found. Please install it.")
96162
sys.exit(1)
97163

98164
logs_dir.mkdir(exist_ok=True)
99165
logger.info(f"Logs will be stored in: {logs_dir}")
100166

101-
build_docs(language, version, logs_dir, cpython_path)
102-
logger.info("Documentation build completed successfully.")
167+
if args.command == "build":
168+
validate_cpython_path(cpython_path)
169+
validate_po_dir(po_dir)
170+
build_docs(language, version, po_dir, logs_dir, cpython_path)
171+
logger.info("Documentation build completed successfully.")
172+
elif args.command == "generate_templates":
173+
validate_cpython_path(cpython_path)
174+
validate_tx_config(tx_project)
175+
generate_templates(logs_dir, cpython_path, tx_project)
103176

104177

105178
if __name__ == "__main__":

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy