manage_locales.py 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134
  1. import json
  2. import os
  3. import sys
  4. from pathlib import Path
  5. LOCALES_DIR = Path("src/locales")
  6. USER_MASTER = LOCALES_DIR / "translations.user.json"
  7. ADMIN_MASTER = LOCALES_DIR / "translations.admin.json"
  8. LANGUAGES = ["en", "me", "ru", "ua"]
  9. def get_nested_keys(data, prefix=""):
  10. keys = {}
  11. for k, v in data.items():
  12. new_prefix = f"{prefix}.{k}" if prefix else k
  13. if isinstance(v, dict):
  14. # Check if this is a leaf node with language keys
  15. if any(lang in v for lang in LANGUAGES):
  16. keys[new_prefix] = v
  17. else:
  18. keys.update(get_nested_keys(v, new_prefix))
  19. else:
  20. keys[new_prefix] = v
  21. return keys
  22. def set_nested_key(data, key_path, value):
  23. parts = key_path.split('.')
  24. for part in parts[:-1]:
  25. data = data.setdefault(part, {})
  26. data[parts[-1]] = value
  27. def _merge_files(master_file, suffix):
  28. """Generic merge from {lang}{suffix} into master_file"""
  29. master_data = {}
  30. all_keys = set()
  31. locale_data = {}
  32. for lang in LANGUAGES:
  33. path = LOCALES_DIR / f"{lang}{suffix}"
  34. if path.exists():
  35. with open(path, "r", encoding="utf-8") as f:
  36. data = json.load(f)
  37. flat = {}
  38. def flatten(d, prefix=""):
  39. for k, v in d.items():
  40. new_prefix = f"{prefix}.{k}" if prefix else k
  41. if isinstance(v, dict):
  42. flatten(v, new_prefix)
  43. else:
  44. flat[new_prefix] = v
  45. flatten(data)
  46. locale_data[lang] = flat
  47. all_keys.update(flat.keys())
  48. for key in sorted(all_keys):
  49. translations = {}
  50. for lang in LANGUAGES:
  51. translations[lang] = locale_data.get(lang, {}).get(key, "")
  52. set_nested_key(master_data, key, translations)
  53. with open(master_file, "w", encoding="utf-8") as f:
  54. json.dump(master_data, f, ensure_ascii=False, indent=2)
  55. print(f"Merged {suffix} files into {master_file}")
  56. def _split_master(master_file, suffix):
  57. """Generic split from master_file into {lang}{suffix}"""
  58. if not master_file.exists():
  59. print(f"Warning: {master_file} not found, skipping split for it.")
  60. return
  61. with open(master_file, "r", encoding="utf-8") as f:
  62. master_data = json.load(f)
  63. for lang in LANGUAGES:
  64. lang_data = {}
  65. def unflatten(d, target, current_lang):
  66. for k, v in d.items():
  67. if isinstance(v, dict):
  68. if any(l in v for l in LANGUAGES):
  69. target[k] = v.get(current_lang, "")
  70. else:
  71. target[k] = {}
  72. unflatten(v, target[k], current_lang)
  73. else:
  74. target[k] = v
  75. unflatten(master_data, lang_data, lang)
  76. output_path = LOCALES_DIR / f"{lang}{suffix}"
  77. with open(output_path, "w", encoding="utf-8") as f:
  78. json.dump(lang_data, f, ensure_ascii=False, indent=2)
  79. print(f"Generated {output_path}")
  80. def merge():
  81. """Merge individual JSON files into respective master files"""
  82. _merge_files(USER_MASTER, ".json")
  83. _merge_files(ADMIN_MASTER, ".admin.json")
  84. def split():
  85. """Split master files into individual JSON files"""
  86. _split_master(USER_MASTER, ".json")
  87. _split_master(ADMIN_MASTER, ".admin.json")
  88. def list_missing():
  89. """List all keys with missing translations in both master files"""
  90. for name, path in [("User", USER_MASTER), ("Admin", ADMIN_MASTER)]:
  91. if not path.exists():
  92. continue
  93. print(f"\n--- Missing in {name} ---")
  94. with open(path, "r", encoding="utf-8") as f:
  95. data = json.load(f)
  96. flat_keys = get_nested_keys(data)
  97. missing_found = False
  98. for key, trans in sorted(flat_keys.items()):
  99. if isinstance(trans, dict):
  100. missing = [l for l in LANGUAGES if not trans.get(l)]
  101. if missing:
  102. print(f"Key: {key} - Missing: {', '.join(missing)}")
  103. missing_found = True
  104. if not missing_found:
  105. print("Everything translated!")
  106. if __name__ == "__main__":
  107. if len(sys.argv) < 2:
  108. print("Usage: python manage_locales.py [merge|split|missing]")
  109. sys.exit(1)
  110. cmd = sys.argv[1].lower()
  111. if cmd == "merge":
  112. merge()
  113. elif cmd == "split":
  114. split()
  115. elif cmd == "missing":
  116. list_missing()
  117. else:
  118. print(f"Unknown command: {cmd}")