Skip to content

Commit 5b8e263

Browse files
Create transifex-util.py
1 parent febc67d commit 5b8e263

1 file changed

Lines changed: 131 additions & 0 deletions

File tree

Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,131 @@
1+
#!/usr/bin/env python
2+
#
3+
# This python file contains utility functions to manage a Python docs translation
4+
# with Transifex.
5+
#
6+
# This file is maintained at: https://github.com/python-docs-translations/transifex-automations/blob/main/sample-workflows/transifex-util.py
7+
8+
import configparser
9+
from argparse import ArgumentParser
10+
import os
11+
from contextlib import chdir
12+
from pathlib import Path
13+
from subprocess import call
14+
import sys
15+
from tempfile import TemporaryDirectory
16+
17+
18+
def fetch():
19+
"""
20+
Fetch translations from Transifex, remove source lines.
21+
"""
22+
if (code := call("tx --version", shell=True)) != 0:
23+
sys.stderr.write("The Transifex client app is required.\n")
24+
exit(code)
25+
lang = LANGUAGE
26+
if PULL_OPTIONS:
27+
_call(f"tx pull -l {lang} --force {PULL_OPTIONS}") # XXX Do we pull everything?
28+
else:
29+
_call(f"tx pull -l {lang} --force")
30+
for file in Path().rglob("*.po"):
31+
_call(f"msgcat --no-location -o {file} {file}")
32+
33+
34+
def _call(command: str):
35+
if (return_code := call(command, shell=True)) != 0:
36+
exit(return_code)
37+
38+
39+
def recreate_tx_config():
40+
"""
41+
Regenerate Transifex client config for all resources.
42+
"""
43+
with TemporaryDirectory() as directory:
44+
with chdir(directory):
45+
_clone_cpython_repo(VERSION)
46+
_build_gettext()
47+
with chdir(Path(directory) / "cpython/Doc/build"):
48+
_create_txconfig()
49+
_update_txconfig_resources()
50+
with open(".tx/config", "r") as file:
51+
contents = file.read()
52+
contents = contents.replace("./<lang>/LC_MESSAGES/", "")
53+
54+
os.makedirs(".tx", exist_ok=True)
55+
with open(".tx/config", "w") as file:
56+
file.write(contents)
57+
58+
59+
def delete_obsolete_files():
60+
files_to_delete = list(_get_files_to_delete())
61+
if not files_to_delete:
62+
return
63+
else:
64+
for file in files_to_delete:
65+
print(f"Removing {file}")
66+
os.remove(file)
67+
_call(f'git rm --quiet "{file}"')
68+
69+
70+
def _get_files_to_delete():
71+
with open(".tx/config") as config_file:
72+
config = config_file.read()
73+
for file in Path().rglob("*.po"):
74+
if os.fsdecode(file) not in config:
75+
yield os.fsdecode(file)
76+
77+
78+
def _clone_cpython_repo(version: str):
79+
_call(
80+
f"git clone -b {version} --single-branch https://github.com/python/cpython.git --depth 1"
81+
)
82+
83+
84+
def _build_gettext():
85+
_call("make -C cpython/Doc/ gettext")
86+
87+
88+
def _create_txconfig():
89+
_call("sphinx-intl create-txconfig")
90+
91+
92+
def _update_txconfig_resources():
93+
_call(
94+
f"sphinx-intl update-txconfig-resources --transifex-organization-name python-doc "
95+
f"--transifex-project-name {PROJECT_SLUG} --locale-dir . --pot-dir gettext"
96+
)
97+
98+
99+
def _get_tx_token() -> str:
100+
if os.path.exists(".tx/api-key"):
101+
with open(".tx/api-key") as f:
102+
return f.read()
103+
104+
config = configparser.ConfigParser()
105+
config.read(os.path.expanduser("~/.transifexrc"))
106+
try:
107+
return config["https://www.transifex.com"]["token"]
108+
except KeyError:
109+
pass
110+
111+
return os.getenv("TX_TOKEN", "")
112+
113+
114+
if __name__ == "__main__":
115+
RUNNABLE_SCRIPTS = ("fetch", "recreate_tx_config", "delete_obsolete_files")
116+
117+
parser = ArgumentParser()
118+
parser.add_argument("cmd", choices=RUNNABLE_SCRIPTS)
119+
parser.add_argument("--language", required=True)
120+
parser.add_argument("--project-slug", required=True)
121+
parser.add_argument("--version", required=True)
122+
parser.add_argument("--pull-options", required=False)
123+
124+
options = parser.parse_args()
125+
126+
LANGUAGE = options.language
127+
PROJECT_SLUG = options.project_slug
128+
VERSION = options.version
129+
PULL_OPTIONS = options.pull_options
130+
131+
globals()[options.cmd]()

0 commit comments

Comments
 (0)