find_leaks.py 2.3 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364
  1. import json
  2. import sys
  3. from pathlib import Path
  4. # Ensure stdout handles UTF-8 correctly for console printing
  5. if hasattr(sys.stdout, 'reconfigure'):
  6. sys.stdout.reconfigure(encoding='utf-8')
  7. LOCALES_DIR = Path("src/locales")
  8. USER_MASTER = LOCALES_DIR / "translations.user.json"
  9. ADMIN_MASTER = LOCALES_DIR / "translations.admin.json"
  10. LANGUAGES = ["en", "me", "ru", "ua"]
  11. def is_cyrillic(s):
  12. """Checks if a string contains any Cyrillic characters."""
  13. return any('\u0400' <= c <= '\u04FF' for c in s)
  14. def find_leaks(data, path=""):
  15. """
  16. Recursively searches through translation objects to find:
  17. 1. Cyrillic characters in 'en' or 'me' fields (leaked Russian/Ukrainian).
  18. 2. Specific Russian-only characters (ы, ъ, ё, э) in 'ua' fields.
  19. """
  20. leaks = []
  21. if isinstance(data, dict):
  22. # If this is a leaf leaf node containing language keys
  23. if all(lang in data for lang in LANGUAGES):
  24. for lang in LANGUAGES:
  25. val = str(data[lang])
  26. # Check for Cyrillic in languages that use Latin (en, me)
  27. if lang in ["en", "me"] and is_cyrillic(val):
  28. leaks.append((f"{path} [{lang}]", val))
  29. # Check for Russian-only characters in Ukrainian
  30. if lang == "ua":
  31. russian_only = ['ы', 'ъ', 'ё', 'э', 'Ы', 'Ъ', 'Ё', 'Э']
  32. if any(c in val for c in russian_only):
  33. leaks.append((f"{path} [ua]", val))
  34. else:
  35. # Continue deeper into the structure
  36. for k, v in data.items():
  37. leaks.extend(find_leaks(v, f"{path}.{k}" if path else k))
  38. return leaks
  39. def run_check(master_path, name):
  40. print(f"\n--- Checking for leaks in {name} ({master_path.name}) ---")
  41. if not master_path.exists():
  42. print(f"Error: {master_path} not found.")
  43. return
  44. with open(master_path, "r", encoding="utf-8") as f:
  45. data = json.load(f)
  46. leaks = find_leaks(data)
  47. if not leaks:
  48. print("Success: No language leaks found!")
  49. else:
  50. for p, val in leaks:
  51. print(f"Leak found at {p}: {val}")
  52. if __name__ == "__main__":
  53. run_check(USER_MASTER, "User Translations")
  54. run_check(ADMIN_MASTER, "Admin Translations")