99import xml .dom .minidom as minidom # nosec
1010from dataclasses import dataclass
1111from functools import cache as memoize
12- from typing import Any
13- from typing import Optional
12+ from typing import Any , Optional
13+ from xml . dom . minicompat import EmptyNodeList
1414
1515import requests
1616from lib import stage
@@ -103,7 +103,7 @@ def __init__(
103103 Language ("zh_TW" ),
104104)
105105
106- _BAIDU_LANGUAGES = ("jbo" , )
106+ _BAIDU_LANGUAGES = ("jbo" ,)
107107_IGNORE_LANGUAGES = ("pr" , "nl_BE" , "sr_Latn" )
108108
109109_LOCK = multiprocessing .Lock ()
@@ -113,11 +113,14 @@ def __init__(
113113def lupdate () -> str :
114114 """Return the path to the lupdate executable."""
115115 # If "lupdate" is in PATH, it will be used.
116- if (subprocess .run ( # nosec
117- ["which" , "lupdate" ],
116+ if (
117+ subprocess .run ( # nosec
118+ ["which" , "lupdate" ],
118119 stdout = subprocess .PIPE ,
119120 stderr = subprocess .PIPE ,
120- ).returncode == 0 ):
121+ ).returncode
122+ == 0
123+ ):
121124 return "lupdate"
122125 # Check if we can find it in the Nix store.
123126 for path in glob .glob ("/nix/store/*-qttools-*/bin/lupdate" ):
@@ -163,13 +166,14 @@ def _fix_translation(lang: Language, source: str, text: str) -> str:
163166 return text
164167 # These are %1, %2, etc. which are used for string formatting in Qt.
165168 # They only go up to 3 at the moment, but we'll be safe and go up to 6.
166- for i in tuple (range (1 , 6 )) + ("n" , ):
169+ for i in tuple (range (1 , 6 )) + ("n" ,):
167170 if f"%{ i } " in source :
168171 text = text .replace (f"% { i } " , f"%{ i } " )
169172 if f"%{ i } " not in text :
170173 raise ValueError (
171174 f"Missing %{ i } in { lang .weblate_code } translation of "
172- f"'{ source } ': '{ text } '" )
175+ f"'{ source } ': '{ text } '"
176+ )
173177 if "%" in source :
174178 text = text .replace ("%%" , "%" )
175179 if source .startswith (" " ) and not text .startswith (" " ):
@@ -196,20 +200,27 @@ def _baidu_call_translate(lang: Language, text: str) -> str:
196200 },
197201 )
198202 response .raise_for_status ()
199- events = (json .loads (line .removeprefix ("data: " ))
200- for line in response .text .split ("\n " )
201- if line .startswith ("data: " ))
203+ events = (
204+ json .loads (line .removeprefix ("data: " ))
205+ for line in response .text .split ("\n " )
206+ if line .startswith ("data: " )
207+ )
202208 translations = (
203- para ["dst" ] for event in events
209+ para ["dst" ]
210+ for event in events
204211 if event ["data" ]["event" ] == "Translating" and event ["data" ]["list" ]
205- for para in event ["data" ]["list" ])
212+ for para in event ["data" ]["list" ]
213+ )
206214 return "\n " .join (translations )
207215
208216
209217def _validate_translation (source : str , translation : str ) -> bool :
210- for i in tuple (range (1 , 6 )) + ("n" , ):
211- if (f"%{ i } " in source and f"% { i } " not in translation
212- and f"%{ i } " not in translation ):
218+ for i in tuple (range (1 , 6 )) + ("n" ,):
219+ if (
220+ f"%{ i } " in source
221+ and f"% { i } " not in translation
222+ and f"%{ i } " not in translation
223+ ):
213224 return False
214225 return True
215226
@@ -283,11 +294,13 @@ def _translate(lang: Language, current: int, total: int, text: str) -> str:
283294 )
284295 response .raise_for_status ()
285296 return _fix_translation (
286- lang , text , _reflow (text , "" .join ([x [0 ] for x in response .json ()[0 ]])))
297+ lang , text , _reflow (text , "" .join ([x [0 ] for x in response .json ()[0 ]]))
298+ )
287299
288300
289- def _need_translation (lang : Language , source : str ,
290- message : minidom .Element ) -> list [Any ]:
301+ def _need_translation (
302+ lang : Language , source : str , message : minidom .Element
303+ ) -> list [Any ]:
291304 translation = message .getElementsByTagName ("translation" )
292305 if not translation :
293306 return []
@@ -304,9 +317,11 @@ def _need_translation(lang: Language, source: str,
304317 translated .data = "LTR"
305318 return []
306319 translatorcomment = message .getElementsByTagName ("translatorcomment" )
307- if (translatorcomment
308- and isinstance (translatorcomment [0 ].firstChild , minidom .Text ) and
309- translatorcomment [0 ].firstChild .data != _AUTOMATED_TRANSLATION ):
320+ if (
321+ translatorcomment
322+ and isinstance (translatorcomment [0 ].firstChild , minidom .Text )
323+ and translatorcomment [0 ].firstChild .data != _AUTOMATED_TRANSLATION
324+ ):
310325 # Skip messages with translator comments. These are probably
311326 # not meant to be translated.
312327 return []
@@ -374,9 +389,12 @@ def _translate_todo_list(
374389 if not translated :
375390 continue
376391 # Clear the translation node of any existing text.
377- translation .childNodes .clear ()
392+ if not isinstance (translation .childNodes , EmptyNodeList ):
393+ translation .childNodes .clear ()
378394 # Add the translation to the translation node.
379- translation .appendChild (dom .createTextNode (translated ))
395+ translation .appendChild ( # type: ignore[misc]
396+ dom .createTextNode (translated )
397+ )
380398 # Add a <translatorcomment> node to the message to indicate
381399 # that the translation was automated.
382400 if not message .getElementsByTagName ("translatorcomment" ):
0 commit comments