#!/usr/bin/env python3
"""
Google-Translate tool: auto-generate 7kaa UI translations for ADDITIONAL
languages from the English source strings, and compile them straight to
.mo catalogs the WASM build loads.

    python gtranslate_po.py it nl sv      # generate Italian, Dutch, Swedish

HARD LIMIT (engine, not this script): 7kaa renders text with bitmap fonts that
only cover Latin-1 / Latin-2 / Latin-3 / Cyrillic. Latin-1 languages
(it,nl,sv,da,no,fi,ca,...) render with the default font. CJK / Arabic / Thai /
Hindi etc. CANNOT render — do not generate those (they'd show blank).

Requires: pip install deep-translator  (uses the free Google endpoint).
"""
import os, sys, re, time, struct

ROOT   = os.path.dirname(os.path.abspath(__file__))
POT    = os.path.join(os.path.dirname(ROOT), "7kaa-2156", "po", "7kaa.pot")
OUT    = os.path.join(ROOT, "locale_build")
# Latin-1 languages that render with 7kaa's default font (safe set):
SAFE_LATIN1 = {"it","nl","sv","da","no","fi","ca","gl","af","id","ms","sw","la"}


def unescape(s):
    out, i = [], 0
    while i < len(s):
        c = s[i]
        if c == '\\' and i+1 < len(s):
            out.append({'n':'\n','t':'\t','r':'\r','"':'"','\\':'\\'}.get(s[i+1], s[i+1])); i += 2
        else:
            out.append(c); i += 1
    return ''.join(out)


def parse_pot_msgids(path):
    ids, cur, mode = [], None, None
    for raw in open(path, encoding='utf-8', errors='replace'):
        line = raw.strip()
        if line.startswith('msgid '):
            if cur is not None and cur != "": ids.append(cur)
            cur = unescape(line[6:].strip().strip('"')); mode='id'
        elif line.startswith('msgstr'):
            if cur is not None and cur != "": ids.append(cur)
            cur = None; mode=None
        elif line.startswith('"') and mode=='id':
            cur = (cur or '') + unescape(line.strip()[1:-1])
    if cur: ids.append(cur)
    # de-dup, keep non-empty, skip format-only tokens
    seen, out = set(), []
    for s in ids:
        if s and s not in seen:
            seen.add(s); out.append(s)
    return out


def write_mo(entries, charset, path):
    keys = sorted(entries.keys())
    ids  = [k.encode(charset, 'replace') for k in keys]
    strs = [entries[k].encode(charset, 'replace') for k in keys]
    n = len(keys); o_keys = 7*4; o_vals = o_keys + n*8; o_str = o_vals + n*8
    out = bytearray(struct.pack('<IIIIIII', 0x950412de,0,n,o_keys,o_vals,0,o_str))
    blob=bytearray(); kt=bytearray(); vt=bytearray()
    for b in ids:  kt += struct.pack('<II', len(b), o_str+len(blob)); blob += b+b'\x00'
    for b in strs: vt += struct.pack('<II', len(b), o_str+len(blob)); blob += b+b'\x00'
    out += kt+vt+blob
    os.makedirs(os.path.dirname(path), exist_ok=True)
    open(path,'wb').write(out)


def gen(lang):
    from deep_translator import GoogleTranslator
    charset = "ISO-8859-1" if lang in SAFE_LATIN1 else "UTF-8"
    if lang not in SAFE_LATIN1:
        print(f"  WARNING: '{lang}' may not render (font covers only Latin/Cyrillic).")
    msgids = parse_pot_msgids(POT)
    print(f"{lang}: translating {len(msgids)} strings via Google…")
    tr = GoogleTranslator(source='en', target=lang)
    entries = {}
    # Char-budget batching: far fewer requests (~6 instead of ~80) -> fast,
    # avoids the free endpoint's rate limit. Google caps ~5000 chars/request.
    batches, cur, curlen = [], [], 0
    for s in msgids:
        L = len(s) + 1
        if cur and curlen + L > 4000:
            batches.append(cur); cur, curlen = [], 0
        cur.append(s); curlen += L
    if cur: batches.append(cur)
    print(f"  {len(batches)} request(s)…", flush=True)
    done = 0
    for bi, batch in enumerate(batches):
        try:
            res = tr.translate_batch(batch)
        except Exception as e:
            print(f"  batch {bi} failed ({repr(e)[:80]}); keeping English", flush=True)
            res = batch
        for src, dst in zip(batch, res):
            if dst: entries[src] = dst
        done += len(batch)
        print(f"  …{done}/{len(msgids)}", flush=True)
        time.sleep(0.5)
    mo = os.path.join(OUT, lang, 'LC_MESSAGES', '7kaa.mo')
    write_mo(entries, charset, mo)
    print(f"{lang}: {len(entries)} strings ({charset}) -> {mo}")


if __name__ == '__main__':
    langs = sys.argv[1:] or ["it"]
    for l in langs:
        gen(l)
    print("done. Add the language to shell.html's <select> and rebuild (build.py link).")
