First Commit

This commit is contained in:
marco
2026-09-01 10:46:29 -03:00
commit bf96b77e9c
10000 changed files with 3508600 additions and 0 deletions
+101
View File
@@ -0,0 +1,101 @@
import os
import json
import glob
APP_PATH = r'c:\Dockers\dockersyscms\app'
MODULES_PATH = os.path.join(APP_PATH, 'modules')
def get_module_locales():
locales = {}
# Find all json files in modules/*/locales/*/*.json
pattern = os.path.join(MODULES_PATH, '*', 'locales', '*', '*.json')
files = glob.glob(pattern)
for file_path in files:
# Extract module, lang, filename
parts = file_path.split(os.sep)
# .../modules/{module}/locales/{lang}/{filename}.json
try:
locales_index = parts.index('locales')
module = parts[locales_index - 1]
lang = parts[locales_index + 1]
filename = parts[locales_index + 2]
key = f"{module}/{filename}"
if key not in locales:
locales[key] = {}
locales[key][lang] = file_path
except ValueError:
continue
return locales
def load_json(path):
try:
with open(path, 'r', encoding='utf-8') as f:
return json.load(f)
except Exception as e:
print(f"Error reading {path}: {e}")
return {}
def flatten_keys(data, prefix=""):
keys = set()
if isinstance(data, dict):
for k, v in data.items():
full_key = f"{prefix}.{k}" if prefix else k
keys.add(full_key)
if isinstance(v, dict):
keys.update(flatten_keys(v, full_key))
return keys
def get_value_by_key(data, key):
parts = key.split('.')
curr = data
for part in parts:
if isinstance(curr, dict) and part in curr:
curr = curr[part]
else:
return None
return curr
def analyze_locales():
groups = get_module_locales()
report = {}
for group_key, langs in groups.items():
# Load all data
data_by_lang = {lang: load_json(path) for lang, path in langs.items()}
# Collect all unique keys
all_keys = set()
for data in data_by_lang.values():
all_keys.update(flatten_keys(data))
# Check for missing
group_report = {}
for lang, data in data_by_lang.items():
missing = []
for key in all_keys:
if get_value_by_key(data, key) is None:
# Find a fallback value from another language
fallback = None
for other_lang in ['en_US', 'pt_BR', 'es_ES', 'de_DE', 'fr_FR']:
if other_lang in data_by_lang:
val = get_value_by_key(data_by_lang[other_lang], key)
if val is not None:
fallback = val
break
missing.append({'key': key, 'fallback': fallback})
if missing:
group_report[lang] = missing
if group_report:
report[group_key] = group_report
return report
if __name__ == "__main__":
report = analyze_locales()
print(json.dumps(report, indent=2, ensure_ascii=False))
+261
View File
@@ -0,0 +1,261 @@
import os
import json
import glob
import copy
APP_PATH = r'c:\Dockers\dockersyscms\app'
MODULES_PATH = os.path.join(APP_PATH, 'modules')
# Simple dictionary for common terms to attempt basic translation
COMMON_TRANSLATIONS = {
'pt_BR': {
'save': 'Salvar', 'cancel': 'Cancelar', 'edit': 'Editar', 'delete': 'Excluir',
'name': 'Nome', 'description': 'Descrição', 'title': 'Título', 'actions': 'Ações',
'create': 'Criar', 'update': 'Atualizar', 'back': 'Voltar', 'view': 'Visualizar',
'home': 'Início', 'dashboard': 'Painel', 'login': 'Entrar', 'register': 'Cadastrar',
'email': 'E-mail', 'password': 'Senha', 'logout': 'Sair', 'profile': 'Perfil',
'search': 'Buscar', 'filter': 'Filtrar', 'reset': 'Limpar', 'status': 'Status',
'active': 'Ativo', 'inactive': 'Inativo', 'yes': 'Sim', 'no': 'Não',
'success': 'Sucesso', 'error': 'Erro', 'warning': 'Aviso', 'info': 'Info',
'confirm': 'Confirmar', 'close': 'Fechar', 'image': 'Imagem', 'file': 'Arquivo',
'date': 'Data', 'author': 'Autor', 'category': 'Categoria', 'categories': 'Categorias',
'post': 'Post', 'posts': 'Posts', 'comment': 'Comentário', 'comments': 'Comentários',
'user': 'Usuário', 'users': 'Usuários', 'role': 'Função', 'roles': 'Funções',
'permission': 'Permissão', 'permissions': 'Permissões', 'settings': 'Configurações'
},
'en_US': {
'save': 'Save', 'cancel': 'Cancel', 'edit': 'Edit', 'delete': 'Delete',
'name': 'Name', 'description': 'Description', 'title': 'Title', 'actions': 'Actions',
'create': 'Create', 'update': 'Update', 'back': 'Back', 'view': 'View',
'home': 'Home', 'dashboard': 'Dashboard', 'login': 'Login', 'register': 'Register',
'email': 'Email', 'password': 'Password', 'logout': 'Logout', 'profile': 'Profile',
'search': 'Search', 'filter': 'Filter', 'reset': 'Reset', 'status': 'Status',
'active': 'Active', 'inactive': 'Inactive', 'yes': 'Yes', 'no': 'No',
'success': 'Success', 'error': 'Error', 'warning': 'Warning', 'info': 'Info',
'confirm': 'Confirm', 'close': 'Close', 'image': 'Image', 'file': 'File',
'date': 'Date', 'author': 'Author', 'category': 'Category', 'categories': 'Categories',
'post': 'Post', 'posts': 'Posts', 'comment': 'Comment', 'comments': 'Comments',
'user': 'User', 'users': 'Users', 'role': 'Role', 'roles': 'Roles',
'permission': 'Permission', 'permissions': 'Permissions', 'settings': 'Settings'
},
'es_ES': {
'save': 'Guardar', 'cancel': 'Cancelar', 'edit': 'Editar', 'delete': 'Eliminar',
'name': 'Nombre', 'description': 'Descripción', 'title': 'Título', 'actions': 'Acciones',
'create': 'Crear', 'update': 'Actualizar', 'back': 'Volver', 'view': 'Ver',
'home': 'Inicio', 'dashboard': 'Tablero', 'login': 'Iniciar sesión', 'register': 'Registrarse',
'email': 'Correo', 'password': 'Contraseña', 'logout': 'Cerrar sesión', 'profile': 'Perfil',
'search': 'Buscar', 'filter': 'Filtrar', 'reset': 'Restablecer', 'status': 'Estado',
'active': 'Activo', 'inactive': 'Inactivo', 'yes': 'Sí', 'no': 'No',
'success': 'Éxito', 'error': 'Error', 'warning': 'Advertencia', 'info': 'Info',
'confirm': 'Confirmar', 'close': 'Cerrar', 'image': 'Imagen', 'file': 'Archivo',
'date': 'Fecha', 'author': 'Autor', 'category': 'Categoría', 'categories': 'Categorías',
'post': 'Publicación', 'posts': 'Publicaciones', 'comment': 'Comentario', 'comments': 'Comentarios',
'user': 'Usuario', 'users': 'Usuarios', 'role': 'Rol', 'roles': 'Roles',
'permission': 'Permiso', 'permissions': 'Permisos', 'settings': 'Configuraciones'
},
'de_DE': {
'save': 'Speichern', 'cancel': 'Abbrechen', 'edit': 'Bearbeiten', 'delete': 'Löschen',
'name': 'Name', 'description': 'Beschreibung', 'title': 'Titel', 'actions': 'Aktionen',
'create': 'Erstellen', 'update': 'Aktualisieren', 'back': 'Zurück', 'view': 'Ansehen',
'home': 'Startseite', 'dashboard': 'Dashboard', 'login': 'Anmelden', 'register': 'Registrieren',
'email': 'E-Mail', 'password': 'Passwort', 'logout': 'Abmelden', 'profile': 'Profil',
'search': 'Suchen', 'filter': 'Filtern', 'reset': 'Zurücksetzen', 'status': 'Status',
'active': 'Aktiv', 'inactive': 'Inaktiv', 'yes': 'Ja', 'no': 'Nein',
'success': 'Erfolg', 'error': 'Fehler', 'warning': 'Warnung', 'info': 'Info',
'confirm': 'Bestätigen', 'close': 'Schließen', 'image': 'Bild', 'file': 'Datei',
'date': 'Datum', 'author': 'Autor', 'category': 'Kategorie', 'categories': 'Kategorien',
'post': 'Beitrag', 'posts': 'Beiträge', 'comment': 'Kommentar', 'comments': 'Kommentare',
'user': 'Benutzer', 'users': 'Benutzer', 'role': 'Rolle', 'roles': 'Rollen',
'permission': 'Berechtigung', 'permissions': 'Berechtigungen', 'settings': 'Einstellungen'
},
'fr_FR': {
'save': 'Enregistrer', 'cancel': 'Annuler', 'edit': 'Modifier', 'delete': 'Supprimer',
'name': 'Nom', 'description': 'Description', 'title': 'Titre', 'actions': 'Actions',
'create': 'Créer', 'update': 'Mettre à jour', 'back': 'Retour', 'view': 'Voir',
'home': 'Accueil', 'dashboard': 'Tableau de bord', 'login': 'Connexion', 'register': 'S\'inscrire',
'email': 'E-mail', 'password': 'Mot de passe', 'logout': 'Déconnexion', 'profile': 'Profil',
'search': 'Rechercher', 'filter': 'Filtrer', 'reset': 'Réinitialiser', 'status': 'Statut',
'active': 'Actif', 'inactive': 'Inactif', 'yes': 'Oui', 'no': 'Non',
'success': 'Succès', 'error': 'Erreur', 'warning': 'Attention', 'info': 'Info',
'confirm': 'Confirmer', 'close': 'Fermer', 'image': 'Image', 'file': 'Fichier',
'date': 'Date', 'author': 'Auteur', 'category': 'Catégorie', 'categories': 'Catégories',
'post': 'Article', 'posts': 'Articles', 'comment': 'Commentaire', 'comments': 'Commentaires',
'user': 'Utilisateur', 'users': 'Utilisateurs', 'role': 'Rôle', 'roles': 'Rôles',
'permission': 'Permission', 'permissions': 'Permissions', 'settings': 'Paramètres'
}
}
def get_module_locales():
locales = {}
pattern = os.path.join(MODULES_PATH, '*', 'locales', '*', '*.json')
files = glob.glob(pattern)
for file_path in files:
parts = file_path.split(os.sep)
try:
locales_index = parts.index('locales')
module = parts[locales_index - 1]
lang = parts[locales_index + 1]
filename = parts[locales_index + 2]
key = f"{module}/{filename}"
if key not in locales:
locales[key] = {}
locales[key][lang] = file_path
except ValueError:
continue
return locales
def load_json(path):
try:
with open(path, 'r', encoding='utf-8') as f:
return json.load(f)
except Exception as e:
print(f"Error reading {path}: {e}")
return {}
def save_json(path, data):
try:
with open(path, 'w', encoding='utf-8') as f:
json.dump(data, f, indent=4, ensure_ascii=False)
print(f"Updated: {path}")
except Exception as e:
print(f"Error writing {path}: {e}")
def flatten_keys(data, prefix=""):
keys = set()
if isinstance(data, dict):
for k, v in data.items():
full_key = f"{prefix}.{k}" if prefix else k
keys.add(full_key)
if isinstance(v, dict):
keys.update(flatten_keys(v, full_key))
return keys
def get_value_by_key(data, key):
parts = key.split('.')
curr = data
for part in parts:
if isinstance(curr, dict) and part in curr:
curr = curr[part]
else:
return None
return curr
def set_value_by_key(data, key, value):
parts = key.split('.')
curr = data
for i, part in enumerate(parts[:-1]):
if part not in curr:
curr[part] = {}
elif not isinstance(curr[part], dict):
# Conflict: trying to use a string as a dict container
# Convert to dict? No, this structure is invalid if keys conflict.
# But for filling, we assume structure consistency.
# If conflict, we skip or overwrite. Here we skip.
print(f"Warning: Structure conflict for key {key} at {part}")
return
curr = curr[part]
last_part = parts[-1]
curr[last_part] = value
def try_translate_word(word, target_lang):
word_lower = word.lower().replace('_', ' ').strip()
# Check direct match
if word_lower in COMMON_TRANSLATIONS.get('en_US', {}):
# It's an english key?
# Find the key in en_US
for k, v in COMMON_TRANSLATIONS['en_US'].items():
if k == word_lower:
return COMMON_TRANSLATIONS[target_lang].get(k)
# Check if word is in COMMON_TRANSLATIONS for target lang directly (as key)
if word_lower in COMMON_TRANSLATIONS[target_lang]:
return COMMON_TRANSLATIONS[target_lang][word_lower]
return None
def fill_translations():
groups = get_module_locales()
for group_key, langs in groups.items():
print(f"Processing {group_key}...")
# Load all data
data_by_lang = {lang: load_json(path) for lang, path in langs.items()}
# Collect all unique keys
all_keys = set()
for data in data_by_lang.values():
all_keys.update(flatten_keys(data))
# Ensure all 5 langs exist in file list (create if missing)
target_langs = ['en_US', 'pt_BR', 'es_ES', 'de_DE', 'fr_FR']
module_path = os.path.dirname(os.path.dirname(list(langs.values())[0])) # .../locales
for t_lang in target_langs:
if t_lang not in data_by_lang:
# Create empty file
f_path = os.path.join(module_path, t_lang, os.path.basename(list(langs.values())[0]))
os.makedirs(os.path.dirname(f_path), exist_ok=True)
data_by_lang[t_lang] = {}
langs[t_lang] = f_path
# Fill missing
for lang in target_langs:
data = data_by_lang[lang]
modified = False
for key in all_keys:
if get_value_by_key(data, key) is None:
# Find a fallback
fallback_val = None
fallback_lang_source = None
# 1. Try en_US
if 'en_US' in data_by_lang:
val = get_value_by_key(data_by_lang['en_US'], key)
if val is not None:
fallback_val = val
fallback_lang_source = 'en_US'
# 2. Try pt_BR
if fallback_val is None and 'pt_BR' in data_by_lang:
val = get_value_by_key(data_by_lang['pt_BR'], key)
if val is not None:
fallback_val = val
fallback_lang_source = 'pt_BR'
# 3. Any other
if fallback_val is None:
for other in data_by_lang:
val = get_value_by_key(data_by_lang[other], key)
if val is not None:
fallback_val = val
fallback_lang_source = other
break
if fallback_val is not None:
# Try to smart translate simple keys
# Extract the last part of the key as a "word" guess
last_part = key.split('.')[-1]
translated = try_translate_word(last_part, lang)
final_val = translated if translated else fallback_val
# If it's a fallback string and we didn't translate it, maybe prepend [LANG] ?
# User said "complete translations", usually means "don't leave empty".
# Using English/Portuguese as fallback is standard.
set_value_by_key(data, key, final_val)
modified = True
if modified:
save_json(langs[lang], data)
if __name__ == "__main__":
fill_translations()
+55
View File
@@ -0,0 +1,55 @@
import json
import os
LOCK_FILE = 'composer.lock'
OUTPUT_FILE = 'THIRD-PARTY-LICENSES.txt'
def main():
if not os.path.exists(LOCK_FILE):
print(f"Error: {LOCK_FILE} not found.")
return
try:
with open(LOCK_FILE, 'r', encoding='utf-8') as f:
data = json.load(f)
except Exception as e:
print(f"Error reading {LOCK_FILE}: {e}")
return
packages = data.get('packages', [])
packages_dev = data.get('packages-dev', [])
# Combine all packages
all_packages = packages + packages_dev
# Sort by name
all_packages.sort(key=lambda x: x.get('name', '').lower())
with open(OUTPUT_FILE, 'w', encoding='utf-8') as f:
f.write("THIRD-PARTY SOFTWARE NOTICES AND INFORMATION\n")
f.write("============================================\n\n")
f.write("This software includes the following third-party software components:\n\n")
for pkg in all_packages:
name = pkg.get('name', 'Unknown')
version = pkg.get('version', 'Unknown')
licenses = pkg.get('license', [])
license_str = ', '.join(licenses) if licenses else 'Unknown'
# Try to find a URL
url = pkg.get('source', {}).get('url', '')
if not url:
url = pkg.get('dist', {}).get('url', '')
f.write(f"Package: {name}\n")
f.write(f"Version: {version}\n")
f.write(f"License: {license_str}\n")
if url:
f.write(f"URL: {url}\n")
f.write("-" * 80 + "\n")
print(f"Successfully generated {OUTPUT_FILE} with {len(all_packages)} packages.")
if __name__ == '__main__':
main()
+110
View File
@@ -0,0 +1,110 @@
import os
import json
APP_PATH = r'c:\Dockers\dockersyscms\app'
LOCALES_PATH = os.path.join(APP_PATH, 'templates', 'locales')
LANGS = ['pt_BR', 'es_ES', 'de_DE', 'fr_FR']
SOURCE_LANG = 'en_US'
TRANSLATIONS = {
'pt_BR': {
'about': 'Sobre', 'contact': 'Contato', 'services': 'Serviços', 'posts': 'Posts',
'dashboard': 'Painel', 'logout': 'Sair', 'login': 'Entrar', 'register': 'Cadastrar',
'profile': 'Perfil', 'settings': 'Configurações', 'pages': 'Páginas', 'faq': 'FAQ',
'vitrine': 'Vitrine', 'search': {'placeholder': 'Buscar...'}
},
'es_ES': {
'about': 'Sobre', 'contact': 'Contacto', 'services': 'Servicios', 'posts': 'Publicaciones',
'dashboard': 'Tablero', 'logout': 'Cerrar sesión', 'login': 'Iniciar sesión', 'register': 'Registrarse',
'profile': 'Perfil', 'settings': 'Configuraciones', 'pages': 'Páginas', 'faq': 'FAQ',
'vitrine': 'Vitrina', 'search': {'placeholder': 'Buscar...'}
},
'de_DE': {
'about': 'Über', 'contact': 'Kontakt', 'services': 'Dienstleistungen', 'posts': 'Beiträge',
'dashboard': 'Dashboard', 'logout': 'Abmelden', 'login': 'Anmelden', 'register': 'Registrieren',
'profile': 'Profil', 'settings': 'Einstellungen', 'pages': 'Seiten', 'faq': 'FAQ',
'vitrine': 'Vitrine', 'search': {'placeholder': 'Suchen...'}
},
'fr_FR': {
'about': 'À propos', 'contact': 'Contact', 'services': 'Services', 'posts': 'Articles',
'dashboard': 'Tableau de bord', 'logout': 'Déconnexion', 'login': 'Connexion', 'register': 'S\'inscrire',
'profile': 'Profil', 'settings': 'Paramètres', 'pages': 'Pages', 'faq': 'FAQ',
'vitrine': 'Vitrine', 'search': {'placeholder': 'Rechercher...'}
}
}
def load_json(path):
try:
with open(path, 'r', encoding='utf-8') as f:
return json.load(f)
except Exception as e:
print(f"Error reading {path}: {e}")
return {}
def save_json(path, data):
try:
with open(path, 'w', encoding='utf-8') as f:
json.dump(data, f, indent=4, ensure_ascii=False)
print(f"Updated: {path}")
except Exception as e:
print(f"Error writing {path}: {e}")
def update_recursive(source, target, lang_code, key_prefix=''):
modified = False
for k, v in source.items():
if k not in target:
# Key missing in target
print(f"Missing key in {lang_code}: {key_prefix}{k}")
if isinstance(v, dict):
target[k] = {}
update_recursive(v, target[k], lang_code, f"{key_prefix}{k}.")
else:
# Try to translate
trans = None
# Check explicit translations map
if lang_code in TRANSLATIONS:
# Try direct key match
if k in TRANSLATIONS[lang_code]:
val = TRANSLATIONS[lang_code][k]
if isinstance(val, str):
trans = val
# Try nested map if v is simple string but we mapped a dict? No, v is string here.
if trans is None:
# Use source value (fallback)
trans = v
target[k] = trans
modified = True
elif isinstance(v, dict):
if not isinstance(target[k], dict):
# Conflict
print(f"Conflict at {key_prefix}{k}")
continue
if update_recursive(v, target[k], lang_code, f"{key_prefix}{k}."):
modified = True
return modified
def sync_layout():
source_path = os.path.join(LOCALES_PATH, SOURCE_LANG, 'layout.json')
source_data = load_json(source_path)
if not source_data:
print("Source file not found or empty.")
return
for lang in LANGS:
target_path = os.path.join(LOCALES_PATH, lang, 'layout.json')
target_data = load_json(target_path)
# We need to preserve existing data but add missing keys from source
if update_recursive(source_data, target_data, lang):
save_json(target_path, target_data)
else:
print(f"No changes for {lang}")
if __name__ == "__main__":
sync_layout()