spun off the translation into its own thing that works with anything
This commit is contained in:
parent
cd6ce96b36
commit
b89390e713
18 changed files with 248 additions and 80 deletions
2
.gitignore
vendored
2
.gitignore
vendored
|
@ -9,3 +9,5 @@ venv/
|
||||||
output.png
|
output.png
|
||||||
.vscode/
|
.vscode/
|
||||||
received_memory.json
|
received_memory.json
|
||||||
|
translation_report.txt
|
||||||
|
translationcompleteness.py
|
||||||
|
|
|
@ -25,3 +25,4 @@ by expect (requires goober version 0.11.8 or higher)
|
||||||
|
|
||||||
[LastFM](https://raw.githubusercontent.com/WhatDidYouExpect/goober/refs/heads/main/cogs/webserver.py)
|
[LastFM](https://raw.githubusercontent.com/WhatDidYouExpect/goober/refs/heads/main/cogs/webserver.py)
|
||||||
by expect (no idea what version it needs i've only tried it on 1.0.3)
|
by expect (no idea what version it needs i've only tried it on 1.0.3)
|
||||||
|
- you have to add LASTFM_USERNAME and LASTFM_API_KEY to your .env
|
|
@ -1,4 +1,5 @@
|
||||||
{
|
{
|
||||||
|
"checks_disabled": "Checks are disabled!",
|
||||||
"unhandled_exception": "An unhandled exception occurred. Please report this issue on GitHub.",
|
"unhandled_exception": "An unhandled exception occurred. Please report this issue on GitHub.",
|
||||||
"active_users:": "Active users:",
|
"active_users:": "Active users:",
|
||||||
"spacy_initialized": "spaCy and spacytextblob are ready.",
|
"spacy_initialized": "spaCy and spacytextblob are ready.",
|
||||||
|
|
|
@ -1,4 +1,9 @@
|
||||||
{
|
{
|
||||||
|
"checks_disabled": "Tarkistukset on poistettu käytöstä!",
|
||||||
|
"active_users:": "Aktiiviset käyttäjät:",
|
||||||
|
"spacy_initialized": "spaCy ja spacytextblob ovat valmiita.",
|
||||||
|
"spacy_model_not_found": "spaCy mallia ei löytynyt! Ladataan se....`",
|
||||||
|
"unhandled_exception": "Käsittelemätön virhe tapahtui. Ilmoita tästä GitHubiin.",
|
||||||
"env_file_not_found": ".env faili ei leitud! Palun loo see vajalike muutujatega.",
|
"env_file_not_found": ".env faili ei leitud! Palun loo see vajalike muutujatega.",
|
||||||
"error_fetching_active_users": "Aktiivsete kasutajate hankimisel tekkis viga: {error}",
|
"error_fetching_active_users": "Aktiivsete kasutajate hankimisel tekkis viga: {error}",
|
||||||
"error_sending_alive_ping": "Elusoleku ping'i saatmisel tekkis viga: {error}",
|
"error_sending_alive_ping": "Elusoleku ping'i saatmisel tekkis viga: {error}",
|
|
@ -1,5 +1,16 @@
|
||||||
{
|
{
|
||||||
|
"active_users:": "Aktiiviset käyttäjät:",
|
||||||
|
"cog_fail2": "Moduulin lataaminen epäonnistui:",
|
||||||
|
"command_ran_s": "Info: {interaction.user} suoritti",
|
||||||
|
"error_fetching_active_users": "Aktiivisten käyttäjien hankkimisessa tapahtui ongelma: {error}",
|
||||||
|
"error_sending_alive_ping": "Pingin lähettäminen goober centraliin epäonnistui: {error}",
|
||||||
|
"goober_server_alert": "Viesti goober centralista!\n",
|
||||||
|
"loaded_cog2": "Ladattiin moduuli:",
|
||||||
|
"spacy_initialized": "spaCy ja spacytextblob ovat valmiita.",
|
||||||
|
"spacy_model_not_found": "spaCy mallia ei löytynyt! Ladataan se....`",
|
||||||
|
"checks_disabled": "Tarkistukset on poistettu käytöstä!",
|
||||||
"unhandled_exception": "Käsittelemätön virhe tapahtui. Ilmoita tästä GitHubissa.",
|
"unhandled_exception": "Käsittelemätön virhe tapahtui. Ilmoita tästä GitHubissa.",
|
||||||
|
"active_users": "Aktiiviset käyttäjät",
|
||||||
"env_file_not_found": ".env-tiedostoa ei löytnyt! Luo tiedosto jossa on tarvittavat muuttujat",
|
"env_file_not_found": ".env-tiedostoa ei löytnyt! Luo tiedosto jossa on tarvittavat muuttujat",
|
||||||
"already_started": "Olen jo käynnistynyt! Ei päivitetä...",
|
"already_started": "Olen jo käynnistynyt! Ei päivitetä...",
|
||||||
"please_restart": "Käynnistä uudelleen, hölmö!",
|
"please_restart": "Käynnistä uudelleen, hölmö!",
|
||||||
|
|
|
@ -1,4 +1,53 @@
|
||||||
{
|
{
|
||||||
|
"checks_disabled": "Les vérifications sont désactivées !",
|
||||||
|
"unhandled_exception": "Une exception non gérée est survenue. Merci de rapporter ce problème sur GitHub.",
|
||||||
|
"active_users:": "Utilisateurs actifs :",
|
||||||
|
"spacy_initialized": "spaCy et spacytextblob sont prêts.",
|
||||||
|
"spacy_model_not_found": "Le modèle spaCy est introuvable ! Téléchargement en cours...",
|
||||||
|
"env_file_not_found": "Le fichier .env est introuvable ! Créez-en un avec les variables nécessaires.",
|
||||||
|
"error_fetching_active_users": "Erreur lors de la récupération des utilisateurs actifs : {error}",
|
||||||
|
"error_sending_alive_ping": "Erreur lors de l’envoi du ping actif : {error}",
|
||||||
|
"already_started": "J’ai déjà démarré ! Je ne me mets pas à jour...",
|
||||||
|
"please_restart": "Redémarre, stp !",
|
||||||
|
"local_ahead": "Local {remote}/{branch} est en avance ou à jour. Pas de mise à jour...",
|
||||||
|
"remote_ahead": "Remote {remote}/{branch} est en avance. Mise à jour en cours...",
|
||||||
|
"cant_find_local_version": "Je ne trouve pas la variable local_version ! Ou elle a été modifiée et ce n’est pas un entier !",
|
||||||
|
"running_prestart_checks": "Exécution des vérifications préalables au démarrage...",
|
||||||
|
"continuing_in_seconds": "Reprise dans {seconds} secondes... Appuie sur une touche pour passer.",
|
||||||
|
"missing_requests_psutil": "requests et psutil manquants ! Installe-les avec pip : `pip install requests psutil`",
|
||||||
|
"requirements_not_found": "requirements.txt introuvable à {path}, a-t-il été modifié ?",
|
||||||
|
"warning_failed_parse_imports": "Avertissement : Échec du parsing des imports depuis {filename} : {error}",
|
||||||
|
"cogs_dir_not_found": "Répertoire des cogs introuvable à {path}, scan ignoré.",
|
||||||
|
"std_lib_local_skipped": "LIB STD / LOCAL {package} (vérification sautée)",
|
||||||
|
"ok_installed": "OK",
|
||||||
|
"missing_package": "MANQUANT",
|
||||||
|
"missing_package2": "n’est pas installé",
|
||||||
|
"missing_packages_detected": "Packages manquants détectés :",
|
||||||
|
"telling_goober_central": "Envoi à goober central à {url}",
|
||||||
|
"failed_to_contact": "Impossible de contacter {url} : {error}",
|
||||||
|
"all_requirements_satisfied": "Toutes les dépendances sont satisfaites.",
|
||||||
|
"ping_to": "Ping vers {host} : {latency} ms",
|
||||||
|
"high_latency": "Latence élevée détectée ! Tu pourrais avoir des délais de réponse.",
|
||||||
|
"could_not_parse_latency": "Impossible d’analyser la latence.",
|
||||||
|
"ping_failed": "Ping vers {host} échoué.",
|
||||||
|
"error_running_ping": "Erreur lors du ping : {error}",
|
||||||
|
"memory_usage": "Utilisation mémoire : {used} Go / {total} Go ({percent}%)",
|
||||||
|
"memory_above_90": "Usage mémoire au-dessus de 90% ({percent}%). Pense à libérer de la mémoire.",
|
||||||
|
"total_memory": "Mémoire totale : {total} Go",
|
||||||
|
"used_memory": "Mémoire utilisée : {used} Go",
|
||||||
|
"low_free_memory": "Mémoire libre faible détectée ! Seulement {free} Go disponibles.",
|
||||||
|
"measuring_cpu": "Mesure de l’usage CPU par cœur...",
|
||||||
|
"core_usage": "Cœur {idx} : [{bar}] {usage}%",
|
||||||
|
"total_cpu_usage": "Usage total CPU : {usage}%",
|
||||||
|
"high_avg_cpu": "Moyenne CPU élevée : {usage}%",
|
||||||
|
"really_high_cpu": "Charge CPU vraiment élevée ! Le système pourrait ralentir ou planter.",
|
||||||
|
"memory_file": "Fichier mémoire : {size} Mo",
|
||||||
|
"memory_file_large": "Fichier mémoire de 1 Go ou plus, pense à le nettoyer pour libérer de l’espace.",
|
||||||
|
"memory_file_corrupted": "Fichier mémoire corrompu ! Erreur JSON : {error}",
|
||||||
|
"consider_backup_memory": "Pense à sauvegarder et recréer le fichier mémoire.",
|
||||||
|
"memory_file_encoding": "Problèmes d’encodage du fichier mémoire : {error}",
|
||||||
|
"error_reading_memory": "Erreur lecture fichier mémoire : {error}",
|
||||||
|
"memory_file_not_found": "Fichier mémoire introuvable.",
|
||||||
"modification_warning": "Goober a été modifié ! Toutes les modifications seront perdues lors d'une mise à jour !",
|
"modification_warning": "Goober a été modifié ! Toutes les modifications seront perdues lors d'une mise à jour !",
|
||||||
"reported_version": "Version rapportée :",
|
"reported_version": "Version rapportée :",
|
||||||
"current_hash": "Hachage actuel :",
|
"current_hash": "Hachage actuel :",
|
||||||
|
|
|
@ -1,7 +1,9 @@
|
||||||
{
|
{
|
||||||
|
"checks_disabled": "I controlli sono disabilitati!",
|
||||||
"unhandled_exception": "Si è verificata un'eccezione non gestita. Segnala questo problema su GitHub, per favore.",
|
"unhandled_exception": "Si è verificata un'eccezione non gestita. Segnala questo problema su GitHub, per favore.",
|
||||||
"active_users:": "Utenti attivi:",
|
"active_users:": "Utenti attivi:",
|
||||||
"spacy_initialized": "spaCy e spacytextblob sono pronti.",
|
"spacy_initialized": "spaCy e spacytextblob sono pronti.",
|
||||||
|
"error_fetching_active_users": "Errore nel recupero degli utenti attivi: {error}",
|
||||||
"spacy_model_not_found": "Il modello spaCy non è stato trovato! Lo sto scaricando...",
|
"spacy_model_not_found": "Il modello spaCy non è stato trovato! Lo sto scaricando...",
|
||||||
"env_file_not_found": "Il file .env non è stato trovato! Crea un file con le variabili richieste.",
|
"env_file_not_found": "Il file .env non è stato trovato! Crea un file con le variabili richieste.",
|
||||||
"error fetching_active_users": "Errore nel recupero degli utenti attivi:",
|
"error fetching_active_users": "Errore nel recupero degli utenti attivi:",
|
||||||
|
@ -108,6 +110,7 @@
|
||||||
"command_help_categories_admin": "Amministrazione",
|
"command_help_categories_admin": "Amministrazione",
|
||||||
"command_help_categories_custom": "Comandi personalizzati",
|
"command_help_categories_custom": "Comandi personalizzati",
|
||||||
"command_ran": "Info: {message.author.name} ha eseguito {message.content}",
|
"command_ran": "Info: {message.author.name} ha eseguito {message.content}",
|
||||||
|
"command_ran_s": "Info: {interaction.user} ha eseguito ",
|
||||||
"command_desc_ping": "ping",
|
"command_desc_ping": "ping",
|
||||||
"command_ping_embed_desc": "Latenza del bot:",
|
"command_ping_embed_desc": "Latenza del bot:",
|
||||||
"command_ping_footer": "Richiesto da",
|
"command_ping_footer": "Richiesto da",
|
||||||
|
|
4
bot.py
4
bot.py
|
@ -30,7 +30,7 @@ from better_profanity import profanity
|
||||||
from discord.ext import commands
|
from discord.ext import commands
|
||||||
|
|
||||||
from modules.central import ping_server
|
from modules.central import ping_server
|
||||||
from modules.translations import _
|
from modules.volta.main import _
|
||||||
from modules.markovmemory import *
|
from modules.markovmemory import *
|
||||||
from modules.version import *
|
from modules.version import *
|
||||||
from modules.sentenceprocessing import *
|
from modules.sentenceprocessing import *
|
||||||
|
@ -368,7 +368,7 @@ async def on_message(message: discord.Message) -> None:
|
||||||
|
|
||||||
# Process commands if message starts with a command prefix
|
# Process commands if message starts with a command prefix
|
||||||
if message.content.startswith((f"{PREFIX}talk", f"{PREFIX}mem", f"{PREFIX}help", f"{PREFIX}stats", f"{PREFIX}")):
|
if message.content.startswith((f"{PREFIX}talk", f"{PREFIX}mem", f"{PREFIX}help", f"{PREFIX}stats", f"{PREFIX}")):
|
||||||
print(f"{(_('failed_generate_image')).format(message=message)}")
|
print(f"{(_('command_ran')).format(message=message)}")
|
||||||
await bot.process_commands(message)
|
await bot.process_commands(message)
|
||||||
return
|
return
|
||||||
|
|
||||||
|
|
21
example.env
21
example.env
|
@ -12,14 +12,15 @@ gooberTOKEN=
|
||||||
song="War Without Reason"
|
song="War Without Reason"
|
||||||
POSITIVE_GIFS="https://tenor.com/view/chill-guy-my-new-character-gif-2777893510283028272, https://tenor.com/view/goodnight-goodnight-friends-weezer-weezer-goodnight-gif-7322052181075806988"
|
POSITIVE_GIFS="https://tenor.com/view/chill-guy-my-new-character-gif-2777893510283028272, https://tenor.com/view/goodnight-goodnight-friends-weezer-weezer-goodnight-gif-7322052181075806988"
|
||||||
splashtext="
|
splashtext="
|
||||||
d8b
|
SS\
|
||||||
?88
|
SS |
|
||||||
88b
|
SSSSSS\ SSSSSS\ SSSSSS\ SSSSSSS\ SSSSSS\ SSSSSS\
|
||||||
d888b8b d8888b d8888b 888888b d8888b 88bd88b
|
SS __SS\ SS __SS\ SS __SS\ SS __SS\ SS __SS\ SS __SS\
|
||||||
d8P' ?88 d8P' ?88d8P' ?88 88P `?8bd8b_,dP 88P' `
|
SS / SS |SS / SS |SS / SS |SS | SS |SSSSSSSS |SS | \__|
|
||||||
88b ,88b 88b d8888b d88 d88, d8888b d88
|
SS | SS |SS | SS |SS | SS |SS | SS |SS ____|SS |
|
||||||
`?88P'`88b`?8888P'`?8888P'd88'`?88P'`?888P'd88'
|
\SSSSSSS |\SSSSSS |\SSSSSS |SSSSSSS |\SSSSSSS\ SS |
|
||||||
)88
|
\____SS | \______/ \______/ \_______/ \_______|\__|
|
||||||
,88P
|
SS\ SS |
|
||||||
`?8888P
|
\SSSSSS |
|
||||||
|
\______/
|
||||||
"
|
"
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import requests
|
import requests
|
||||||
import os
|
import os
|
||||||
import modules.globalvars as gv
|
import modules.globalvars as gv
|
||||||
from modules.translations import _
|
from modules.volta.main import _
|
||||||
from modules.markovmemory import get_file_info
|
from modules.markovmemory import get_file_info
|
||||||
|
|
||||||
# Ping the server to check if it's alive and send some info
|
# Ping the server to check if it's alive and send some info
|
||||||
|
|
|
@ -3,7 +3,7 @@ import json
|
||||||
import markovify
|
import markovify
|
||||||
import pickle
|
import pickle
|
||||||
from modules.globalvars import *
|
from modules.globalvars import *
|
||||||
from modules.translations import _
|
from modules.volta.main import _
|
||||||
|
|
||||||
# Get file size and line count for a given file path
|
# Get file size and line count for a given file path
|
||||||
def get_file_info(file_path):
|
def get_file_info(file_path):
|
||||||
|
|
|
@ -1,12 +1,16 @@
|
||||||
from modules.globalvars import *
|
from modules.globalvars import *
|
||||||
from modules.translations import _
|
from modules.volta.main import _, get_translation, load_translations, set_language, translations
|
||||||
|
|
||||||
import time
|
import time
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
import subprocess
|
import subprocess
|
||||||
|
import sysconfig
|
||||||
import ast
|
import ast
|
||||||
import json
|
import json
|
||||||
|
import re
|
||||||
|
import importlib.metadata
|
||||||
|
|
||||||
# import shutil
|
# import shutil
|
||||||
psutilavaliable = True
|
psutilavaliable = True
|
||||||
try:
|
try:
|
||||||
|
@ -16,30 +20,56 @@ except ImportError:
|
||||||
psutilavaliable = False
|
psutilavaliable = False
|
||||||
print(RED, _('missing_requests_psutil'), RESET)
|
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
|
en_keys = set(translations.get("en", {}).keys())
|
||||||
import importlib.metadata
|
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():
|
def check_requirements():
|
||||||
STD_LIB_MODULES = {
|
STD_LIB_MODULES = get_stdlib_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",
|
|
||||||
}
|
|
||||||
PACKAGE_ALIASES = {
|
PACKAGE_ALIASES = {
|
||||||
"discord": "discord.py",
|
"discord": "discord.py",
|
||||||
"better_profanity": "better-profanity",
|
"better_profanity": "better-profanity",
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
parent_dir = os.path.dirname(os.path.abspath(__file__))
|
parent_dir = os.path.dirname(os.path.abspath(__file__))
|
||||||
requirements_path = os.path.join(parent_dir, '..', 'requirements.txt')
|
requirements_path = os.path.abspath(os.path.join(parent_dir, '..', 'requirements.txt'))
|
||||||
requirements_path = os.path.abspath(requirements_path)
|
|
||||||
|
|
||||||
if not os.path.exists(requirements_path):
|
if not os.path.exists(requirements_path):
|
||||||
print(f"{RED}{(_('requirements_not_found')).format(path=requirements_path)}{RESET}")
|
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('#')
|
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):
|
if os.path.isdir(cogs_dir):
|
||||||
for filename in os.listdir(cogs_dir):
|
for filename in os.listdir(cogs_dir):
|
||||||
if filename.endswith('.py'):
|
if filename.endswith('.py'):
|
||||||
|
@ -106,7 +136,7 @@ def check_requirements():
|
||||||
"token": gooberTOKEN
|
"token": gooberTOKEN
|
||||||
}
|
}
|
||||||
try:
|
try:
|
||||||
response = requests.post(VERSION_URL + "/ping", json=payload)
|
requests.post(VERSION_URL + "/ping", json=payload)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f"{RED}{(_('failed_to_contact')).format(url=VERSION_URL, error=e)}{RESET}")
|
print(f"{RED}{(_('failed_to_contact')).format(url=VERSION_URL, error=e)}{RESET}")
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
@ -247,6 +277,7 @@ def start_checks():
|
||||||
print(f"{YELLOW}{(_('checks_disabled'))}{RESET}")
|
print(f"{YELLOW}{(_('checks_disabled'))}{RESET}")
|
||||||
return
|
return
|
||||||
print(_('running_prestart_checks'))
|
print(_('running_prestart_checks'))
|
||||||
|
check_missing_translations()
|
||||||
check_requirements()
|
check_requirements()
|
||||||
check_latency()
|
check_latency()
|
||||||
check_memory()
|
check_memory()
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import re
|
import re
|
||||||
from modules.globalvars import *
|
from modules.globalvars import *
|
||||||
from modules.translations import _
|
from modules.volta.main import _
|
||||||
|
|
||||||
import spacy
|
import spacy
|
||||||
from spacy.tokens import Doc
|
from spacy.tokens import Doc
|
||||||
|
|
|
@ -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)
|
|
|
@ -2,7 +2,7 @@ import sys
|
||||||
import traceback
|
import traceback
|
||||||
import os
|
import os
|
||||||
from modules.globalvars import RED, RESET, splashtext
|
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):
|
def handle_exception(exc_type, exc_value, exc_traceback, *, context=None):
|
||||||
os.system('cls' if os.name == 'nt' else 'clear')
|
os.system('cls' if os.name == 'nt' else 'clear')
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
from modules.translations import _
|
from modules.volta.main import _
|
||||||
from modules.globalvars import *
|
from modules.globalvars import *
|
||||||
import requests
|
import requests
|
||||||
import subprocess
|
import subprocess
|
||||||
|
@ -18,18 +18,18 @@ def is_remote_ahead(branch='main', remote='origin'):
|
||||||
# Automatically update the local repository if the remote is ahead
|
# Automatically update the local repository if the remote is ahead
|
||||||
def auto_update(branch='main', remote='origin'):
|
def auto_update(branch='main', remote='origin'):
|
||||||
if launched == True:
|
if launched == True:
|
||||||
print((_('already_started')))
|
print(_("already_started"))
|
||||||
return
|
return
|
||||||
if AUTOUPDATE != "True":
|
if AUTOUPDATE != "True":
|
||||||
pass # Auto-update is disabled
|
pass # Auto-update is disabled
|
||||||
if is_remote_ahead(branch, remote):
|
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}')
|
pull_result = run_cmd(f'git pull {remote} {branch}')
|
||||||
print(pull_result)
|
print(pull_result)
|
||||||
print((_('please_restart')))
|
print(_( "please_restart"))
|
||||||
sys.exit(0)
|
sys.exit(0)
|
||||||
else:
|
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
|
# Fetch the latest version info from the update server
|
||||||
def get_latest_version_info():
|
def get_latest_version_info():
|
||||||
|
@ -38,23 +38,21 @@ def get_latest_version_info():
|
||||||
if response.status_code == 200:
|
if response.status_code == 200:
|
||||||
return response.json()
|
return response.json()
|
||||||
else:
|
else:
|
||||||
print(f"{RED}{(_('version_error'))} {response.status_code}{RESET}")
|
print(f"{RED}{_( 'version_error')} {response.status_code}{RESET}")
|
||||||
return None
|
return None
|
||||||
except requests.RequestException as e:
|
except requests.RequestException as e:
|
||||||
print(f"{RED}{(_('version_error'))} {e}{RESET}")
|
print(f"{RED}{_( 'version_error')} {e}{RESET}")
|
||||||
return None
|
return None
|
||||||
|
|
||||||
# Check if an update is available and perform update if needed
|
# Check if an update is available and perform update if needed
|
||||||
def check_for_update():
|
def check_for_update():
|
||||||
global latest_version, local_version, launched
|
|
||||||
launched = True
|
|
||||||
if ALIVEPING != "True":
|
if ALIVEPING != "True":
|
||||||
return # Update check is disabled
|
return
|
||||||
|
global latest_version, local_version
|
||||||
|
|
||||||
latest_version_info = get_latest_version_info()
|
latest_version_info = get_latest_version_info()
|
||||||
if not latest_version_info:
|
if not latest_version_info:
|
||||||
print(f"{(_('fetch_update_fail'))}")
|
print(f"{_('fetch_update_fail')}")
|
||||||
return None, None
|
return None, None
|
||||||
|
|
||||||
latest_version = latest_version_info.get("version")
|
latest_version = latest_version_info.get("version")
|
||||||
|
@ -62,20 +60,24 @@ def check_for_update():
|
||||||
download_url = latest_version_info.get("download_url")
|
download_url = latest_version_info.get("download_url")
|
||||||
|
|
||||||
if not latest_version or not 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
|
return None, None
|
||||||
|
|
||||||
# Check if local_version is valid
|
# Check if local_version is valid
|
||||||
if local_version == "0.0.0" or None:
|
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
|
return
|
||||||
|
|
||||||
# Compare local and latest versions
|
# Compare local and latest versions
|
||||||
if local_version < latest_version:
|
if local_version < latest_version:
|
||||||
print(f"{YELLOW}{(_('new_version')).format(latest_version=latest_version, local_version=local_version)}{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}")
|
print(f"{YELLOW}{_('changelog').format(VERSION_URL=VERSION_URL)}{RESET}")
|
||||||
auto_update()
|
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:
|
elif local_version == latest_version:
|
||||||
print(f"{GREEN}{(_('latest_version'))} {local_version}{RESET}")
|
print(f"{GREEN}{_('latest_version')} {local_version}{RESET}")
|
||||||
print(f"{(_('latest_version2')).format(VERSION_URL=VERSION_URL)}\n\n")
|
print(f"{_('latest_version2').format(VERSION_URL=VERSION_URL)}\n\n")
|
||||||
return latest_version
|
return latest_version
|
93
modules/volta/main.py
Normal file
93
modules/volta/main.py
Normal 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()
|
Loading…
Add table
Add a link
Reference in a new issue