import struct
import json
import sys
from pathlib import Path
try:
from babel import Locale
except ImportError:
print("Error: babel library not found.")
print("Install it with: pip install babel")
sys.exit(1)
try:
import gi
gi.require_version('GLib', '2.0')
from gi.repository import GLib
except ImportError:
print("Error: PyGObject not found.")
sys.exit(1)
verbose = False
def log(msg):
if verbose:
print(msg)
def read_linguas(linguas_path):
languages = []
with open(linguas_path, "r", encoding="utf-8") as f:
for line in f:
line = line.strip()
if line and not line.startswith("#"):
languages.append(line)
return languages
def normalize_locale_code(lang_code):
locale_map = {"zh_CN": "zh_Hans_CN", "zh_TW": "zh_Hant_TW", "fa_IR": "fa_IR"}
return locale_map.get(lang_code, lang_code)
def get_country_translation(country_code, lang_code):
try:
normalized = normalize_locale_code(lang_code)
if "_" in normalized:
parts = normalized.split("_")
if len(parts) == 3:
locale = Locale(parts[0], script=parts[1], territory=parts[2])
else:
lang, territory = parts[0], parts[1]
locale = Locale(lang, territory=territory)
else:
locale = Locale(normalized)
territory_name = locale.territories.get(country_code.upper())
return territory_name if territory_name else None
except Exception as e:
log(f"Warning: Could not get translation for {country_code} in {lang_code}: {e}")
return None
def build_variant(json_path, linguas_path):
languages = read_linguas(linguas_path)
log(f"Found {len(languages)} languages: {', '.join(languages)}")
with open(json_path, "r", encoding="utf-8") as f:
data = json.load(f)
builder = GLib.VariantBuilder(GLib.VariantType.new("a(ssa{ss}aaa(dd))"))
for feature in data.get("features", []):
country_name = feature.get("N", "")
country_code = feature.get("I", "")
if not country_code:
continue
log(f"Processing: {country_name} ({country_code})")
translations = {}
for lang in languages:
translation = get_country_translation(country_code, lang)
translations[lang] = translation if translation else country_name
coords_raw = feature.get("C", [])
poly_builder = GLib.VariantBuilder(GLib.VariantType.new("aaa(dd)"))
for polygon in coords_raw:
ring_builder = GLib.VariantBuilder(GLib.VariantType.new("aa(dd)"))
for ring in polygon:
point_builder = GLib.VariantBuilder(GLib.VariantType.new("a(dd)"))
for point in ring:
point_builder.add_value(GLib.Variant("(dd)", (float(point[0]), float(point[1]))))
ring_builder.add_value(point_builder.end())
poly_builder.add_value(ring_builder.end())
trans_variant = GLib.Variant("a{ss}", translations)
coords_variant = poly_builder.end()
entry = GLib.Variant.new_tuple(
GLib.Variant("s", country_name),
GLib.Variant("s", country_code),
trans_variant,
coords_variant,
)
builder.add_value(entry)
return builder.end()
def main():
global verbose
linguas_path = "../po/LINGUAS"
json_path = "countries.json.in"
output_path = "../src/countries.gvariant"
if "--verbose" in sys.argv:
verbose = True
sys.argv.remove("--verbose")
if len(sys.argv) > 1:
json_path = sys.argv[1]
if len(sys.argv) > 2:
linguas_path = sys.argv[2]
if len(sys.argv) > 3:
output_path = sys.argv[3]
if not Path(linguas_path).exists():
print(f"Error: LINGUAS file not found at {linguas_path}")
sys.exit(1)
if not Path(json_path).exists():
print(f"Error: JSON file not found at {json_path}")
sys.exit(1)
variant = build_variant(json_path, linguas_path)
data = variant.get_data_as_bytes()
with open(output_path, "wb") as f:
f.write(data.get_data())
print(f"GVariant saved to: {output_path} ({GLib.format_size(data.get_size())})")
if __name__ == "__main__":
main()