spun off the translation into its own thing that works with anything

This commit is contained in:
WhatDidYouExpect 2025-07-06 21:06:04 +02:00
parent cd6ce96b36
commit b89390e713
18 changed files with 248 additions and 80 deletions

View file

@ -1,7 +1,7 @@
import requests
import os
import modules.globalvars as gv
from modules.translations import _
from modules.volta.main import _
from modules.markovmemory import get_file_info
# Ping the server to check if it's alive and send some info

View file

@ -3,7 +3,7 @@ import json
import markovify
import pickle
from modules.globalvars import *
from modules.translations import _
from modules.volta.main import _
# Get file size and line count for a given file path
def get_file_info(file_path):

View file

@ -1,12 +1,16 @@
from modules.globalvars import *
from modules.translations import _
from modules.volta.main import _, get_translation, load_translations, set_language, translations
import time
import os
import sys
import subprocess
import sysconfig
import ast
import json
import re
import importlib.metadata
# import shutil
psutilavaliable = True
try:
@ -16,30 +20,56 @@ except ImportError:
psutilavaliable = False
print(RED, _('missing_requests_psutil'), RESET)
def check_missing_translations():
if LOCALE == "en":
print("Locale is English, skipping missing key check.")
return
load_translations()
import re
import importlib.metadata
en_keys = set(translations.get("en", {}).keys())
locale_keys = set(translations.get(LOCALE, {}).keys())
missing_keys = en_keys - locale_keys
total_keys = len(en_keys)
missing_count = len(missing_keys)
if missing_count > 0:
percent_missing = (missing_count / total_keys) * 100
print(f"{YELLOW}Warning: {missing_count}/{total_keys} keys missing in locale '{LOCALE}' ({percent_missing:.1f}%)!{RESET}")
for key in sorted(missing_keys):
print(f" - {key}")
time.sleep(5)
else:
print("All translation keys present for locale:", LOCALE)
def get_stdlib_modules():
stdlib_path = pathlib.Path(sysconfig.get_paths()['stdlib'])
modules = set()
if hasattr(sys, 'builtin_module_names'):
modules.update(sys.builtin_module_names)
for file in stdlib_path.glob('*.py'):
if file.stem != '__init__':
modules.add(file.stem)
for folder in stdlib_path.iterdir():
if folder.is_dir() and (folder / '__init__.py').exists():
modules.add(folder.name)
for file in stdlib_path.glob('*.*'):
if file.suffix in ('.so', '.pyd'):
modules.add(file.stem)
return modules
def check_requirements():
STD_LIB_MODULES = {
"os", "sys", "time", "ast", "asyncio", "re", "subprocess", "json",
"datetime", "threading", "math", "logging", "functools", "itertools",
"collections", "shutil", "socket", "types", "enum", "pathlib",
"inspect", "traceback", "platform", "typing", "warnings", "email",
"http", "urllib", "argparse", "io", "copy", "pickle", "gzip", "csv",
}
STD_LIB_MODULES = get_stdlib_modules()
PACKAGE_ALIASES = {
"discord": "discord.py",
"better_profanity": "better-profanity",
}
parent_dir = os.path.dirname(os.path.abspath(__file__))
requirements_path = os.path.join(parent_dir, '..', 'requirements.txt')
requirements_path = os.path.abspath(requirements_path)
requirements_path = os.path.abspath(os.path.join(parent_dir, '..', 'requirements.txt'))
if not os.path.exists(requirements_path):
print(f"{RED}{(_('requirements_not_found')).format(path=requirements_path)}{RESET}")
@ -52,7 +82,7 @@ def check_requirements():
if line.strip() and not line.startswith('#')
}
cogs_dir = os.path.abspath(os.path.join(parent_dir, '..', 'cogs'))
cogs_dir = os.path.abspath(os.path.join(parent_dir, '..', 'assets', 'cogs'))
if os.path.isdir(cogs_dir):
for filename in os.listdir(cogs_dir):
if filename.endswith('.py'):
@ -106,7 +136,7 @@ def check_requirements():
"token": gooberTOKEN
}
try:
response = requests.post(VERSION_URL + "/ping", json=payload)
requests.post(VERSION_URL + "/ping", json=payload)
except Exception as e:
print(f"{RED}{(_('failed_to_contact')).format(url=VERSION_URL, error=e)}{RESET}")
sys.exit(1)
@ -247,6 +277,7 @@ def start_checks():
print(f"{YELLOW}{(_('checks_disabled'))}{RESET}")
return
print(_('running_prestart_checks'))
check_missing_translations()
check_requirements()
check_latency()
check_memory()

View file

@ -1,6 +1,6 @@
import re
from modules.globalvars import *
from modules.translations import _
from modules.volta.main import _
import spacy
from spacy.tokens import Doc

View file

@ -1,31 +0,0 @@
import os
import json
import pathlib
from modules.globalvars import RED, RESET, LOCALE
# Load translations at module import
def load_translations():
translations = {}
translations_dir = pathlib.Path(__file__).parent.parent / 'assets' / 'locales'
for filename in os.listdir(translations_dir):
if filename.endswith(".json"):
lang_code = filename.replace(".json", "")
with open(translations_dir / filename, "r", encoding="utf-8") as f:
translations[lang_code] = json.load(f)
return translations
translations = load_translations()
def set_language(lang: str):
global LOCALE
LOCALE = lang if lang in translations else "en"
def get_translation(lang: str, key: str):
lang_translations = translations.get(lang, translations["en"])
if key not in lang_translations:
print(f"{RED}Missing key: {key} in language {lang}{RESET}")
return lang_translations.get(key, key)
def _(key: str) -> str:
return get_translation(LOCALE, key)

View file

@ -2,7 +2,7 @@ import sys
import traceback
import os
from modules.globalvars import RED, RESET, splashtext
from modules.translations import _
from modules.volta.main import _
def handle_exception(exc_type, exc_value, exc_traceback, *, context=None):
os.system('cls' if os.name == 'nt' else 'clear')

View file

@ -1,4 +1,4 @@
from modules.translations import _
from modules.volta.main import _
from modules.globalvars import *
import requests
import subprocess
@ -18,18 +18,18 @@ def is_remote_ahead(branch='main', remote='origin'):
# Automatically update the local repository if the remote is ahead
def auto_update(branch='main', remote='origin'):
if launched == True:
print((_('already_started')))
print(_("already_started"))
return
if AUTOUPDATE != "True":
pass # Auto-update is disabled
if is_remote_ahead(branch, remote):
print((_('remote_ahead')).format(remote=remote, branch=branch))
print(_( "remote_ahead").format(remote=remote, branch=branch))
pull_result = run_cmd(f'git pull {remote} {branch}')
print(pull_result)
print((_('please_restart')))
print(_( "please_restart"))
sys.exit(0)
else:
print((_('local_ahead')).format(remote=remote, branch=branch))
print(_( "local_ahead").format(remote=remote, branch=branch))
# Fetch the latest version info from the update server
def get_latest_version_info():
@ -38,23 +38,21 @@ def get_latest_version_info():
if response.status_code == 200:
return response.json()
else:
print(f"{RED}{(_('version_error'))} {response.status_code}{RESET}")
print(f"{RED}{_( 'version_error')} {response.status_code}{RESET}")
return None
except requests.RequestException as e:
print(f"{RED}{(_('version_error'))} {e}{RESET}")
print(f"{RED}{_( 'version_error')} {e}{RESET}")
return None
# Check if an update is available and perform update if needed
def check_for_update():
global latest_version, local_version, launched
launched = True
if ALIVEPING != "True":
return # Update check is disabled
return
global latest_version, local_version
latest_version_info = get_latest_version_info()
if not latest_version_info:
print(f"{(_('fetch_update_fail'))}")
print(f"{_('fetch_update_fail')}")
return None, None
latest_version = latest_version_info.get("version")
@ -62,20 +60,24 @@ def check_for_update():
download_url = latest_version_info.get("download_url")
if not latest_version or not download_url:
print(f"{RED}{(_('invalid_server'))}{RESET}")
print(f"{RED}{_(LOCALE, 'invalid_server')}{RESET}")
return None, None
# Check if local_version is valid
if local_version == "0.0.0" or None:
print(f"{RED}{(_('cant_find_local_version'))}{RESET}")
print(f"{RED}{_('cant_find_local_version')}{RESET}")
return
# Compare local and latest versions
if local_version < latest_version:
print(f"{YELLOW}{(_('new_version')).format(latest_version=latest_version, local_version=local_version)}{RESET}")
print(f"{YELLOW}{(_('changelog')).format(VERSION_URL=VERSION_URL)}{RESET}")
print(f"{YELLOW}{_('new_version').format(latest_version=latest_version, local_version=local_version)}{RESET}")
print(f"{YELLOW}{_('changelog').format(VERSION_URL=VERSION_URL)}{RESET}")
auto_update()
elif local_version > latest_version and beta == True:
print(f"{YELLOW}You are running an unstable version of Goober, do not expect it to work properly.\nVersion {local_version}{RESET}")
elif local_version > latest_version:
print(f"{YELLOW}{_('modification_warning')}{RESET}")
elif local_version == latest_version:
print(f"{GREEN}{(_('latest_version'))} {local_version}{RESET}")
print(f"{(_('latest_version2')).format(VERSION_URL=VERSION_URL)}\n\n")
print(f"{GREEN}{_('latest_version')} {local_version}{RESET}")
print(f"{_('latest_version2').format(VERSION_URL=VERSION_URL)}\n\n")
return latest_version

93
modules/volta/main.py Normal file
View file

@ -0,0 +1,93 @@
import os
import json
import pathlib
import threading
import time
from dotenv import load_dotenv
from modules.globalvars import RED, RESET
load_dotenv()
LOCALE = os.getenv("locale")
module_dir = pathlib.Path(__file__).parent.parent
working_dir = pathlib.Path.cwd()
EXCLUDE_DIRS = {'.git', '__pycache__'}
locales_dirs = []
def find_locales_dirs(base_path):
found = []
for root, dirs, files in os.walk(base_path):
dirs[:] = [d for d in dirs if d not in EXCLUDE_DIRS]
if 'locales' in dirs:
locales_path = pathlib.Path(root) / 'locales'
found.append(locales_path)
dirs.remove('locales')
return found
locales_dirs.extend(find_locales_dirs(module_dir))
if working_dir != module_dir:
locales_dirs.extend(find_locales_dirs(working_dir))
translations = {}
_file_mod_times = {}
def load_translations():
global translations, _file_mod_times
translations.clear()
_file_mod_times.clear()
for locales_dir in locales_dirs:
for filename in os.listdir(locales_dir):
if filename.endswith(".json"):
lang_code = filename[:-5]
file_path = locales_dir / filename
try:
with open(file_path, "r", encoding="utf-8") as f:
data = json.load(f)
if lang_code not in translations:
translations[lang_code] = {}
translations[lang_code].update(data)
_file_mod_times[(lang_code, file_path)] = file_path.stat().st_mtime
except Exception as e:
print(f"{RED}Failed loading {file_path}: {e}{RESET}")
def reload_if_changed():
while True:
for (lang_code, file_path), last_mtime in list(_file_mod_times.items()):
try:
current_mtime = file_path.stat().st_mtime
if current_mtime != last_mtime:
print(f"{RED}Translation file changed: {file_path}, reloading...{RESET}")
load_translations()
break
except FileNotFoundError:
print(f"{RED}Translation file removed: {file_path}{RESET}")
_file_mod_times.pop((lang_code, file_path), None)
if lang_code in translations:
translations.pop(lang_code, None)
def set_language(lang: str):
global LOCALE
if lang in translations:
LOCALE = lang
else:
print(f"{RED}Language '{lang}' not found, defaulting to 'en'{RESET}")
LOCALE = "en"
def get_translation(lang: str, key: str):
lang_translations = translations.get(lang, {})
if key in lang_translations:
return lang_translations[key]
fallback = translations.get("en", {}).get(key, key)
print(f"{RED}Missing key: '{key}' in language '{lang}', falling back to: '{fallback}'{RESET}")
return fallback
def _(key: str) -> str:
return get_translation(LOCALE, key)
load_translations()
watchdog_thread = threading.Thread(target=reload_if_changed, daemon=True)
watchdog_thread.start()