forked from nvdaaddons/AddonTemplate
-
Notifications
You must be signed in to change notification settings - Fork 6
Expand file tree
/
Copy pathcheckTranslation.py
More file actions
148 lines (113 loc) · 4.18 KB
/
checkTranslation.py
File metadata and controls
148 lines (113 loc) · 4.18 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
# checkTranslation.py
# Copyright (C) 2026 NV Access Limited, Abdel
# This file is covered by the GNU General Public License.
# See the file COPYING for more details.
import sys
import os
from crowdin_api import CrowdinClient
def findFileId(client: CrowdinClient, projectId: int, baseTarget: str, searchExt: str) -> int | None:
"""
Iterates through all project files (using pagination) to find the ID of the source file matching the target name and extension.
:param client: The Crowdin API client instance.
:param projectId: The ID of the Crowdin project.
:param base_target: The base name of the file (e.g., 'myAddon).
:param search_ext: The extension to look for (e.g., '.pot').
:return: The file ID if found, otherwise None.
"""
offset = 0
limit = 100
while True:
resp = client.source_files.list_files(
projectId=projectId,
limit=limit,
offset=offset,
)
data = resp["data"]
for f in data:
path_crowdin = f["data"]["path"].lower()
# Check if the path ends with addon_id.pot or addon_id.xliff.
if path_crowdin.endswith(f"{baseTarget}{searchExt}"):
fileId = f["data"]["id"]
print(f"DEBUG: Match found: {path_crowdin} (ID: {fileId})")
return fileId
if len(data) < limit:
break
offset += limit
return None
def getScoreFromApi(fileNameToSearch: str, langId: str) -> float:
"""
Retrieves the translation progress score for a specific language and file.
Handles pagination for both file listing and language status.
:param fileNameToSearch: The local path or name of the file to check.
:param langId: The language code (e.g., 'fr' or 'pt_BR').
:return: The translation ratio between 0.0 and 1.0.
"""
token = os.environ.get("crowdinAuthToken")
projectIdEnv = os.environ.get("CROWDIN_PROJECT_ID")
if not token or not projectIdEnv:
print("ERROR: Missing environment variables 'crowdinAuthToken' or 'CROWDIN_PROJECT_ID'.")
return 0.0
client = CrowdinClient(token=token)
projectId = int(projectIdEnv)
try:
# Clean and prepare search patterns.
# Example: 'addon/locale/fr/LC_MESSAGES/myAddon.po' -> base_target: 'myAddon'.
baseTarget = fileNameToSearch.replace("\\", "/").split("/")[-1].rsplit(".", 1)[0].lower()
extTarget = fileNameToSearch.split(".")[-1].lower()
# On Crowdin, the source for a .po file is usually a .pot file.
searchExt = ".pot" if extTarget == "po" else f".{extTarget}"
print(f"DEBUG: Searching for source file: {baseTarget}{searchExt}")
fileId = findFileId(client, projectId, baseTarget, searchExt)
if fileId is None:
print(f"WARNING: File '{baseTarget}{searchExt}' not found on Crowdin.")
return 0.0
# Pagination for translation status (Progress).
offset = 0
limit = 100
while True:
resp = client.translation_status.get_file_progress(
projectId=projectId,
fileId=fileId,
limit=limit,
offset=offset,
)
data = resp["data"]
for item in data:
langApi = item["data"]["languageId"]
# Flexible matching (e.g., 'fr' will match 'fr' or 'fr-FR' from API).
# Also handles underscore to dash conversion for Crowdin compatibility
if langApi.lower().startswith(langId.lower().replace("_", "-")):
progress = float(item["data"]["translationProgress"])
return progress / 100
# Check pagination total.
total = resp["pagination"]["totalCount"]
if offset + limit >= total:
break
offset += limit
print(f"DEBUG: Language '{langId}' not found in progress list for this file.")
return 0.0
except Exception as e:
print(f"API ERROR: {e}")
return 0.0
def main():
if len(sys.argv) < 3:
print("Usage: python checkTranslation.py <filePath> <langId>")
sys.exit(2)
input_file = sys.argv[1]
lang = sys.argv[2]
score = getScoreFromApi(input_file, lang)
# Output formatted for capture by the PowerShell script.
print(f"translationRatio={score}")
# Identify extension to provide a specific score label.
ext = input_file.lower().split(".")[-1]
if ext == "md":
print(f"mdScore={score}")
elif ext == "xliff":
print(f"xliffScore={score}")
else:
# Default to poScore for .po and other localization files.
print(f"poScore={score}")
# Exit with success (0) if there is at least 50% translated content.
sys.exit(0 if score > 0.5 else 1)
if __name__ == "__main__":
main()