diff --git a/.github/scripts/check_pot_freshness.py b/.github/scripts/check_pot_freshness.py deleted file mode 100755 index 8eacaf35..00000000 --- a/.github/scripts/check_pot_freshness.py +++ /dev/null @@ -1,56 +0,0 @@ -#!/usr/bin/env python3 -"""Check that all tr() strings from code exist in base.pot. - -Used by CI. Fails if any translatable string is missing from the committed pot. - -Usage: - xgettext ... -o /tmp/generated.pot - python3 check_pot_freshness.py /tmp/generated.pot locales/base.pot -""" - -import re -import sys -from pathlib import Path - - -def extract_msgids(path: str) -> set[str]: - content = Path(path).read_text() - ids: set[str] = set() - current: str | None = None - - for line in content.splitlines(): - if line.startswith('msgid '): - m = re.search(r'"(.*)"', line) - current = m.group(1) if m else '' - elif current is not None and line.startswith('"'): - m = re.search(r'"(.*)"', line) - if m: - current += m.group(1) - else: - if current is not None and current: - ids.add(current) - current = None - - if current: - ids.add(current) - - return ids - - -def main() -> None: - generated = extract_msgids(sys.argv[1]) - committed = extract_msgids(sys.argv[2]) - - missing = sorted(generated - committed) - - if missing: - print('::error::New tr() strings not in base.pot - run locales_generator.sh:') - for s in missing: - print(f' {s}') - sys.exit(1) - - print('All tr() strings are present in base.pot') - - -if __name__ == '__main__': - main() diff --git a/.github/workflows/translation-check.yaml b/.github/workflows/translation-check.yaml index 6d996309..f99cc330 100644 --- a/.github/workflows/translation-check.yaml +++ b/.github/workflows/translation-check.yaml @@ -5,13 +5,11 @@ on: - 'archinstall/**/*.py' - 'archinstall/locales/**' - '.github/workflows/translation-check.yaml' - - '.github/scripts/check_pot_freshness.py' pull_request: paths: - 'archinstall/**/*.py' - 'archinstall/locales/**' - '.github/workflows/translation-check.yaml' - - '.github/scripts/check_pot_freshness.py' jobs: validate-po: name: Validate .po files and translation patterns @@ -123,18 +121,18 @@ jobs: else echo "has_py_changes=false" >> "$GITHUB_OUTPUT" fi - - name: Install gettext and python + - name: Install gettext if: steps.check_py.outputs.has_py_changes == 'true' run: | pacman-key --init pacman --noconfirm -Sy archlinux-keyring pacman --noconfirm -Syyu - pacman --noconfirm -S gettext python + pacman --noconfirm -S gettext - name: Check for missing translatable strings if: steps.check_py.outputs.has_py_changes == 'true' run: | cd archinstall - find . -type f -name '*.py' | xargs xgettext \ + find . -type f -name '*.py' | sort | xargs xgettext \ --no-location --omit-header --keyword='tr' \ -d base -o /tmp/generated.pot - python3 ../.github/scripts/check_pot_freshness.py /tmp/generated.pot locales/base.pot + msgcmp --use-untranslated locales/base.pot /tmp/generated.pot diff --git a/scripts/pot_tools.py b/scripts/pot_tools.py deleted file mode 100755 index aec7374e..00000000 --- a/scripts/pot_tools.py +++ /dev/null @@ -1,151 +0,0 @@ -#!/usr/bin/env python3 -"""Tools for managing base.pot: find and add missing translatable strings. - -Usage (from repo root): - scripts/pot_tools.py stats - scripts/pot_tools.py list - scripts/pot_tools.py add_missing [--dry-run] - -Requires: gettext (xgettext) installed. -""" - -import os -import re -import subprocess -import sys -import tempfile -from pathlib import Path - -REPO_ROOT = Path(__file__).resolve().parent.parent -ARCHINSTALL_DIR = REPO_ROOT / 'archinstall' -BASE_POT = ARCHINSTALL_DIR / 'locales' / 'base.pot' - - -def extract_msgids(path: Path) -> set[str]: - content = path.read_text() - ids: set[str] = set() - current: str | None = None - - for line in content.splitlines(): - if line.startswith('msgid '): - m = re.search(r'"(.*)"', line) - current = m.group(1) if m else '' - elif current is not None and line.startswith('"'): - m = re.search(r'"(.*)"', line) - if m: - current += m.group(1) - else: - if current is not None and current: - ids.add(current) - current = None - - if current: - ids.add(current) - - return ids - - -def generate_fresh_pot() -> Path: - fd, tmp_path = tempfile.mkstemp(suffix='.pot') - os.close(fd) - tmp = Path(tmp_path) - py_files = sorted(str(p) for p in ARCHINSTALL_DIR.rglob('*.py')) - - cmd = [ - 'xgettext', - '--no-location', - '--omit-header', - '--keyword=tr', - '-d', - 'base', - '-o', - str(tmp), - ] + py_files - - subprocess.run(cmd, check=True, capture_output=True) - return tmp - - -def get_missing(fresh_pot: Path) -> set[str]: - generated = extract_msgids(fresh_pot) - committed = extract_msgids(BASE_POT) - return generated - committed - - -def cmd_stats() -> None: - fresh_pot = generate_fresh_pot() - try: - generated = extract_msgids(fresh_pot) - committed = extract_msgids(BASE_POT) - missing = generated - committed - - print(f'Code: {len(generated)} translatable strings') - print(f'base.pot: {len(committed)} msgids') - print(f' Missing: {len(missing)}') - finally: - fresh_pot.unlink(missing_ok=True) - - -def cmd_list() -> None: - fresh_pot = generate_fresh_pot() - try: - missing = sorted(get_missing(fresh_pot)) - - if missing: - print(f'=== MISSING ({len(missing)}): in code but not in base.pot ===') - for s in missing: - print(f' + {s}') - else: - print('No missing strings') - finally: - fresh_pot.unlink(missing_ok=True) - - -def cmd_add_missing(dry_run: bool = False) -> None: - fresh_pot = generate_fresh_pot() - try: - missing = sorted(get_missing(fresh_pot)) - - if not missing: - print('No missing strings, base.pot is up to date') - return - - print(f'Adding {len(missing)} missing string(s)') - for s in missing: - print(f' + {s}') - - if dry_run: - print('(dry-run, no changes written)') - return - - with open(BASE_POT, 'a') as f: - for s in missing: - if '{' in s: - f.write('\n#, python-brace-format') - f.write(f'\nmsgid "{s}"\nmsgstr ""\n') - - print(f'Done. Added to {BASE_POT}') - finally: - fresh_pot.unlink(missing_ok=True) - - -def main() -> None: - if len(sys.argv) < 2 or sys.argv[1] in ('-h', '--help'): - print('Usage: pot_tools.py {stats|list|add_missing} [--dry-run]') - sys.exit(0) - - cmd = sys.argv[1] - if cmd == 'stats': - cmd_stats() - elif cmd == 'list': - cmd_list() - elif cmd == 'add_missing': - dry_run = '--dry-run' in sys.argv - cmd_add_missing(dry_run) - else: - print(f'Unknown command: {cmd}') - sys.exit(1) - - -if __name__ == '__main__': - main()