|
| 1 | +#!/usr/bin/env python |
| 2 | +# |
| 3 | +# This python file contains utility scripts to manage Python docs Polish translation. |
| 4 | +# It has to be run inside the python-docs-uk git root directory. |
| 5 | +# |
| 6 | +# Inspired by django-docs-translations script by claudep. |
| 7 | +# |
| 8 | +# The following commands are available: |
| 9 | +# |
| 10 | +# * fetch: fetch translations from transifex.com and strip source lines from the |
| 11 | +# files. |
| 12 | +# * recreate_readme: recreate readme to update translation progress. |
| 13 | +# * regenerate_tx_config: recreate configuration for all resources. |
| 14 | + |
| 15 | +from argparse import ArgumentParser |
| 16 | +from collections import Counter |
| 17 | +import os |
| 18 | +from re import match |
| 19 | +from subprocess import call, run |
| 20 | +import sys |
| 21 | + |
| 22 | +LANGUAGE = 'uk' |
| 23 | + |
| 24 | + |
| 25 | +def fetch(): |
| 26 | + """ |
| 27 | + Fetch translations from Transifex, remove source lines. |
| 28 | + """ |
| 29 | + if call("tx --version", shell=True) != 0: |
| 30 | + sys.stderr.write("The Transifex client app is required (pip install transifex-client).\n") |
| 31 | + exit(1) |
| 32 | + lang = LANGUAGE |
| 33 | + pull_returncode = call(f'tx pull -l {lang} --minimum-perc=1 --force --skip', shell=True) |
| 34 | + if pull_returncode != 0: |
| 35 | + exit(pull_returncode) |
| 36 | + for root, _, po_files in os.walk('../..'): |
| 37 | + for po_file in po_files: |
| 38 | + if not po_file.endswith(".po"): |
| 39 | + continue |
| 40 | + po_path = os.path.join(root, po_file) |
| 41 | + call(f'msgcat --no-location -o {po_path} {po_path}', shell=True) |
| 42 | + |
| 43 | + |
| 44 | +RESOURCE_NAME_MAP = {'glossary_': 'glossary'} |
| 45 | +TX_ORGANISATION = 'python-doc' |
| 46 | +TX_PROJECT = 'python-newest' |
| 47 | +GH_ORGANISATION = 'python' |
| 48 | + |
| 49 | +def recreate_tx_config(): |
| 50 | + """ |
| 51 | + Regenerate Transifex client config for all resources. |
| 52 | + """ |
| 53 | + resources = _get_resources() |
| 54 | + with open('.tx/config', 'w') as config: |
| 55 | + config.writelines(('[main]\n', 'host = https://www.transifex.com\n',)) |
| 56 | + for resource in resources: |
| 57 | + slug = resource['slug'] |
| 58 | + name = RESOURCE_NAME_MAP.get(slug, slug) |
| 59 | + if slug == '0': |
| 60 | + continue |
| 61 | + elif '--' in slug: |
| 62 | + directory, file_name = name.split('--') |
| 63 | + if match(r'\d+_\d+', file_name): |
| 64 | + file_name = file_name.replace('_', '.') |
| 65 | + config.writelines( |
| 66 | + ( |
| 67 | + '\n', |
| 68 | + f'[{TX_PROJECT}.{slug}]\n', |
| 69 | + f'trans.{LANGUAGE} = {directory}/{file_name}.po\n', |
| 70 | + 'type = PO\n', |
| 71 | + 'source_lang = en\n', |
| 72 | + ) |
| 73 | + ) |
| 74 | + else: |
| 75 | + config.writelines( |
| 76 | + ( |
| 77 | + '\n', |
| 78 | + f'[{TX_PROJECT}.{slug}]\n', |
| 79 | + f'trans.{LANGUAGE} = {name}.po\n', |
| 80 | + 'type = PO\n', |
| 81 | + 'source_lang = en\n', |
| 82 | + ) |
| 83 | + ) |
| 84 | + |
| 85 | + |
| 86 | +def _get_resources(): |
| 87 | + from requests import get |
| 88 | + |
| 89 | + resources = [] |
| 90 | + offset = 0 |
| 91 | + if os.path.exists('.tx/api-key'): |
| 92 | + with open('.tx/api-key') as f: |
| 93 | + transifex_api_key = f.read() |
| 94 | + else: |
| 95 | + transifex_api_key = os.getenv('TX_TOKEN') |
| 96 | + while True: |
| 97 | + response = get( |
| 98 | + f'https://api.transifex.com/organizations/{TX_ORGANISATION}/projects/{TX_PROJECT}/resources/', |
| 99 | + params={'language_code': LANGUAGE, 'offset': offset}, |
| 100 | + auth=('api', transifex_api_key), |
| 101 | + ) |
| 102 | + response.raise_for_status() |
| 103 | + response_list = response.json() |
| 104 | + resources.extend(response_list) |
| 105 | + if len(response_list) < 100: |
| 106 | + break |
| 107 | + offset += len(response_list) |
| 108 | + return resources |
| 109 | + |
| 110 | + |
| 111 | +def _get_unique_translators(): |
| 112 | + process = run( |
| 113 | + ['grep', '-ohP', r'(?<=^# )(.+)(?=, \d+$)', '-r', '.'], |
| 114 | + capture_output=True, |
| 115 | + text=True, |
| 116 | + ) |
| 117 | + translators = [match('(.*)( <.*>)?', t).group(1) for t in process.stdout.splitlines()] |
| 118 | + unique_translators = Counter(translators) |
| 119 | + return unique_translators |
| 120 | + |
| 121 | + |
| 122 | +def recreate_readme(): |
| 123 | + def language_switcher(entry): |
| 124 | + return ( |
| 125 | + entry['name'].startswith('bugs') |
| 126 | + or entry['name'].startswith('tutorial') |
| 127 | + or entry['name'].startswith('library--functions') |
| 128 | + ) |
| 129 | + |
| 130 | + def average(averages, weights): |
| 131 | + return sum([a * w for a, w in zip(averages, weights)]) / sum(weights) |
| 132 | + |
| 133 | + resources = _get_resources() |
| 134 | + filtered = list(filter(language_switcher, resources)) |
| 135 | + average_list = [e['stats']['translated']['percentage'] for e in filtered] |
| 136 | + weights_list = [e['wordcount'] for e in filtered] |
| 137 | + |
| 138 | + language_switcher_status = average(average_list, weights=weights_list) * 100 |
| 139 | + unique_translators = _get_unique_translators() |
| 140 | + number_of_translators = len(unique_translators) |
| 141 | + |
| 142 | + with open('README.md', 'w') as file: |
| 143 | + file.write( |
| 144 | + f'''\ |
| 145 | +Український переклад документації Python |
| 146 | +======================================== |
| 147 | + |
| 148 | + |
| 149 | + |
| 150 | + |
| 151 | +
|
| 152 | +Якщо ви знайшли помилку або маєте пропозицію, |
| 153 | +[додати issue](https://github.com/{GH_ORGANISATION}/python-docs-uk/issues) у цьому проекті або запропонуйте зміни: |
| 154 | +
|
| 155 | +* Зареєструйтесь на платформі [Transifex](https://www.transifex.com/) |
| 156 | +* Перейдіть на сторінку [документації Python](https://www.transifex.com/{TX_ORGANISATION}/{TX_PROJECT}/). |
| 157 | +* Натисніть кнопку „Join Team”, оберіть українську (uk) мову та натисніть „Join” щоб приєднатися до команди. |
| 158 | +* Приєднавшись до команди, виберіть ресурс, що хочете виправити/оновити. |
| 159 | +
|
| 160 | +Додаткову інформацію про використання Transifex дивіться [в документації](https://docs.transifex.com/getting-started-1/translators). |
| 161 | +
|
| 162 | +**Прогрес перекладу** |
| 163 | +
|
| 164 | + |
| 165 | +
|
| 166 | +Українська мова з’явиться в меню вибору мови docs.python.org, [коли будуть повністю перекладені](https://www.python.org/dev/peps/pep-0545/#add-translation-to-the-language-switcher): |
| 167 | +* `bugs`, |
| 168 | +* всі ресурси в каталозі `tutorial`, |
| 169 | +* `library/functions`. |
| 170 | +
|
| 171 | +**Як переглянути останню збірку документації?** |
| 172 | +
|
| 173 | +Завантажте останню створену документацію зі списку артефактів в останній дії GitHub (вкладка Actions). |
| 174 | +Переклади завантажуються з Transifex до цього репозиторію приблизно кожні півгодини. |
| 175 | +Документація на python.org оновлюється приблизно раз на день. |
| 176 | +
|
| 177 | +**Канали зв'язку** |
| 178 | +
|
| 179 | +* [Telegram-чат перекладачів](https://t.me/+dXwqHZ0KPKYyNDc6) |
| 180 | +* [Python translations working group](https://mail.python.org/mailman3/lists/translation.python.org/) |
| 181 | +* [Python Documentation Special Interest Group](https://www.python.org/community/sigs/current/doc-sig/) |
| 182 | +
|
| 183 | +**Ліцензія** |
| 184 | +
|
| 185 | +Запрошуючи вас до спільного створення проекту на платформі Transifex, ми пропонуємо договір на передачу ваших перекладів |
| 186 | +Python Software Foundation [по ліцензії CC0](https://creativecommons.org/publicdomain/zero/1.0/deed.uk). |
| 187 | +Натомість ви побачите, що ви є перекладачем тієї частини, яку ви переклали. |
| 188 | +Ви висловлюєте свою згоду з цією угодою, надаючи свою роботу для включення в документацію. |
| 189 | +
|
| 190 | +**Оновлення локального перекладу** |
| 191 | +
|
| 192 | +* `.github/scripts/manage_translation.py recreate_tx_config` |
| 193 | +* `.github/scripts/manage_translation.py fetch` |
| 194 | +* `.github/scripts/manage_translation.py recreate_readme` |
| 195 | +
|
| 196 | +**Подяка** |
| 197 | +* Maciej Olko - Polish team |
| 198 | +* Julien Palard - French team |
| 199 | +* Tomo Cocoa - Japanese team |
| 200 | +
|
| 201 | +**Внесок спільноти** |
| 202 | +
|
| 203 | +| Перекладач | Кількість документів | |
| 204 | +|:----------------|:--------------------:| |
| 205 | +''' |
| 206 | + ) |
| 207 | + |
| 208 | + file.writelines( |
| 209 | + (f'|{t}|{c}|\n' for (t, c) in unique_translators.most_common()) |
| 210 | + ) |
| 211 | + |
| 212 | + |
| 213 | +if __name__ == "__main__": |
| 214 | + RUNNABLE_SCRIPTS = ('fetch', 'recreate_tx_config', 'recreate_readme') |
| 215 | + |
| 216 | + parser = ArgumentParser() |
| 217 | + parser.add_argument('cmd', nargs=1, choices=RUNNABLE_SCRIPTS) |
| 218 | + options = parser.parse_args() |
| 219 | + |
| 220 | + eval(options.cmd[0])() |
0 commit comments