diff --git a/.github/scripts/check_pot_freshness.py b/.github/scripts/check_pot_freshness.py index 1d2d78e5..8eacaf35 100755 --- a/.github/scripts/check_pot_freshness.py +++ b/.github/scripts/check_pot_freshness.py @@ -4,8 +4,8 @@ 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 + xgettext ... -o /tmp/generated.pot + python3 check_pot_freshness.py /tmp/generated.pot locales/base.pot """ import re @@ -14,43 +14,43 @@ from pathlib import Path def extract_msgids(path: str) -> set[str]: - content = Path(path).read_text() - ids: set[str] = set() - current: str | None = None + 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 + 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) + if current: + ids.add(current) - return ids + return ids def main() -> None: - generated = extract_msgids(sys.argv[1]) - committed = extract_msgids(sys.argv[2]) + generated = extract_msgids(sys.argv[1]) + committed = extract_msgids(sys.argv[2]) - missing = sorted(generated - committed) + 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) + 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') + print('All tr() strings are present in base.pot') if __name__ == '__main__': - main() + main() diff --git a/scripts/pot_tools.py b/scripts/pot_tools.py index 35bd051b..aec7374e 100755 --- a/scripts/pot_tools.py +++ b/scripts/pot_tools.py @@ -2,9 +2,9 @@ """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] + scripts/pot_tools.py stats + scripts/pot_tools.py list + scripts/pot_tools.py add_missing [--dry-run] Requires: gettext (xgettext) installed. """ @@ -22,124 +22,130 @@ 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 + 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 + 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) + if current: + ids.add(current) - return ids + 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')) + 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')) - subprocess.run( - ['xgettext', '--no-location', '--omit-header', - '--keyword=tr', '-d', 'base', '-o', str(tmp)] + py_files, - check=True, - capture_output=True, - ) - return tmp + 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 + 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 + 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) + 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)) + 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) + 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)) + 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 + 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}') + 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 + 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') + 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) + 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) + 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) + 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() + main()