@@ -134,51 +134,43 @@ jobs:
134134 run : |
135135 echo "Fetching contributors between $DATE_FROM and $DATE_TO"
136136
137- # ── A: Map changed translation paths → source (en) paths ───────────────
138- # e.g. climweb/.../locale/fr/LC_MESSAGES/django.po
139- # → /climweb/.../locale/en/LC_MESSAGES/django.po (Crowdin absolute path)
140- SOURCE_PATHS=()
141- while IFS= read -r f; do
142- [ -z "$f" ] && continue
143- src=$(echo "$f" | sed 's|/locale/[^/]*/LC_MESSAGES/|/locale/en/LC_MESSAGES/|g')
144- SOURCE_PATHS+=("/$src")
145- done <<< "$CHANGED_FILES"
146-
147- # Deduplicate — multiple languages changed from the same source file
148- # should only result in one file ID lookup
149- mapfile -t SOURCE_PATHS < <(printf '%s\n' "${SOURCE_PATHS[@]}" | sort -u)
150-
151- echo "Source paths to look up (${#SOURCE_PATHS[@]}):"
152- printf ' %s\n' "${SOURCE_PATHS[@]}"
153-
154- # ── B: Fetch all Crowdin file IDs ───────────────────────────────────────
137+ # ── A: Fetch all Crowdin file IDs once — matched per changed file below ───
155138 ALL_FILES=$(curl -sf \
156139 "https://api.crowdin.com/api/v2/projects/${CROWDIN_PROJECT_ID}/files?limit=500" \
157140 -H "Authorization: Bearer ${CROWDIN_TOKEN}")
158141
159- # ── C: Match source paths → Crowdin file IDs ────────────────────────────
160- FILE_IDS=()
161- for src_path in "${SOURCE_PATHS[@]}"; do
142+ # ── B: Fetch approvals per file+language, collect unique approvers ────────
143+ # The approvals endpoint requires both fileId AND languageId.
144+ # We extract the language code from each changed file path directly
145+ # e.g. locale/fr/LC_MESSAGES/django.po → "fr"
146+ # Then query approvals for each unique file+language combination.
147+ declare -A SEEN_USERS
148+ declare -A SEEN_FILE_LANG # avoid duplicate file+lang lookups
149+ CO_AUTHORS=""
150+
151+ while IFS= read -r changed_file; do
152+ [ -z "$changed_file" ] && continue
153+
154+ # Extract language code from path e.g. locale/fr/LC_MESSAGES → fr
155+ lang_code=$(echo "$changed_file" | grep -oP '(?<=/locale/)[^/]+(?=/LC_MESSAGES)')
156+ [ -z "$lang_code" ] && continue
157+
158+ # Map to source path to get file ID
159+ src_path="/$(echo "$changed_file" | sed 's|/locale/[^/]*/LC_MESSAGES/|/locale/en/LC_MESSAGES/|g')"
162160 file_id=$(echo "$ALL_FILES" | jq -r \
163161 --arg p "$src_path" \
164162 '.data[] | select(.data.path == $p) | .data.id')
165- if [ -n "$file_id" ] && [ "$file_id" != "null" ]; then
166- FILE_IDS+=("$file_id")
167- echo " Matched: $src_path → file ID $file_id"
168- else
169- echo " No match for: $src_path"
170- fi
171- done
172-
173- # ── D: Fetch approvals per file, collect unique approvers ───────────────
174- # Only approvals whose createdAt falls within the sync window are included.
175- declare -A SEEN_USERS
176- CO_AUTHORS=""
177163
178- for file_id in "${FILE_IDS[@]}"; do
179- echo "Fetching approvals for file ID: $file_id"
164+ [ -z "$file_id" ] || [ "$file_id" = "null" ] && continue
165+
166+ # Skip if we already fetched this file+language combination
167+ key="${file_id}:${lang_code}"
168+ [ -n "${SEEN_FILE_LANG[$key]+_}" ] && continue
169+ SEEN_FILE_LANG[$key]=1
170+
171+ echo "Fetching approvals for file ID $file_id, language $lang_code"
180172 APPROVALS=$(curl -sf \
181- "https://api.crowdin.com/api/v2/projects/${CROWDIN_PROJECT_ID}/approvals?fileId=${file_id}&limit=500" \
173+ "https://api.crowdin.com/api/v2/projects/${CROWDIN_PROJECT_ID}/approvals?fileId=${file_id}&languageId=${lang_code}& limit=500" \
182174 -H "Authorization: Bearer ${CROWDIN_TOKEN}")
183175
184176 while IFS=$'\t' read -r fullname username; do
@@ -196,7 +188,7 @@ jobs:
196188 | select(.data.user != null)
197189 | [(.data.user.fullName // .data.user.username), .data.user.username]
198190 | @tsv')
199- done
191+ done <<< "$CHANGED_FILES"
200192
201193 CO_AUTHORS=$(echo "$CO_AUTHORS" | sort -u | sed '/^$/d')
202194
0 commit comments