From 1846940181234434436cea5d073e3c759492a58c Mon Sep 17 00:00:00 2001 From: Adrien Ufferte Date: Fri, 13 Feb 2026 10:30:11 +0100 Subject: [PATCH] Check translations --- .../check_localization_translations.py | 103 ++++++++++++++++++ .../workflows/localization-translations.yml | 34 ++++++ 2 files changed, 137 insertions(+) create mode 100644 .github/scripts/check_localization_translations.py create mode 100644 .github/workflows/localization-translations.yml diff --git a/.github/scripts/check_localization_translations.py b/.github/scripts/check_localization_translations.py new file mode 100644 index 00000000..52acd032 --- /dev/null +++ b/.github/scripts/check_localization_translations.py @@ -0,0 +1,103 @@ +import csv +import re +import sys +from collections import Counter +from pathlib import Path + +UTILS_PATH = Path("sources/utils/autoloads/utils.gd") +LOCALIZATION_PATH = Path("kalulu_localization.csv") + + +def parse_supported_locales() -> list[str]: + content = UTILS_PATH.read_text(encoding="utf-8") + match = re.search( + r"const\s+SUPPORTED_LOCALES\s*:\s*Dictionary\[String,\s*String\]\s*=\s*\{(.*?)\}", + content, + re.S, + ) + if not match: + raise ValueError("Could not find SUPPORTED_LOCALES in utils.gd") + + dictionary_body = match.group(1) + locale_keys = re.findall(r'"([A-Za-z0-9_]+)"\s*:', dictionary_body) + if not locale_keys: + raise ValueError("No locale keys found in SUPPORTED_LOCALES") + return locale_keys + + +def build_required_columns(locales: list[str], headers: list[str]) -> tuple[set[str], dict[str, str]]: + base_counts = Counter(locale.split("_", 1)[0] for locale in locales) + required = set() + resolved_columns = {} + + for locale in locales: + base = locale.split("_", 1)[0] + if base_counts[base] > 1: + required.add(base) + if base in headers: + resolved_columns[base] = base + continue + + # Unique locale: accept either base (e.g. fr) or full locale (e.g. pt_BR) + required.add(base) + if base in headers: + resolved_columns[base] = base + elif locale in headers: + resolved_columns[base] = locale + + return required, resolved_columns + + +def main() -> int: + locales = parse_supported_locales() + + with LOCALIZATION_PATH.open("r", encoding="utf-8-sig", newline="") as csv_file: + reader = csv.reader(csv_file) + rows = list(reader) + + if not rows: + print("### ❌ Localization check failed\n") + print("`kalulu_localization.csv` is empty.") + return 1 + + headers = [header.strip() for header in rows[0]] + required_columns, resolved_columns = build_required_columns(locales, headers) + + missing_columns = sorted(column for column in required_columns if column not in resolved_columns) + + missing_translations = [] + if not missing_columns: + header_indexes = {header: idx for idx, header in enumerate(headers)} + for row_number, row in enumerate(rows[1:], start=2): + if not row: + continue + + key = row[0].strip() if len(row) > 0 else "" + key_label = key if key else f"" + + for required_column, actual_header in resolved_columns.items(): + column_index = header_indexes[actual_header] + value = row[column_index].strip() if column_index < len(row) else "" + if value == "": + missing_translations.append((row_number, key_label, required_column)) + + if missing_columns or missing_translations: + print("### ❌ Localization translation check failed\n") + + for column in missing_columns: + print(f"- Missing translation column {column} in kalulu_localization.csv") + + for row_number, key_label, column in missing_translations: + print( + f"- Missing translation for key `{key_label}` in language `{column}` " + f"(row {row_number} in kalulu_localization.csv)" + ) + + return 1 + + print("✅ All required translation columns and values are present.") + return 0 + + +if __name__ == "__main__": + sys.exit(main()) diff --git a/.github/workflows/localization-translations.yml b/.github/workflows/localization-translations.yml new file mode 100644 index 00000000..54286947 --- /dev/null +++ b/.github/workflows/localization-translations.yml @@ -0,0 +1,34 @@ +name: Localization Translation Check + +on: + pull_request: + types: [opened, synchronize, reopened] + +jobs: + localization_translations: + runs-on: ubuntu-latest + permissions: + pull-requests: write + steps: + - uses: actions/checkout@v3 + - name: Run localization translation check + id: localization + run: | + python3 .github/scripts/check_localization_translations.py > localization_translation_output.txt + continue-on-error: true + - name: Comment on PR with localization translation output + if: steps.localization.outcome != 'success' + uses: actions/github-script@v7 + with: + script: | + const fs = require('fs'); + const body = fs.readFileSync('localization_translation_output.txt', 'utf8'); + await github.rest.issues.createComment({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: context.issue.number, + body, + }); + - name: Fail if localization translation check failed + if: steps.localization.outcome != 'success' + run: exit 1