mirror of
https://github.com/meshtastic/Meshtastic-Android.git
synced 2026-06-25 22:15:33 -04:00
80 lines
2.8 KiB
Python
Executable File
80 lines
2.8 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
"""Validate Fastlane store-listing metadata against store length limits.
|
|
|
|
The ``fastlane/metadata/android`` tree is a mirror of Crowdin: translations are
|
|
downloaded on a schedule (see ``.github/workflows/scheduled-updates.yml``).
|
|
Crowdin's max-length toggle only blocks *new* submissions; translations entered
|
|
before enforcement was enabled are grandfathered in and keep syncing down. This
|
|
script is the repo-side guard that catches them regardless of Crowdin state.
|
|
|
|
Lengths are measured in Unicode code points (what Google Play and F-Droid /
|
|
IzzyOnDroid count), not bytes -- a byte count badly over-reports Cyrillic and
|
|
CJK strings.
|
|
|
|
Exit status is non-zero if any file exceeds its limit, so it can gate CI.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import os
|
|
import sys
|
|
from pathlib import Path
|
|
|
|
# Repo root = parent of this script's directory (scripts/).
|
|
REPO_ROOT = Path(__file__).resolve().parent.parent
|
|
METADATA_DIR = REPO_ROOT / "fastlane" / "metadata" / "android"
|
|
|
|
# Per-file character limits. Keys are file names under each locale directory.
|
|
# 80 is the F-Droid summary / Google Play short-description limit; 30 is the
|
|
# Play title limit. Add more entries here to extend coverage.
|
|
LIMITS = {
|
|
"short_description.txt": 80,
|
|
"title.txt": 30,
|
|
}
|
|
|
|
# Running inside GitHub Actions enables ::error:: annotations on the PR.
|
|
IN_GITHUB_ACTIONS = os.environ.get("GITHUB_ACTIONS") == "true"
|
|
|
|
|
|
def char_count(path: Path) -> int:
|
|
"""Code-point length of a metadata file, ignoring trailing whitespace."""
|
|
return len(path.read_text(encoding="utf-8").rstrip())
|
|
|
|
|
|
def main() -> int:
|
|
if not METADATA_DIR.is_dir():
|
|
print(f"error: metadata directory not found: {METADATA_DIR}", file=sys.stderr)
|
|
return 2
|
|
|
|
violations: list[tuple[Path, int, int]] = []
|
|
|
|
for file_name, limit in sorted(LIMITS.items()):
|
|
for path in sorted(METADATA_DIR.glob(f"*/{file_name}")):
|
|
count = char_count(path)
|
|
if count > limit:
|
|
violations.append((path, count, limit))
|
|
|
|
if not violations:
|
|
print("All store-listing metadata is within length limits.")
|
|
return 0
|
|
|
|
print("Store-listing metadata exceeds length limits:\n")
|
|
for path, count, limit in violations:
|
|
rel = path.relative_to(REPO_ROOT)
|
|
message = f"{rel} is {count} chars (limit {limit})"
|
|
print(f" - {message}")
|
|
if IN_GITHUB_ACTIONS:
|
|
# Annotate the offending file directly in the PR diff view.
|
|
print(f"::error file={rel}::{message}")
|
|
|
|
print(
|
|
"\nThese files are mirrored from Crowdin. Fix them at the source "
|
|
"(shorten or remove the overlength translation so it is re-translated), "
|
|
"then re-sync -- editing the mirror here is overwritten on the next sync."
|
|
)
|
|
return 1
|
|
|
|
|
|
if __name__ == "__main__":
|
|
raise SystemExit(main())
|