diff --git a/.github/workflows/translation-check.yml b/.github/workflows/translation-check.yml index 60d8a2d40d..e3e9ccc494 100644 --- a/.github/workflows/translation-check.yml +++ b/.github/workflows/translation-check.yml @@ -10,6 +10,7 @@ on: push: paths: - 'src/translation/wininstaller/**' + - 'src/translation/*.ts' - 'tools/check-wininstaller-translations.sh' - '.github/workflows/translation-check.yml' @@ -24,5 +25,7 @@ jobs: uses: actions/checkout@v6 - name: "Check Windows installer translations" run: ./tools/check-wininstaller-translations.sh + - name: "Check application translations" + run: pip install PyGithub && ./tools/check-translations.py #- name: "Check for duplicate hotkeys (will not fail)" # run: sudo apt install libxml-simple-perl && cd src/translation/ && perl ./tools/checkkeys.pl diff --git a/tools/check-translations.py b/tools/check-translations.py new file mode 100755 index 0000000000..78552c8b70 --- /dev/null +++ b/tools/check-translations.py @@ -0,0 +1,210 @@ +#!/usr/bin/env python3 +# +############################################################################## +# Copyright (c) 2022-2026 +# +# Author(s): +# ChatGPT +# ann0see +# The Jamulus Development Team +# +############################################################################## +# +# This program is free software; you can redistribute it and/or modify it under +# the terms of the GNU General Public License as published by the Free Software +# Foundation; either version 2 of the License, or (at your option) any later +# version. +# +# This program is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more +# details. +# +# You should have received a copy of the GNU General Public License along with +# this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA +# +############################################################################## + +import re +import os +import xml.etree.ElementTree as ET +from collections import defaultdict +from pathlib import Path + +from github import Github + +# --- Configuration --- +# Directory where the TS translation files are stored +TS_DIR = Path("src/translation") +TS_FILES = sorted(TS_DIR.glob("translation_*.ts")) + +# Regex patterns for placeholders (%1, %2...) and HTML tags +PLACEHOLDER_RE = re.compile(r"%\d+") +HTML_TAG_RE = re.compile(r"<[^>]+>") + +# GitHub environment variables for optional PR commenting +GH_TOKEN = os.environ.get("GH_TOKEN") +REPO = os.environ.get("GITHUB_REPOSITORY") +PR_NUMBER = os.environ.get("PR_NUMBER") + + +# --- Function: detect warnings in a TS file --- +def detect_warnings(ts_file): + """ + Scans a TS file and returns a list of warning dictionaries. + Each warning contains the file, approximate line number, and message. + """ + warnings = [] + + try: + # Read all lines to help approximate line numbers + lines = ts_file.read_text(encoding="utf-8").splitlines() + tree = ET.parse(ts_file) + root = tree.getroot() + except Exception as e: + warnings.append( + { + "file": ts_file, + "line": 0, + "message": f"Error reading or parsing XML: {e}", + } + ) + return warnings + + # Ensure language in the TS header matches the filename + file_lang = ts_file.stem.replace("translation_", "") + if root.attrib.get("language", "") != file_lang: + warnings.append( + { + "file": ts_file, + "line": 0, + "message": f"Language header mismatch '{root.attrib.get('language', '')}' != '{file_lang}'", + } + ) + + line_idx = 0 + for context in root.findall("context"): + for message in context.findall("message"): + # Approximate line number: first line containing + approx_line = next( + (i + 1 for i in range(line_idx, len(lines)) if "