| import copy |
| import glob |
| import os |
| import re |
| import sys |
| from collections import defaultdict |
|
|
| import polib |
|
|
| localedir = "katrain/i18n/locales" |
| locales = set(os.listdir(localedir)) |
| print("locales found:", locales) |
|
|
| strings_to_langs = defaultdict(dict) |
| strings_to_keys = defaultdict(dict) |
| lang_to_strings = defaultdict(set) |
|
|
| DEFAULT_LANG = "en" |
| INACTIVE_LANGS = ["es"] |
| errors = False |
|
|
| po = {} |
| pofile = {} |
| todos = defaultdict(list) |
|
|
| for lang in locales: |
| if lang in INACTIVE_LANGS: |
| continue |
| pofile[lang] = os.path.join(localedir, lang, "LC_MESSAGES", "katrain.po") |
| po[lang] = polib.pofile(pofile[lang]) |
| for entry in po[lang].translated_entries(): |
| if "TODO" in entry.comment and "DEPRECATED" not in entry.comment: |
| todos[lang].append(entry) |
| strings_to_langs[entry.msgid][lang] = entry |
| strings_to_keys[entry.msgid][lang] = set(re.findall("{.*?}", entry.msgstr)) |
| if entry.msgid in lang_to_strings[lang]: |
| print("duplicate", entry.msgid, "in", lang, "--> deleting", entry.msgstr) |
| errors = True |
| po[lang].remove(entry) |
| else: |
| lang_to_strings[lang].add(entry.msgid) |
| if todos[lang] and any("todo" in a for a in sys.argv): |
| print(f"========== {lang} has {len(todos[lang])} TODO entries ========== ") |
| for item in todos[lang]: |
| print(item) |
|
|
|
|
| for lang in locales: |
| if lang in INACTIVE_LANGS: |
| continue |
| if lang != DEFAULT_LANG: |
| for msgid in lang_to_strings[lang]: |
| if ( |
| DEFAULT_LANG in strings_to_keys[msgid] |
| and strings_to_keys[msgid][lang] != strings_to_keys[msgid][DEFAULT_LANG] |
| ): |
| print( |
| f"{msgid} has inconstent formatting keys for {lang}: ", |
| strings_to_keys[msgid][lang], |
| "is different from default", |
| strings_to_keys[msgid][DEFAULT_LANG], |
| ) |
| errors = True |
|
|
| for msgid in strings_to_langs.keys() - lang_to_strings[lang]: |
| if lang == DEFAULT_LANG: |
| print("Message id", msgid, "found as ", strings_to_langs[msgid], "but missing in default", DEFAULT_LANG) |
| errors = True |
| elif DEFAULT_LANG in strings_to_langs[msgid]: |
| copied_entry = copy.copy(strings_to_langs[msgid][DEFAULT_LANG]) |
| print("Message id", msgid, "missing in ", lang, "-> Adding it from", DEFAULT_LANG) |
| if copied_entry.comment: |
| copied_entry.comment = f"TODO - {copied_entry.comment}" |
| else: |
| copied_entry.comment = "TODO" |
| po[lang].append(copied_entry) |
| errors = True |
| else: |
| print(f"MISSING IN DEFAULT AND {lang}", msgid) |
| errors = True |
|
|
| for msgid, lang_entries in strings_to_langs.items(): |
| if lang in lang_entries and "TODO" in lang_entries[lang].comment: |
| if any(e.msgstr == lang_entries[lang].msgstr for ll, e in lang_entries.items() if ll != lang): |
| if lang_entries.get(DEFAULT_LANG): |
| todo_comment = ( |
| f"TODO - {lang_entries[DEFAULT_LANG].comment}" if lang_entries[DEFAULT_LANG].comment else "TODO" |
| ) |
| if ( |
| lang_entries[lang].msgstr != lang_entries[DEFAULT_LANG].msgstr |
| or lang_entries[lang].comment.replace("\n", " ") != todo_comment |
| ): |
| print( |
| [ |
| lang_entries[lang].msgstr, |
| lang_entries[DEFAULT_LANG].msgstr, |
| lang_entries[lang].comment, |
| todo_comment, |
| ] |
| ) |
| lang_entries[lang].msgstr = lang_entries[DEFAULT_LANG].msgstr |
| lang_entries[lang].comment = todo_comment |
| print(f"{lang}/{msgid} todo entry updated") |
|
|
| po[lang].save(pofile[lang]) |
| mofile = pofile[lang].replace(".po", ".mo") |
| po[lang].save_as_mofile(mofile) |
| print("Fixed", pofile[lang], "and converted ->", mofile) |
|
|
|
|
| for ext in ["py", "kv"]: |
| lc = 0 |
| for file in glob.glob(f"katrain/*.{ext}") + glob.glob(f"katrain/**/*.{ext}"): |
| with open(file, "r") as f: |
| for i, line in enumerate(f.readlines()): |
| if line.strip(): |
| lc += 1 |
| matches = [m.strip() for m in re.findall(r"i18n._\((.*?)\)", line)] |
| for msgid in matches: |
| stripped_msgid = msgid.strip("\"'") |
| if stripped_msgid and msgid[0] in ['"', "'"] and stripped_msgid not in strings_to_langs: |
| print(f"Missing {msgid} used in code at \t{file}:{i} \t'{line.strip()}'") |
| errors += 1 |
| print(f"Checked {lc} lines of {ext} code for missing i18n entries.") |
| sys.exit(int(errors)) |
|
|