import json import os import sys from pathlib import Path LOCALES_DIR = Path("src/locales") USER_MASTER = LOCALES_DIR / "translations.user.json" ADMIN_MASTER = LOCALES_DIR / "translations.admin.json" LANGUAGES = ["en", "me", "ru", "ua"] def get_nested_keys(data, prefix=""): keys = {} for k, v in data.items(): new_prefix = f"{prefix}.{k}" if prefix else k if isinstance(v, dict): # Check if this is a leaf node with language keys if any(lang in v for lang in LANGUAGES): keys[new_prefix] = v else: keys.update(get_nested_keys(v, new_prefix)) else: keys[new_prefix] = v return keys def set_nested_key(data, key_path, value): parts = key_path.split('.') for part in parts[:-1]: data = data.setdefault(part, {}) data[parts[-1]] = value def _merge_files(master_file, suffix): """Generic merge from {lang}{suffix} into master_file""" master_data = {} all_keys = set() locale_data = {} for lang in LANGUAGES: path = LOCALES_DIR / f"{lang}{suffix}" if path.exists(): with open(path, "r", encoding="utf-8") as f: data = json.load(f) flat = {} def flatten(d, prefix=""): for k, v in d.items(): new_prefix = f"{prefix}.{k}" if prefix else k if isinstance(v, dict): flatten(v, new_prefix) else: flat[new_prefix] = v flatten(data) locale_data[lang] = flat all_keys.update(flat.keys()) for key in sorted(all_keys): translations = {} for lang in LANGUAGES: translations[lang] = locale_data.get(lang, {}).get(key, "") set_nested_key(master_data, key, translations) with open(master_file, "w", encoding="utf-8") as f: json.dump(master_data, f, ensure_ascii=False, indent=2) print(f"Merged {suffix} files into {master_file}") def _split_master(master_file, suffix): """Generic split from master_file into {lang}{suffix}""" if not master_file.exists(): print(f"Warning: {master_file} not found, skipping split for it.") return with open(master_file, "r", encoding="utf-8") as f: master_data = json.load(f) for lang in LANGUAGES: lang_data = {} def unflatten(d, target, current_lang): for k, v in d.items(): if isinstance(v, dict): if any(l in v for l in LANGUAGES): target[k] = v.get(current_lang, "") else: target[k] = {} unflatten(v, target[k], current_lang) else: target[k] = v unflatten(master_data, lang_data, lang) output_path = LOCALES_DIR / f"{lang}{suffix}" with open(output_path, "w", encoding="utf-8") as f: json.dump(lang_data, f, ensure_ascii=False, indent=2) print(f"Generated {output_path}") def merge(): """Merge individual JSON files into respective master files""" _merge_files(USER_MASTER, ".json") _merge_files(ADMIN_MASTER, ".admin.json") def split(): """Split master files into individual JSON files""" _split_master(USER_MASTER, ".json") _split_master(ADMIN_MASTER, ".admin.json") def list_missing(): """List all keys with missing translations in both master files""" for name, path in [("User", USER_MASTER), ("Admin", ADMIN_MASTER)]: if not path.exists(): continue print(f"\n--- Missing in {name} ---") with open(path, "r", encoding="utf-8") as f: data = json.load(f) flat_keys = get_nested_keys(data) missing_found = False for key, trans in sorted(flat_keys.items()): if isinstance(trans, dict): missing = [l for l in LANGUAGES if not trans.get(l)] if missing: print(f"Key: {key} - Missing: {', '.join(missing)}") missing_found = True if not missing_found: print("Everything translated!") if __name__ == "__main__": if len(sys.argv) < 2: print("Usage: python manage_locales.py [merge|split|missing]") sys.exit(1) cmd = sys.argv[1].lower() if cmd == "merge": merge() elif cmd == "split": split() elif cmd == "missing": list_missing() else: print(f"Unknown command: {cmd}")