ScriptCollection 4.2.55__py3-none-any.whl → 4.2.57__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -3,7 +3,6 @@ import json
3
3
  import binascii
4
4
  import filecmp
5
5
  import hashlib
6
- import logging
7
6
  import multiprocessing
8
7
  import time
9
8
  from io import BytesIO
@@ -37,7 +36,7 @@ from .ProgramRunnerBase import ProgramRunnerBase
37
36
  from .ProgramRunnerPopen import ProgramRunnerPopen
38
37
  from .SCLog import SCLog, LogLevel
39
38
 
40
- version = "4.2.55"
39
+ version = "4.2.57"
41
40
  __version__ = version
42
41
 
43
42
  class VSCodeWorkspaceShellTask:
@@ -2880,7 +2879,7 @@ OCR-content:
2880
2879
  lines=program_result[1].split("\n")[1:]
2881
2880
  for line in lines:
2882
2881
  splitted=[item for item in line.split(' ') if GeneralUtilities.string_has_content(item)]
2883
- result.append(splitted[1])
2882
+ result.append(splitted[1].replace("\n","").replace("\r","").strip())
2884
2883
  return result
2885
2884
 
2886
2885
  @GeneralUtilities.check_arguments
@@ -3123,11 +3122,99 @@ OCR-content:
3123
3122
 
3124
3123
  #sync existing files
3125
3124
  self.__sync_xlf2_files(base_file_xml, language_files_with_content)
3126
-
3125
+
3127
3126
  @GeneralUtilities.check_arguments
3128
- def translate_messages_in_folder(self,folder:str,base_language:str, api_server:str):
3129
- pass#TODO for each file in folder: call self.translate(...)
3130
-
3127
+ def translate_xlf_files_in_folder(self, folder: str, base_language: str, libre_translate_api_server: str):
3128
+ """Translates all .xlf files directly in the given folder (non-recursive)."""
3129
+ pattern = re.compile(r'^.+\.[a-z]{2,3}\.xlf$')
3130
+ for filename in os.listdir(folder):
3131
+ if not pattern.match(filename):
3132
+ continue
3133
+ file_path = os.path.join(folder, filename)
3134
+ self.translate_xlf_file(file_path, base_language, libre_translate_api_server)
3135
+
3131
3136
  @GeneralUtilities.check_arguments
3132
- def translate(self,content:str, source_language:str, target_language:str,api_server:str)->str:
3133
- pass#TODO call libretranslate-api
3137
+ def translate_xlf_file(self, file: str, base_language: str, libre_translate_api_server: str):
3138
+ """
3139
+ Translates all segments with state='initial' in a XLIFF 2.0 file.
3140
+ The target language is extracted from the filename (e.g. 'messages.es.xlf' -> 'es').
3141
+ """
3142
+ ns_uri = "urn:oasis:names:tc:xliff:document:2.0"
3143
+ ns = {"xliff": ns_uri}
3144
+
3145
+ filename = os.path.basename(file)
3146
+ parts = filename.split(".")
3147
+ if len(parts) < 3:
3148
+ raise ValueError(f"Cannot extract language from filename: {filename}")
3149
+ target_language = parts[-2]
3150
+
3151
+ tree = ET.parse(file)
3152
+ root = tree.getroot()
3153
+
3154
+ for segment in root.findall(".//xliff:segment[@state='initial']", ns):
3155
+ source_el = segment.find("xliff:source", ns)
3156
+ if source_el is None or not source_el.text:
3157
+ continue
3158
+
3159
+ translated_text = self.translate(source_el.text, base_language, target_language, libre_translate_api_server)
3160
+
3161
+ target_el = segment.find("xliff:target", ns)
3162
+ if target_el is None:
3163
+ target_el = ET.SubElement(segment, f"{{{ns_uri}}}target")
3164
+
3165
+ target_el.text = translated_text
3166
+ segment.set("state", "translated")
3167
+
3168
+ ET.register_namespace("", ns_uri)
3169
+ xml_bytes = ET.tostring(root, encoding="utf-8", xml_declaration=True)
3170
+ with open(file, "wb") as f:
3171
+ f.write(xml_bytes)
3172
+
3173
+ @GeneralUtilities.check_arguments
3174
+ def translate(self, content: str, source_language: str, target_language: str, libre_translate_api_server: str) -> str:
3175
+ """Translates text using the LibreTranslate API."""
3176
+ url = f"{libre_translate_api_server.rstrip('/')}/translate"
3177
+ if "-" in source_language:
3178
+ source_language=source_language.split("-")[0]
3179
+ if "-" in target_language:
3180
+ target_language=target_language.split("-")[0]
3181
+ payload = {
3182
+ "q": content,
3183
+ "source": source_language,
3184
+ "target": target_language,
3185
+ "format": "text"
3186
+ }
3187
+ response = requests.post(url, json=payload, timeout=30)
3188
+ response.raise_for_status()
3189
+ return response.json()["translatedText"]
3190
+
3191
+ @GeneralUtilities.check_arguments
3192
+ def detect_language(self, content: str, libre_translate_api_server: str) -> str:
3193
+ """Detects the language of the given text using the LibreTranslate API."""
3194
+ url = f"{libre_translate_api_server.rstrip('/')}/detect"
3195
+ payload = {"q": content}
3196
+ response = requests.post(url, json=payload, timeout=30)
3197
+ response.raise_for_status()
3198
+ results = response.json()
3199
+ if not results:
3200
+ raise ValueError("Language detection returned no results.")
3201
+ return results[0]["language"]
3202
+
3203
+ @GeneralUtilities.check_arguments
3204
+ def get_all_files_in_git_repository(self,repository_folder:str,include_submodules: bool = True) -> list[str]:
3205
+ """returns all files in a git-repository except ignored files"""
3206
+ cmd = ["ls-files", "--cached", "--exclude-standard"]
3207
+ if include_submodules:
3208
+ cmd.append("--recurse-submodules")
3209
+ output=self.run_program_argsasarray("git", cmd,repository_folder)
3210
+ files = [ GeneralUtilities.normalize_path("./" + line) for line in output[1].splitlines()if line.strip() ]
3211
+ return files
3212
+
3213
+ @GeneralUtilities.check_arguments
3214
+ def write_file_list_for_repository(self,repository_folder:str,target_file:str="./FileList.txt") -> None:
3215
+ if os.path.isabs(target_file):
3216
+ target_file=GeneralUtilities.resolve_relative_path(target_file,repository_folder)
3217
+ target_file=GeneralUtilities.normalize_path(target_file)
3218
+ files=self.get_all_files_in_git_repository(repository_folder)
3219
+ GeneralUtilities.ensure_file_exists(target_file)
3220
+ GeneralUtilities.write_lines_to_file(target_file, files)
@@ -192,8 +192,8 @@ class TFCPS_CodeUnitSpecific_NodeJS_Functions(TFCPS_CodeUnitSpecific_Base):
192
192
 
193
193
  @GeneralUtilities.check_arguments
194
194
  def organize_translations(self,languages:list[str])->None:
195
- self.__ensure_translations_exist(languages)
196
195
  self._protected_sc.run_with_epew("npm","run extract-translations",self.get_codeunit_folder())
196
+ self.__ensure_translations_exist(languages)
197
197
  self._protected_sc.sync_xlf2_files("messages",languages,os.path.join(self.get_codeunit_folder(),"Other","Resources","Translations"))
198
198
 
199
199
  @GeneralUtilities.check_arguments
@@ -726,7 +726,7 @@ class TFCPS_Tools_General:
726
726
  if generate_certificate:
727
727
  self.__sc.generate_certificate_authority(ca_folder, ca_name, "DE", "SubjST", "SubjL", "SubjO", "SubjOU")
728
728
  # TODO add switch to auto-install the script if desired
729
- # for windows: powershell Import-Certificate -FilePath ConSurvCA_20241121000236.crt -CertStoreLocation 'Cert:\CurrentUser\Root'
729
+ # for windows: powershell Import-Certificate -FilePath MyProjectCA_20241121000236.crt -CertStoreLocation 'Cert:\CurrentUser\Root'
730
730
  # for linux: (TODO)
731
731
 
732
732
  @GeneralUtilities.check_arguments
@@ -1430,12 +1430,20 @@ class TFCPS_Tools_General:
1430
1430
  manifest_content = GeneralUtilities.replace_variable_in_string(manifest_content, "sha256_hashvalue", GeneralUtilities.get_sha256_of_file(artifacts_file))
1431
1431
  GeneralUtilities.write_text_to_file(winget_manifest_file, manifest_content)
1432
1432
 
1433
+ def download_file(self,source:str,target:str):
1434
+ GeneralUtilities.ensure_directory_exists(os.path.dirname(target))
1435
+ GeneralUtilities.ensure_file_exists(target)
1436
+ response = requests.get(source, timeout=30)
1437
+ response.raise_for_status()
1438
+ with open(target, "wb") as f:
1439
+ f.write(response.content)
1440
+
1433
1441
  def try_update_basic_codeunitreference_from_examples_repository(self,codeunit_folder:str,example_codeunit_name: str):
1434
- source=f"https://github.com/anionDev/CommonProjectStructureExamples/blob/main/{example_codeunit_name}/Other/Reference/ReferenceContent/HowToBuild.md"
1442
+ source=f"https://raw.githubusercontent.com/anionDev/CommonProjectStructureExamples/refs/heads/main/{example_codeunit_name}/Other/Reference/ReferenceContent/HowToBuild.md"
1435
1443
  target=f"{codeunit_folder}/Other/Reference/ReferenceContent/HowToBuild.md"
1436
- pass#TODO copy source to target. replace entire content. create target-file if it does not exist. ignore any error but print a warning in that case.
1444
+ self.download_file(source,target)
1437
1445
 
1438
1446
  def try_update_basic_repositoryreference_from_examples_repository(self,repository_folder:str):
1439
- source=f"https://github.com/anionDev/CommonProjectStructureExamples/blob/main/Other/Reference/RepositoryStructure.md"
1447
+ source=f"https://raw.githubusercontent.com/anionDev/CommonProjectStructureExamples/refs/heads/main/Other/Reference/RepositoryStructure.mdd"
1440
1448
  target=f"{repository_folder}/Other/Reference/RepositoryStructure.md"
1441
- pass#TODO copy source to target. replace entire content. create target-file if it does not exist. ignore any error but print a warning in that case.
1449
+ self.download_file(source,target)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ScriptCollection
3
- Version: 4.2.55
3
+ Version: 4.2.57
4
4
  Summary: The ScriptCollection is the place for reusable scripts.
5
5
  Home-page: https://github.com/anionDev/ScriptCollection
6
6
  Author: Marius Göcke
@@ -33,7 +33,7 @@ Requires-Dist: ntplib>=0.4.0
33
33
  Requires-Dist: Pillow>=11.3.0
34
34
  Requires-Dist: psutil>=7.2.2
35
35
  Requires-Dist: pycdlib>=1.14.0
36
- Requires-Dist: Pygments>=2.19.2
36
+ Requires-Dist: Pygments>=2.20.0
37
37
  Requires-Dist: pylint>=4.0.5
38
38
  Requires-Dist: pyOpenSSL>=25.3.0
39
39
  Requires-Dist: PyPDF>=6.9.2
@@ -9,7 +9,7 @@ ScriptCollection/ProgramRunnerMock.py,sha256=uTu-aFle1W_oKjeQEmuPsFPQpvo0kRf2FrR
9
9
  ScriptCollection/ProgramRunnerPopen.py,sha256=BPY7-ZMIlqT7JOKz8qlB5c0laF2Js-ijzqk09GxZC48,3821
10
10
  ScriptCollection/ProgramRunnerSudo.py,sha256=_khC3xuTdrPoLluBJZWfldltmmuKltABJPcbjZSFW-4,4835
11
11
  ScriptCollection/SCLog.py,sha256=8TRy1LeYMsPOIuWUcnUNNbO5pd-cNBS-3cn-kdzP8FU,4768
12
- ScriptCollection/ScriptCollectionCore.py,sha256=RP0uhnHlZGtVxzOUjMzX0zGQ9OA7IjexFgJH6jOcI1Q,170736
12
+ ScriptCollection/ScriptCollectionCore.py,sha256=jjGd7cbFB-FpsXsymVoFcF_M9wXIZ2AIttcRfiXl8IU,174895
13
13
  ScriptCollection/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
14
14
  ScriptCollection/OCIImages/AbstractImageHandler.py,sha256=83qDMILwxhH9DbC0sb358Vu8PXEysmJJyap_6gECZqs,1627
15
15
  ScriptCollection/OCIImages/OCIImageManager.py,sha256=aBogkSXNDyi8NO11N-s03nuFJEv7PyJ-wjHuYYeZfvs,6662
@@ -30,7 +30,7 @@ ScriptCollection/TFCPS/TFCPS_Generic.py,sha256=O-0guM_LJCcZmPZJhMgTvXD2RXUJEBWWv
30
30
  ScriptCollection/TFCPS/TFCPS_MergeToMain.py,sha256=-Ev9D3bZDlUk2WFQhcmvzQ3FCS97OdsVUd0koAdmpZc,7474
31
31
  ScriptCollection/TFCPS/TFCPS_MergeToStable.py,sha256=Ajfy2pLajTuU6UpwItHt4C2a-gLF3gPc4z6BktL3Cio,22163
32
32
  ScriptCollection/TFCPS/TFCPS_PreBuildCodeunitsScript.py,sha256=f0Uq1cA_4LvmL72cal0crrbKF6PcxL13D9wBKuQ1YBw,2328
33
- ScriptCollection/TFCPS/TFCPS_Tools_General.py,sha256=e_v-YqtRW1Qe4xvuOZYq3WZJKdnOScgfHu8H-keC-gE,93779
33
+ ScriptCollection/TFCPS/TFCPS_Tools_General.py,sha256=WV67pHLrhD_qEjUqM-8tUpEdhQ4brwVentfIf7AMOP4,93942
34
34
  ScriptCollection/TFCPS/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
35
35
  ScriptCollection/TFCPS/Docker/TFCPS_CodeUnitSpecific_Docker.py,sha256=BPJkoy2KVgB_38cAk5qjM4s4FpJvOkTp467nrvANIIU,10606
36
36
  ScriptCollection/TFCPS/Docker/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -43,12 +43,12 @@ ScriptCollection/TFCPS/Flutter/TFCPS_CodeUnitSpecific_Flutter.py,sha256=U8oBAOLR
43
43
  ScriptCollection/TFCPS/Flutter/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
44
44
  ScriptCollection/TFCPS/Go/TFCPS_CodeUnitSpecific_Go.py,sha256=kyx26AnT1-LySFA46wfJ9yZUKYdMWTD0U2XZfSQbuB0,3497
45
45
  ScriptCollection/TFCPS/Go/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
46
- ScriptCollection/TFCPS/NodeJS/TFCPS_CodeUnitSpecific_NodeJS.py,sha256=BBWrFaAUVdmjl8qPq231aYlAENnjF1BOWXQQmOrQdxE,11816
46
+ ScriptCollection/TFCPS/NodeJS/TFCPS_CodeUnitSpecific_NodeJS.py,sha256=Kkyyof6DML7jUdES5GmIXQ_yVMJ1xnJbZmbIAqls3IE,11816
47
47
  ScriptCollection/TFCPS/NodeJS/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
48
48
  ScriptCollection/TFCPS/Python/TFCPS_CodeUnitSpecific_Python.py,sha256=nLw_eSUd_56jjgfcAvtUyzecSZ14mYmNJl0iu-1YNVk,13496
49
49
  ScriptCollection/TFCPS/Python/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
50
- scriptcollection-4.2.55.dist-info/METADATA,sha256=4gNDfxGTvE09BqqV8gBNTLsHpqDVRywDDUSOtZfksTs,7690
51
- scriptcollection-4.2.55.dist-info/WHEEL,sha256=aeYiig01lYGDzBgS8HxWXOg3uV61G9ijOsup-k9o1sk,91
52
- scriptcollection-4.2.55.dist-info/entry_points.txt,sha256=27XwAJEcaMEc1be0Ec1vKHCbiU4Ziu8jKL-SqsrYOIQ,4680
53
- scriptcollection-4.2.55.dist-info/top_level.txt,sha256=hY2hOVH0V0Ce51WB76zKkIWTUNwMUdHo4XDkR2vYVwg,17
54
- scriptcollection-4.2.55.dist-info/RECORD,,
50
+ scriptcollection-4.2.57.dist-info/METADATA,sha256=iMa7-_9uZdnhT-dv-aA7iTfCkOk5d8-Os0jqzuyFT1Y,7690
51
+ scriptcollection-4.2.57.dist-info/WHEEL,sha256=aeYiig01lYGDzBgS8HxWXOg3uV61G9ijOsup-k9o1sk,91
52
+ scriptcollection-4.2.57.dist-info/entry_points.txt,sha256=27XwAJEcaMEc1be0Ec1vKHCbiU4Ziu8jKL-SqsrYOIQ,4680
53
+ scriptcollection-4.2.57.dist-info/top_level.txt,sha256=hY2hOVH0V0Ce51WB76zKkIWTUNwMUdHo4XDkR2vYVwg,17
54
+ scriptcollection-4.2.57.dist-info/RECORD,,