1515from argparse import ArgumentParser
1616from collections import Counter
1717import os
18- from re import match
18+ from dataclasses import dataclass
19+ from re import match ,search
1920from subprocess import call ,run
2021import sys
22+ from typing import Self
23+ from urllib .parse import unquote
2124
2225LANGUAGE = 'pl'
2326
@@ -91,29 +94,51 @@ def recreate_tx_config():
9194 )
9295
9396
97+ @dataclass
98+ class ResourceLanguageStatistics :
99+ name :str
100+ total_words :int
101+ translated_words :int
102+ total_strings :int
103+ translated_strings :int
104+
105+ @classmethod
106+ def from_api_v3_entry (cls ,data :dict )-> Self :
107+ return cls (
108+ name = search ('r:([^:]*)' ,data ['id' ]).group (1 ),
109+ total_words = data ['attributes' ]['total_words' ],
110+ translated_words = data ['attributes' ]['translated_words' ],
111+ total_strings = data ['attributes' ]['total_strings' ],
112+ translated_strings = data ['attributes' ]['translated_strings' ],
113+ )
114+
115+
94116def _get_resources ():
95117from requests import get
96118
97119resources = []
98- offset = 0
120+ cursor = None
99121if os .path .exists ('.tx/api-key' ):
100122with open ('.tx/api-key' )as f :
101123transifex_api_key = f .read ()
102124else :
103125transifex_api_key = os .getenv ('TX_TOKEN' )
104126while True :
105127response = get (
106- f'https://api.transifex.com/organizations/python-doc/projects/{ PROJECT_SLUG } /resources/' ,
107- params = {'language_code' :LANGUAGE ,'offset' :offset },
108- auth = ('api' ,transifex_api_key ),
128+ 'https://rest.api.transifex.com/resource_language_stats' ,
129+ params = {
130+ 'filter[project]' :f'o:python-doc:p:{ PROJECT_SLUG } ' ,'filter[language]' :f'l:{ LANGUAGE } '
131+ }| ({'page[cursor]' :cursor }if cursor else {}),
132+ headers = {'Authorization' :f'Bearer{ transifex_api_key } ' }
109133 )
110134response .raise_for_status ()
111- response_list = response .json ()
135+ response_json = response .json ()
136+ response_list = response_json ['data' ]
112137resources .extend (response_list )
113- if len ( response_list ) < 100 :
138+ if 'next' not in response_json [ 'links' ] :
114139break
115- offset += len ( response_list )
116- return resources
140+ cursor = unquote ( search ( 'page\[cursor]=([^&]*)' , response_json [ 'links' ][ 'next' ]). group ( 1 ) )
141+ return [ ResourceLanguageStatistics . from_api_v3_entry ( entry ) for entry in resources ]
117142
118143
119144def _get_number_of_translators ():
@@ -130,18 +155,18 @@ def _get_number_of_translators():
130155def recreate_readme ():
131156def language_switcher (entry ):
132157return (
133- entry [ ' name' ] .startswith ('bugs' )
134- or entry [ ' name' ] .startswith ('tutorial' )
135- or entry [ ' name' ] .startswith ('library--functions' )
158+ entry . name .startswith ('bugs' )
159+ or entry . name .startswith ('tutorial' )
160+ or entry . name .startswith ('library--functions' )
136161 )
137162
138163def average (averages ,weights ):
139164return sum ([a * w for a ,w in zip (averages ,weights )])/ sum (weights )
140165
141166resources = _get_resources ()
142167filtered = list (filter (language_switcher ,resources ))
143- average_list = [e [ 'stats' ][ 'translated' ][ 'percentage' ] for e in filtered ]
144- weights_list = [e [ 'wordcount' ] for e in filtered ]
168+ average_list = [e . translated_words / e . total_words for e in filtered ]
169+ weights_list = [e . total_words for e in filtered ]
145170
146171language_switcher_status = average (average_list ,weights = weights_list )* 100
147172number_of_translators = _get_number_of_translators ()