I18n based in gettext #3

Merged
absurdo merged 4 commits from i18n into master 2025-03-20 23:59:10 +00:00
22 changed files with 503 additions and 288 deletions

View file

@ -1,7 +1,7 @@
#!/usr/bin/env python3
from collections import OrderedDict
from paramecio.libraries.sessions import get_session
from paramecio.libraries.sessionplugin import get_session
from paramecio.libraries.urls import make_url
from paramecio.libraries.i18n import I18n
from paramecio.libraries.httputils import GetPostFiles

View file

@ -42,11 +42,14 @@ def start():
path_save=args.module+'/i18n'
if args.module.endswith('/'):
args.module=args.module[:-1]
module_base=os.path.basename(args.module)
lang_p=re.compile(r"I18n\.lang\('("+module_base+"?)',\s+'(.*?)',\s+'(.*?)'\)")
lang_p=re.compile(r"I18n\.lang\('({}?)',\s+'(.*?)',\s+'(.*?)'\)".format(module_base))
#lang_t=re.compile("\${lang\('("+module_base+"?)',\s+'(.*?)',\s+'(.*?)'\)\}")
lang_t=re.compile(r"lang\('("+module_base+"?)',\s+'(.*?)',\s+'(.*?)'\)")
lang_t=re.compile(r"lang\('({}?)',\s+'(.*?)',\s+'(.*?)'\)".format(module_base))
lang_s=re.compile(r"slang\('(.*?)',\s+'(.*?)'\)")

View file

@ -3,10 +3,14 @@ from bottle import request
from paramecio.libraries.urls import add_get_parameters, redirect
from paramecio.libraries.mtemplates import set_flash_message
from paramecio.libraries.db.formsutils import show_form
from paramecio.libraries.i18n import I18n
from paramecio.libraries.i18n import I18n, PGetText
from paramecio.libraries.httputils import GetPostFiles
from collections import OrderedDict
gtext=PGetText(__file__)
_=gtext.gettext
class GenerateAdminClass:
def __init__(self, model, url, t):
@ -53,7 +57,7 @@ class GenerateAdminClass:
self.post_update=None
self.text_home=I18n.lang('common', 'home', 'Home')
self.text_home=_('Home')
def show(self):
@ -80,13 +84,13 @@ class GenerateAdminClass:
post=None
title_edit=I18n.lang('common', 'add_new_item', 'Add new item')
title_edit=_('Add new item')
pass_value=False
if getpostfiles.get['id']!='0':
post=self.model.select_a_row(getpostfiles.get['id'], [], True)
title_edit=I18n.lang('common', 'edit_new_item', 'Edit item')
title_edit=_('Edit item')
pass_value=True
if post==None or post==False:
@ -120,19 +124,19 @@ class GenerateAdminClass:
getpostfiles.get['id']='0'
title_edit=I18n.lang('common', 'add_new_item', 'Add new item')
title_edit=_('Add new item')
if getpostfiles.get['id']!='0':
insert_row=self.model.update
title_edit=I18n.lang('common', 'edit_new_item', 'Edit item')
title_edit=_('Edit item')
self.model.conditions=['WHERE `'+self.model.name+'`.`'+self.model.name_field_id+'`=%s', [getpostfiles.get['id']]]
if self.pre_update:
getpostfiles.post=self.pre_update(self, getpostfiles.post)
if insert_row(getpostfiles.post):
set_flash_message(I18n.lang('common', 'task_successful', 'Task successful'))
set_flash_message(_('Task successful'))
if self.post_update:
if getpostfiles.get['id']=='0':
@ -158,7 +162,7 @@ class GenerateAdminClass:
if getpostfiles.get['id']!='0':
self.model.conditions=['WHERE `'+self.model.name+'`.`'+self.model.name_field_id+'`=%s', [getpostfiles.get['id']]]
self.model.delete()
set_flash_message(I18n.lang('common', 'task_successful', 'Task successful'))
set_flash_message(_('Task successful'))
redirect(self.url_redirect)
else:
@ -218,7 +222,7 @@ class GenerateConfigClass:
self.post_update=None
self.text_home=I18n.lang('common', 'home', 'Home')
self.text_home=_('Home')
def show(self):
@ -232,7 +236,7 @@ class GenerateConfigClass:
self.model.create_forms()
title_edit=I18n.lang('common', 'edit', 'Edit')+' '+self.title_name
title_edit=_('Edit')+' '+self.title_name
edit_forms=OrderedDict()
@ -257,7 +261,7 @@ class GenerateConfigClass:
insert_model=self.model.update
if insert_model(getpostfiles.post):
set_flash_message(I18n.lang('common', 'task_successful', 'Task successful'))
set_flash_message(_('Task successful'))
self.model.yes_reset_conditions=True
if self.post_update:

View file

@ -1,4 +1,4 @@
from paramecio.libraries.sessions import get_session
from paramecio.libraries.sessionplugin import get_session
from paramecio.libraries.i18n import I18n
from settings import config

View file

@ -3,13 +3,17 @@
from paramecio.libraries.pages import Pages
from paramecio.libraries.urls import add_get_parameters
from paramecio.libraries.sessions import get_session
from paramecio.libraries.i18n import I18n
from paramecio.libraries.i18n import I18n, PGetText
from paramecio.libraries.httputils import GetPostFiles
from bottle import request
import sys
import re
from paramecio.libraries.pages import Pages
gtext=PGetText(__file__)
_=gtext.gettext
class SimpleList:
def __init__(self, model, url, t):
@ -76,7 +80,7 @@ class SimpleList:
#self.yes_options=True
self.arr_extra_fields=[I18n.lang('common', 'options', 'Options')]
self.arr_extra_fields=[_('Options')]
self.arr_extra_options=[SimpleList.standard_options]
@ -167,8 +171,8 @@ class SimpleList:
@staticmethod
def standard_options(url, id, arr_row):
options=[]
options.append('<a href="'+add_get_parameters(url, op_admin=1, id=id)+'">'+I18n.lang('common', 'edit', 'Edit')+'</a>')
options.append('<a href="'+add_get_parameters(url, op_admin=3, id=id)+'">'+I18n.lang('common', 'delete', 'Delete')+'</a>')
options.append('<a href="'+add_get_parameters(url, op_admin=1, id=id)+'">'+_('Edit')+'</a>')
options.append('<a href="'+add_get_parameters(url, op_admin=3, id=id)+'">'+_('Delete')+'</a>')
return options
def show(self):
@ -310,7 +314,7 @@ class AjaxList(SimpleList):
pages=Pages()
html_pages=I18n.lang('cuchulu', 'pages', 'Pages')+': '+pages.show( begin_page, total_elements, limit, '#' ,initial_num_pages=self.initial_num_pages, variable='begin_page', label='', func_jscript='')
html_pages=_('Pages')+': '+pages.show( begin_page, total_elements, limit, '#' ,initial_num_pages=self.initial_num_pages, variable='begin_page', label='', func_jscript='')
with self.db.query(str_query, params) as cursor:
for row in cursor:

View file

@ -33,6 +33,10 @@ from os import path
from collections import OrderedDict
from paramecio.wsgiapp import app
gtext=PGetText(__file__)
_=gtext.gettext
# Preparing envs for views of modules, and views of
def env_theme(module, cache_enabled=True, cache_impl='', cache_args={}, module_directory="./tmp/modules"):
@ -458,7 +462,7 @@ def set_flash_message(message):
s['flash']=message
#s.save()
s.save()
def qf(text):

View file

@ -2,7 +2,11 @@
from math import ceil, floor
from paramecio.libraries.urls import add_get_parameters
from paramecio.libraries.i18n import I18n
from paramecio.libraries.i18n import I18n, PGetText
gtext=PGetText(__file__)
_=gtext.gettext
class Pages:
@ -64,7 +68,7 @@ class Pages:
middle_link=add_get_parameters(link, **{variable: str(x+num_elements)} );
last_link=add_get_parameters(link, **{variable: str( ( ( total_page*num_elements ) - num_elements) ) } )
pages += "<a class=\""+Pages.css_class+"\" href=\""+middle_link+"\" onclick=\"func_jscript\">&gt;&gt;</a> <a class=\"link_pages\" href=\""+last_link+"\" onclick=\"func_jscript\">"+I18n.lang('common', 'last', 'Last')+"</a>"
pages += "<a class=\""+Pages.css_class+"\" href=\""+middle_link+"\" onclick=\"func_jscript\">&gt;&gt;</a> <a class=\"link_pages\" href=\""+last_link+"\" onclick=\"func_jscript\">"+_('Last')+"</a>"
return pages

View file

@ -1,60 +1,30 @@
#!/usr/bin/python
"""
Paramecio2fm is a series of wrappers for Flask, mako and others and construct a simple headless cms.
#A very simple version of strtr of php.
Copyright (C) 2023 Antonio de la Rosa Caballero
def strtr(str_in, pat_str, rep_str):
ret_str=''
arr_dict={}
if(len(pat_str)!=len(rep_str)):
raise NameError('Ups, pat_str len != rep_str len')
#Create dictionary
for (i, l) in enumerate(pat_str):
arr_dict[l]=rep_str[i]
#Make a for to the str_in and substr.
for le in str_in:
if le in arr_dict:
ret_str+=arr_dict[le]
else:
ret_str+=le
return (ret_str)
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
def slugify(str_in, respect_upper=False, replace_space='-', replace_dot=False, replace_barr=False):
str_out=''
from_str='àáâãäåæçèéêëìíîïðòóôõöøùúûýþÿŕñÀÁÂÃÄÅÇÈÉÊËÌÍÎÏÐÒÓÔÕÖØÙÚÛÝỲŸÞŔÑ¿?!¡()"|#*%,;+&$ºª<>`çÇ{}@~=^:´[]\''
to_str= 'aaaaaaaceeeeiiiidoooooouuuybyrnAAAAAACEEEEIIIIDOOOOOOUUUYYYBRN----------------------------------'
if replace_dot==True:
from_str+='.'
from_to+='-'
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
if replace_barr==True:
from_str+="/"
to_str+="-"
str_out=str_in.strip()
str_out=strtr(str_out, from_str, to_str)
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
"""
str_out=str_out.replace(" ", replace_space)
if respect_upper==False:
str_out=str_out.lower()
return str_out
from slugify import slugify as slugify_func
def slugify(slug, *args, **wargs):
"""Simple wrapper for slugify module https://github.com/un33k/python-slugify
Args:
slug (str): The string to be slugified
"""
return slugify_func(slug, *args, **wargs)

View file

@ -1,6 +1,6 @@
#from paramecio import wsgi_app
from paramecio.libraries.i18n import I18n
from paramecio.libraries.i18n import I18n, PGetText
from paramecio.libraries.mtemplates import env_theme, PTemplate
from paramecio.modules.admin2.models.admin import UserAdmin2, LoginTries2, PrivilegesModule2
from paramecio.libraries.db.webmodel import WebModel
@ -28,6 +28,10 @@ admin_app.install(check_login)
env=env_theme(__file__)
t=PTemplate(env)
gtext=PGetText(__file__)
_=gtext.gettext
usermodel=UserAdmin2()
usermodel.create_forms()
@ -64,9 +68,9 @@ def home_admin(session={}):
#s=get_session()
i18n=I18n('admin2')
#i18n=I18n('admin2')
return t.load_template('layout.phtml', title=i18n.tlang('Admin'), module_selected='home_admin', session=session)
return t.load_template('layout.phtml', title=_('Admin'), module_selected='home_admin', session=session)
#return {}
@ -99,9 +103,9 @@ def login_admin(session={}):
db.close()
i18n=I18n('admin2')
#i18n=I18n('admin2')
return t.load_template('login.phtml', title=i18n.tlang('Login'))
return t.load_template('login.phtml', title=_('Login'))
@admin_app.get('/signup', skip=[check_login], name='admin_app.signup_admin')
def signup_admin(session={}):
@ -116,20 +120,20 @@ def signup_admin(session={}):
db.close()
i18n=I18n('admin2')
#i18n=I18n('admin2')
return t.load_template('signup.phtml', title=i18n.tlang('Signup'))
return t.load_template('signup.phtml', title=_('Signup'))
@admin_app.post('/login', skip=[check_login], name='admin_app.check_login_admin')
def check_login_admin(session={}):
db=WebModel.connection()
i18n=I18n('admin2')
#i18n=I18n('admin2')
error=1
message=i18n.tlang('Invalid user and password')
message=_('Invalid user and password')
no_login=check_login_tries(request, db)
@ -179,21 +183,21 @@ def check_login_admin(session={}):
sendmail=SendMail(ssl=True)
sendmail.send(config.portal_email, [result['email']], i18n.tlang('Code for complete login'), i18n.tlang('We send to you a code for activate your account using double authentication:')+"\n"+token_auth, content_type='plain', attachments=[])
sendmail.send(config.portal_email, [result['email']], _('Code for complete login'), _('We send to you a code for activate your account using double authentication:')+"\n"+token_auth, content_type='plain', attachments=[])
if result['privileges']==0:
with db.query('select module from privilegesmodule2 WHERE user_id=%s', [result['id']]) as cursor:
modules_priv=[v['module'] for v in cursor.fetchall()]
for v in modules_admin:
if v[0] in modules_priv:
for k, v in modules_admin.items():
if k in modules_priv:
if len(v)>2:
modules_priv+=v[2]
else:
modules_priv=[]
for v in modules_admin:
modules_priv.append(v[0])
for k, v in modules_admin.items():
modules_priv.append(k)
if len(v)==3:
modules_priv+=v[2]
@ -217,7 +221,7 @@ def check_login_admin(session={}):
@admin_app.post('/signup', skip=[check_login], name='admin_app.signup_insert_admin')
def signup_insert_admin(session={}):
i18n=I18n('admin2')
#i18n=I18n('admin2')
error=1
@ -256,7 +260,7 @@ def signup_insert_admin(session={}):
error=0
message="User added!"
else:
message=i18n.tlang('Sorry, cannot create the new user')
message=_('Sorry, cannot create the new user')
db.close()
@ -311,9 +315,9 @@ def change_theme(session={}):
@admin_app.get('/need_auth', skip=[check_login], name='admin_app.need_auth')
def need_auth(session={}):
i18n=I18n('admin2')
#i18n=I18n('admin2')
return t.load_template('need_auth.phtml', title=i18n.tlang('Auth check'))
return t.load_template('need_auth.phtml', title=_('Auth check'))
@admin_app.post('/auth_check', skip=[check_login], name='admin_app.auth_check')
def auth_check(session={}):

View file

@ -2,7 +2,7 @@ from paramecio.modules.admin2.models.admin import UserAdmin2
from paramecio.modules.admin2.app import admin_app
from paramecio.modules.admin2.libraries.config import modules_admin, modules_admin_icons
from paramecio.libraries.mtemplates import PTemplate, env_theme
from paramecio.libraries.i18n import I18n
from paramecio.libraries.i18n import I18n, PGetText
import paramecio.modules.admin2.libraries.i18n as i18n_lang
import os
#from paramecio.libraries.lists import SimpleList
@ -21,7 +21,12 @@ env=env_theme(__file__)
t=PTemplate(env)
i18n=I18n('admin2')
#i18n=I18n('admin2')
gtext=PGetText(__file__)
_=gtext.gettext
#t.env.directories=admin_t.env.directories
"""
@ -32,9 +37,13 @@ if t.env.directories[1]!=tpl_path:
"""
#modules_admin.append(['menu_users', 'people-circle', True])
modules_admin.append(['admin_app.admin_users', 'people-circle', ['admin_app.admin_permissions']])
def admin_users():
return _('Admin users')
modules_admin_icons.append('<symbol id="people-circle" viewBox="0 0 16 16"><path d="M11 6a3 3 0 1 1-6 0 3 3 0 0 1 6 0z"/><path fill-rule="evenodd" d="M0 8a8 8 0 1 1 16 0A8 8 0 0 1 0 8zm8-7a7 7 0 0 0-5.468 11.37C3.242 11.226 4.805 10 8 10s4.757 1.225 5.468 2.37A7 7 0 0 0 8 1z"/></symbol>')
modules_admin['admin_app.admin_users']=[admin_users, 'people-circle', ['admin_app.admin_permissions']]
modules_admin_icons['admin_app.admin_users']='<symbol id="people-circle" viewBox="0 0 16 16"><path d="M11 6a3 3 0 1 1-6 0 3 3 0 0 1 6 0z"/><path fill-rule="evenodd" d="M0 8a8 8 0 1 1 16 0A8 8 0 0 1 0 8zm8-7a7 7 0 0 0-5.468 11.37C3.242 11.226 4.805 10 8 10s4.757 1.225 5.468 2.37A7 7 0 0 0 8 1z"/></symbol>'
@admin_app.get('/ausers', name="admin_app.admin_users")
@admin_app.post('/ausers', name="admin_app.admin_users")
@ -54,11 +63,11 @@ def admin_users(session={}):
user_admin.create_forms(['username', 'password', 'email', 'privileges', 'lang', 'dark_theme', 'double_auth'])
user_admin.forms['privileges'].arr_select={0: I18n.lang('admin', 'without_privileges', 'Without privileges'), 1: I18n.lang('admin', 'selected_privileges', 'Selected privileges'), 2: I18n.lang('admin', 'administrator', 'Administrator')}
user_admin.forms['privileges'].arr_select={0: _('Without privileges'), 1: _('Selected privileges'), 2: _('Administrator')}
user_admin.forms['dark_theme'].arr_select={0: i18n.tlang('Light theme'), 1: i18n.tlang('Dark theme')}
user_admin.forms['dark_theme'].arr_select={0: _('Light theme'), 1: _('Dark theme')}
user_admin.forms['double_auth'].arr_select={0: i18n.tlang('No'), 1: i18n.tlang('Yes')}
user_admin.forms['double_auth'].arr_select={0: _('No'), 1: _('Yes')}
user_admin.fields['password'].protected=False
@ -78,7 +87,7 @@ def admin_users(session={}):
db.close()
return t.load_template('users.phtml', title=i18n.tlang('Admin users'), tlang=i18n.tlang, module_selected='admin_app.admin_users', slist=slist, session=session)
return t.load_template('users.phtml', title=_('Admin users'), tlang=_, module_selected='admin_app.admin_users', slist=slist, session=session)
@admin_app.get('/ausers/permissions/<user_id:int>', name="admin_app.admin_permissions")
@admin_app.post('/ausers/permissions/<user_id:int>', name="admin_app.admin_permissions")
@ -104,7 +113,14 @@ def admin_permissions(user_id, session={}):
priv.fields['module'].name_form=SelectForm
arr_modules={v[0]:i18n.clang('admin2', v[0], v[0]) for v in modules_admin}
#arr_modules={k:v[0] for k, v in modules_admin.items()}
arr_modules={}
for k, v in modules_admin.items():
if type(v[0]).__name__=='function':
arr_modules[k]=v[0]()
else:
arr_modules[k]=v[0]
priv.fields['user_id'].name_form=HiddenForm
@ -124,18 +140,18 @@ def admin_permissions(user_id, session={}):
privileges_admin=admin.show()
else:
arr_user={'username': i18n.tlang('User not found')}
arr_user={'username': _('User not found')}
privileges_admin=''
db.close()
return t.load_template('access.phtml', title=i18n.tlang('Users permissions'), privileges_admin=privileges_admin, user=arr_user, module_selected='admin_app.admin_users')
return t.load_template('access.phtml', title=_('Users permissions'), privileges_admin=privileges_admin, user=arr_user, module_selected='admin_app.admin_users')
def user_options(url, id, arr_row):
options=[]
options.append('<a href="'+add_get_parameters(url, op_admin=1, id=id)+'">'+I18n.lang('common', 'edit', 'Edit')+'</a>')
options.append('<a href="'+add_get_parameters(url, op_admin=1, id=id)+'">'+_('Edit')+'</a>')
if not arr_row['privileges']:
options.append(f'<a href="{app.get_url('admin_app.admin_permissions', user_id=id)}">'+i18n.tlang('User access')+'</a>')
options.append('<a href="'+add_get_parameters(url, op_admin=3, id=id)+'">'+I18n.lang('common', 'delete', 'Delete')+'</a>')
options.append(f'<a href="{app.get_url('admin_app.admin_permissions', user_id=id)}">'+_('User access')+'</a>')
options.append('<a href="'+add_get_parameters(url, op_admin=3, id=id)+'">'+_('Delete')+'</a>')
return options

View file

@ -0,0 +1,107 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2025-03-21 00:00+0100\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"Language: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=CHARSET\n"
"Content-Transfer-Encoding: 8bit\n"
#: templates/layout.phtml:79
msgid "Applications"
msgstr ""
#: templates/layout.phtml:103 ausers.py:64
msgid "Dark theme"
msgstr ""
#: app.py:73
msgid "Admin"
msgstr ""
#: app.py:108
msgid "Login"
msgstr ""
#: app.py:125
msgid "Signup"
msgstr ""
#: app.py:136
msgid "Invalid user and password"
msgstr ""
#: app.py:186
msgid "Code for complete login"
msgstr ""
#: app.py:186
msgid ""
"We send to you a code for activate your account using double authentication:"
msgstr ""
#: app.py:263
msgid "Sorry, cannot create the new user"
msgstr ""
#: app.py:320
msgid "Auth check"
msgstr ""
#: ausers.py:40 ausers.py:86
msgid "Admin users"
msgstr ""
#: ausers.py:62
msgid "Without privileges"
msgstr ""
#: ausers.py:62
msgid "Selected privileges"
msgstr ""
#: ausers.py:62
msgid "Administrator"
msgstr ""
#: ausers.py:64
msgid "Light theme"
msgstr ""
#: ausers.py:66
msgid "No"
msgstr ""
#: ausers.py:66
msgid "Yes"
msgstr ""
#: ausers.py:132
msgid "User not found"
msgstr ""
#: ausers.py:137
msgid "Users permissions"
msgstr ""
#: ausers.py:142
msgid "Edit"
msgstr ""
#: ausers.py:144
msgid "User access"
msgstr ""
#: ausers.py:145
msgid "Delete"
msgstr ""

View file

@ -0,0 +1,107 @@
# Paramecio admin2 language file
# Copyright (C) 2025
# This file is distributed under the same license as the Paramecio package.
# Antonio de la Rosa <antonio.delarosa@salirdelhoyo.com>, 2025.
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: \n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2025-03-21 00:00+0100\n"
"PO-Revision-Date: 2025-03-21 00:02+0100\n"
"Last-Translator: \n"
"Language-Team: \n"
"Language: en_US\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Generator: Poedit 3.5\n"
#: templates/layout.phtml:79
msgid "Applications"
msgstr "Applications"
#: templates/layout.phtml:103 ausers.py:64
msgid "Dark theme"
msgstr "Dark theme"
#: app.py:73
msgid "Admin"
msgstr "Admin"
#: app.py:108
msgid "Login"
msgstr "Login"
#: app.py:125
msgid "Signup"
msgstr "Signup"
#: app.py:136
msgid "Invalid user and password"
msgstr "Invalid user and password"
#: app.py:186
msgid "Code for complete login"
msgstr "Code for complete login"
#: app.py:186
msgid "We send to you a code for activate your account using double authentication:"
msgstr "We send to you a code for activate your account using double authentication:"
#: app.py:263
msgid "Sorry, cannot create the new user"
msgstr "Sorry, cannot create the new user"
#: app.py:320
msgid "Auth check"
msgstr "Auth check"
#: ausers.py:40 ausers.py:86
msgid "Admin users"
msgstr "Admin users"
#: ausers.py:62
msgid "Without privileges"
msgstr "Without privileges"
#: ausers.py:62
msgid "Selected privileges"
msgstr "Selected privileges"
#: ausers.py:62
msgid "Administrator"
msgstr "Administrator"
#: ausers.py:64
msgid "Light theme"
msgstr "Light theme"
#: ausers.py:66
msgid "No"
msgstr "No"
#: ausers.py:66
msgid "Yes"
msgstr "Yes"
#: ausers.py:132
msgid "User not found"
msgstr "User not found"
#: ausers.py:137
msgid "Users permissions"
msgstr "Users permissions"
#: ausers.py:142
msgid "Edit"
msgstr "Edit"
#: ausers.py:144
msgid "User access"
msgstr "User access"
#: ausers.py:145
msgid "Delete"
msgstr "Delete"

View file

@ -0,0 +1,107 @@
# Paramecio admin2 language file
# Copyright (C) 2025
# This file is distributed under the same license as the Paramecio package.
# Antonio de la Rosa <antonio.delarosa@salirdelhoyo.com>, 2025.
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: \n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2025-03-21 00:00+0100\n"
"PO-Revision-Date: 2025-03-21 00:03+0100\n"
"Last-Translator: \n"
"Language-Team: \n"
"Language: es_ES\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Generator: Poedit 3.5\n"
#: templates/layout.phtml:79
msgid "Applications"
msgstr "Aplicaciones"
#: templates/layout.phtml:103 ausers.py:64
msgid "Dark theme"
msgstr "Tema oscuro"
#: app.py:73
msgid "Admin"
msgstr "Admin"
#: app.py:108
msgid "Login"
msgstr "Login"
#: app.py:125
msgid "Signup"
msgstr "Registrarse"
#: app.py:136
msgid "Invalid user and password"
msgstr "Nombre de usuario o contraseña inválida"
#: app.py:186
msgid "Code for complete login"
msgstr "Código para completar login"
#: app.py:186
msgid "We send to you a code for activate your account using double authentication:"
msgstr "Te enviáremos un código para activar tu cuenta usando doble autenticación:"
#: app.py:263
msgid "Sorry, cannot create the new user"
msgstr "Lo siendo, no puedo crear el nuevo usuario."
#: app.py:320
msgid "Auth check"
msgstr "Verificar login"
#: ausers.py:40 ausers.py:86
msgid "Admin users"
msgstr "Administrar usuarios"
#: ausers.py:62
msgid "Without privileges"
msgstr "Sin privilegios"
#: ausers.py:62
msgid "Selected privileges"
msgstr "Privilegios seleccionados"
#: ausers.py:62
msgid "Administrator"
msgstr "Administrador"
#: ausers.py:64
msgid "Light theme"
msgstr "Thema luminoso"
#: ausers.py:66
msgid "No"
msgstr "No"
#: ausers.py:66
msgid "Yes"
msgstr "Sí"
#: ausers.py:132
msgid "User not found"
msgstr "Usuario no encontrado"
#: ausers.py:137
msgid "Users permissions"
msgstr "Permisos de usuario"
#: ausers.py:142
msgid "Edit"
msgstr "Editar"
#: ausers.py:144
msgid "User access"
msgstr "Acceso de usuario"
#: ausers.py:145
msgid "Delete"
msgstr "Borrar"

View file

@ -4,7 +4,7 @@
# ['Name of module admin', 'name_function_for_url_for', 'xml-icon']
modules_admin=[]
modules_admin={}
modules_admin_icons=[]
modules_admin_icons={}

View file

@ -1,7 +1,7 @@
<%inherit file="layout.phtml"/>
<%block name="content">
<h3>${tlang('User')}: ${user['username'].capitalize()}</h3>
<p><a href="${url_for('admin_app.admin_users')}">${tlang('Users')}</a> &gt;&gt; ${tlang('Permissions')}</p>
<p><a href="${url_for('admin_app.admin_users')}">${_('Users')}</a> &gt;&gt; ${_('Permissions')}</p>
${privileges_admin|n}
<p><a href="${url_for('admin_app.admin_users')}">${tlang('Users')}</a> &gt;&gt; ${tlang('Permissions')}</p>
<p><a href="${url_for('admin_app.admin_users')}">${_('Users')}</a> &gt;&gt; ${_('Permissions')}</p>
</%block>

View file

@ -44,7 +44,7 @@ lang_selected=session['lang']
<symbol id="home" viewBox="0 0 16 16">
<path d="M8.354 1.146a.5.5 0 0 0-.708 0l-6 6A.5.5 0 0 0 1.5 7.5v7a.5.5 0 0 0 .5.5h4.5a.5.5 0 0 0 .5-.5v-4h2v4a.5.5 0 0 0 .5.5H14a.5.5 0 0 0 .5-.5v-7a.5.5 0 0 0-.146-.354L13 5.793V2.5a.5.5 0 0 0-.5-.5h-1a.5.5 0 0 0-.5.5v1.293L8.354 1.146zM2.5 14V7.707l5.5-5.5 5.5 5.5V14H10v-4a.5.5 0 0 0-.5-.5h-3a.5.5 0 0 0-.5.5v4H2.5z"/>
</symbol>
%for module_icon in modules_admin_icons:
%for module_icon in modules_admin_icons.values():
${module_icon|n}
@ -76,19 +76,27 @@ lang_selected=session['lang']
<div class="content_admin">
<nav id="menu" class="nav-collapse">
<ul>
<li class="menu_title"><%block name="applications"><i class="fa fa-gear" aria-hidden="true"></i>${tlang('Applications')}</li></%block>
% for module in modules_admin:
<li class="menu_title"><%block name="applications"><i class="fa fa-gear" aria-hidden="true"></i>${_('Applications')}</li></%block>
% for module, mod_v in modules_admin.items():
<li>
% if module[0] in session['modules']:
% if len(module)>2 and type(module[2]).__name__=='str':
% if module in session['modules']:
% if len(mod_v)>2 and type(mod_v[2]).__name__=='str':
<div class="father_admin">
<svg class="bi me-2" width="16" height="16"><use xlink:href="#${module[1]}"></use></svg>
${i18n.clang('admin2', module[0], module[0])}
<svg class="bi me-2" width="16" height="16"><use xlink:href="#${mod_v[1]}"></use></svg>
% if type(mod_v[0]).__name__=='function':
${mod_v[0]()}
% else:
${mod_v[0]}
%endif
</div>
% else:
<a href="${url_for(module[0])}" class="${'selected_menu' if module[0]==module_selected else ''}">
<svg class="bi me-2" width="16" height="16"><use xlink:href="#${module[1]}"></use></svg>
${i18n.clang('admin2', module[0], module[0])}
<a href="${url_for(module)}" class="${'selected_menu' if module==module_selected else ''}">
<svg class="bi me-2" width="16" height="16"><use xlink:href="#${mod_v[1]}"></use></svg>
% if type(mod_v[0]).__name__=='function':
${mod_v[0]()}
% else:
${mod_v[0]}
%endif
</a>
% endif
% endif
@ -110,7 +118,7 @@ lang_selected=session['lang']
</div>
</div>
<div class="content">
${show_flash_message()|n}
<%block name="content">
</%block>
</div>

View file

@ -1,123 +0,0 @@
<%
from parameciofast.modules.fastadmin.libraries.config import modules_admin, modules_admin_icons
from parameciofast.libraries.i18n import I18n
i18n=I18n('fastadmin')
%>
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>${title}</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-QWTKZyjpPEjISv5WaRU9OFeRpok6YctnYmDr5pNlyT2bRjXh0JMhjY6hW+ALEwIH" crossorigin="anonymous">
<link rel="stylesheet" href="${make_media_url('css/layout.css', 'fastadmin')}" type="text/css" media="all" />
<%block name="css">
</%block>
<%block name="header_js">
</%block>
</head>
<body data-bs-theme="dark">
<svg xmlns="http://www.w3.org/2000/svg" style="display: none;">
<symbol id="home" viewBox="0 0 16 16">
<path d="M8.354 1.146a.5.5 0 0 0-.708 0l-6 6A.5.5 0 0 0 1.5 7.5v7a.5.5 0 0 0 .5.5h4.5a.5.5 0 0 0 .5-.5v-4h2v4a.5.5 0 0 0 .5.5H14a.5.5 0 0 0 .5-.5v-7a.5.5 0 0 0-.146-.354L13 5.793V2.5a.5.5 0 0 0-.5-.5h-1a.5.5 0 0 0-.5.5v1.293L8.354 1.146zM2.5 14V7.707l5.5-5.5 5.5 5.5V14H10v-4a.5.5 0 0 0-.5-.5h-3a.5.5 0 0 0-.5.5v4H2.5z"/>
</symbol>
%for module_icon in modules_admin_icons:
${module_icon|n}
%endfor
</svg>
<div class="loader-div" id="loader-div" style="display:none;">
<span class="loader">
<span></span>
<span></span>
</span>
</div>
<main>
<div class="container-fluid">
<div id="header_dashboard" class="row pt-3 pb-3">
<div class="col-sm-6 m-0 d-flex align-content-center flex-wrap align-self-center">
<h2 class="text-left ms-4 mt-0 mt-0 p-0" id="form_title">${tlang('Dashboard')}</h2>
</div>
</div>
<div class="row">
<div class="col-sm-2 p-3 m-0 text-white bg-dark" style="height:91vh;">
<!--<a href="/" class="d-flex align-items-center mb-3 mb-md-0 me-md-auto text-white text-decoration-none">
<svg class="bi me-2" width="40" height="32"><use xlink:href="#bootstrap"></use></svg>
<span class="fs-4">Sidebar</span>
</a>-->
<hr>
<!--<ul class="nav nav-pills flex-column mb-auto">
<li>
<a href="#" class="nav-link active text-white">
<svg class="bi me-2" width="16" height="16"><use xlink:href="#speedometer2"></use></svg>
${tlang('Dashboard')}
</a>
</li>
</ul>-->
% for module in modules_admin:
<ul class="nav nav-pills flex-column mb-auto">
<li>
<a href="${url_for(module[0])}" class="nav-link text-white menu_item ${'active' if module[0]==module_selected else ''}" id="menu_${module[0]}">
<svg class="bi me-2" width="16" height="16"><use xlink:href="#${module[1]}"></use></svg>
${i18n.clang('fastadmin', module[0], module[0])}
</a>
</li>
</ul>
% endfor
<hr>
</div>
<div class="col-sm m-2 pt-3" style="">
<%block name="content">
<div class="card">
<div class="card-header bg-primary bg-gradient">
${tlang('Welcome to admin')}
</div>
<div class="card-body">
<p>${tlang('This is the admin section of your site.')}</p>
</div>
</div>
</%block>
</div>
</div>
</main>
</div>
<footer class="footer m-0 p-0">
</footer>
<script src="https://cdn.jsdelivr.net/npm/@popperjs/core@2.11.8/dist/umd/popper.min.js" integrity="sha384-I7E8VVD/ismYTF4hNIPjVp/Zjvgyol6VFvRkX/vR+Vc4jQkC+hVqc2pM8ODewa9r" crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.min.js" integrity="sha384-0pUGZvbkm6XF6gxjEnlmuGrJXVbNuzT9qBBavbLwCsOGabYfZo0T0to5eqruptLy" crossorigin="anonymous"></script>
<script src="https://code.jquery.com/jquery-3.7.1.min.js" integrity="sha256-/JqT3SQfawRcv/BIHPThkBvs0OEvtFFmqPF/lYI/Cxo=" crossorigin="anonymous"></script>
<script>
document.documentElement.setAttribute('data-bs-theme','dark');
setTimeout(function () {
$('#loader-div').fadeOut(2000);
}, 1000);
$('.menu_item').hover( function (e) {
if($(this).hasClass('active')) {
$(this).removeClass('active');
} else {
$(this).addClass('active');
}
});
</script>
<%block name="js">
</%block>
</body>
</html>

View file

@ -25,12 +25,12 @@
<%block name="content">
<div class="card">
<div class="card-header bg-primary">
${tlang('Login')}
${_('Login')}
</div>
<div class="card-body">
<form method="POST" action="${url_for('admin_app.check_login_admin')}" id="login_form" class="needs-validation" novalidate>
<div class="mb-3">
<label for="username_form" class="form-label">${tlang('Username')}</label>
<label for="username_form" class="form-label">${_('Username')}</label>
<input type="text" class="form-control form-control-lg has-validation" id="username_form" name="password" aria-describedby="username" autocomplete="off" required>
<div class="invalid-feedback">
@ -40,12 +40,12 @@
<label for="password_form" class="form-label">Password</label>
<input type="password" class="form-control form-control-lg has-validation" id="password_form" name="password" autocomplete="off" required>
<div class="invalid-feedback" id="login_invalid">
${tlang('Error: username or password invalid')}
${_('Error: username or password invalid')}
</div>
</div>
<div class="mb-3 form-check">
<input type="checkbox" class="form-check-input" id="remember_login_form" name="remember_login" value="1">
<label class="form-check-label" for="autologin">${tlang('Remember login')}</label>
<label class="form-check-label" for="autologin">${_('Remember login')}</label>
</div>
<button type="submit" id="login_submit" class="btn btn-primary">Submit</button>
${csrf_token()|n}
@ -117,7 +117,7 @@
$('#loader-div').hide();
$('#login_submit').prop('disabled', false);
alert('${tlang("Error: please, try again later")}');
alert('${_("Error: please, try again later")}');
},
}).done(function(data) {
@ -132,19 +132,19 @@
else
{
$('#username_form').get(0).setCustomValidity("${tlang('Error: username or password invalid')}");
$('#password_form').get(0).setCustomValidity("${tlang('Error: username or password invalid')}");
$('#username_form').get(0).setCustomValidity("${_('Error: username or password invalid')}");
$('#password_form').get(0).setCustomValidity("${_('Error: username or password invalid')}");
console.log(JSON.stringify(data));
if(data.no_login) {
$('#login_invalid').html("${tlang('Error: you try login excessive times, please wait some minutes for try again')}");
$('#login_invalid').html("${_('Error: you try login excessive times, please wait some minutes for try again')}");
}
else {
$('#login_invalid').html("${tlang('Error: username or password invalid')}");
$('#login_invalid').html("${_('Error: username or password invalid')}");
}

View file

@ -2,30 +2,30 @@
<%block name="content">
<div class="card">
<div class="card-header bg-primary">
${tlang('Auth code')}
${_('Auth code')}
</div>
<div class="card-body">
<form method="POST" action="#" id="auth_code_form" class="needs-validation" novalidate>
<div class="mb-3">
<label for="code_form" class="form-label">${tlang('Check your email for get instructions for complete login with double auth or')} <a href="${url_for('admin_app.logout_admin')}">logout</a> and login again with other user</label>
<label for="code_form" class="form-label">${_('Check your email for get instructions for complete login with double auth or')} <a href="${url_for('admin_app.logout_admin')}">logout</a> and login again with other user</label>
<input type="text" class="form-control form-control-lg has-validation" id="code_form" name="code" aria-describedby="code" autocomplete="off" required>
<div class="invalid-feedback" id="txt_error_code">
${tlang('You need a valid code')}
${_('You need a valid code')}
</div>
</div>
<button type="submit" id="code_submit" class="btn btn-primary">${tlang('Check code')}</button>
<button type="submit" id="code_submit" class="btn btn-primary">${_('Check code')}</button>
${csrf_token()|n}
</form>
</div>
<!--<div class="form">
<p align="center">${tlang('Check your email for get instructions for complete login with double auth or')} <a href="${url_for('admin_app.logout_admin')}">logout</a> and login again with other user</p>
<p><label>${tlang('Code')} *</label><input type="text" class="" name="code" id="code_form" value="" /> <span class="error" id="code_error"></span></p>
<p align="center">${_('Check your email for get instructions for complete login with double auth or')} <a href="${url_for('admin_app.logout_admin')}">logout</a> and login again with other user</p>
<p><label>${_('Code')} *</label><input type="text" class="" name="code" id="code_form" value="" /> <span class="error" id="code_error"></span></p>
${csrf_token()|n}
</div>
<div id="submit_block">
<input type="submit" value="${tlang('Send code')}" class="submit" id="code_submit"/>
<input type="submit" value="${_('Send code')}" class="submit" id="code_submit"/>
<span id="loading">&nbsp;</span>
</div>-->
@ -74,7 +74,7 @@
form.classList.add('was-validated');
alert(textStatus);
$('#code_submit').prop('disabled', false);
$('#code_form').get(0).setCustomValidity("${tlang('Error, please try again later')}");
$('#code_form').get(0).setCustomValidity("${_('Error, please try again later')}");
}
}).done(function(data) {
@ -100,22 +100,22 @@
if(data.hasOwnProperty('disable')) {
//$('#code_error').html("${tlang('Error, your user is disabled, you need support of web administration')}");
$('#code_form').get(0).setCustomValidity("${tlang('Error, your user is disabled, you need support of web administration')}");
//$('#code_error').html("${_('Error, your user is disabled, you need support of web administration')}");
$('#code_form').get(0).setCustomValidity("${_('Error, your user is disabled, you need support of web administration')}");
$('#txt_error_code').html("${tlang('Error, your user is disabled, you need support of web administration')}");
$('#txt_error_code').html("${_('Error, your user is disabled, you need support of web administration')}");
} else {
$('#code_form').get(0).setCustomValidity("${tlang('Error, wrong code')}");
//$('#code_error').html("${tlang('Error, wrong code')}");
$('#txt_error_code').html("${tlang('Error, wrong code')}");
$('#code_form').get(0).setCustomValidity("${_('Error, wrong code')}");
//$('#code_error').html("${_('Error, wrong code')}");
$('#txt_error_code').html("${_('Error, wrong code')}");
}
if(data.you_cannot_login) {
//$('#code_error').html("${tlang('Error, excessive tries, wait some minutes for login again')}");
$('#code_form').get(0).setCustomValidity("${tlang('Error, excessive tries, wait some minutes for login again')}");
$('#txt_error_code').html("${tlang('Error, excessive tries, wait some minutes for login again')}");
//$('#code_error').html("${_('Error, excessive tries, wait some minutes for login again')}");
$('#code_form').get(0).setCustomValidity("${_('Error, excessive tries, wait some minutes for login again')}");
$('#txt_error_code').html("${_('Error, excessive tries, wait some minutes for login again')}");
}
@ -170,17 +170,17 @@
if(data.hasOwnProperty('disable')) {
$('#code_error').html("${tlang('Error, your user is disabled, you need support of web administration')}");
$('#code_error').html("${_('Error, your user is disabled, you need support of web administration')}");
} else {
$('#code_error').html("${tlang('Error, wrong code')}");
$('#code_error').html("${_('Error, wrong code')}");
}
if(data.you_cannot_login) {
$('#code_error').html("${tlang('Error, excessive tries, wait some minutes for login again')}");
$('#code_error').html("${_('Error, excessive tries, wait some minutes for login again')}");
}

View file

@ -2,39 +2,39 @@
<%block name="content">
<div class="card">
<div class="card-header bg-primary">
${tlang('Signup')}
${_('Signup')}
</div>
<div class="card-body">
<form method="POST" action="${url_for('admin_app.signup_insert_admin')}" id="login_form" class="needs-validation" novalidate>
<div class="mb-3">
<label for="username_form" class="form-label">${tlang('Username')}*</label>
<label for="username_form" class="form-label">${_('Username')}*</label>
<input type="text" class="form-control form-control-lg has-validation" id="username_form" name="password" aria-describedby="username" autocomplete="off" minlength="4" pattern="\w{4,32}" required>
<div class="invalid-feedback">
${tlang('You need a valid username')}
${_('You need a valid username')}
</div>
</div>
<div class="mb-3">
<label for="email_form" class="form-label">${tlang('Email')}*</label>
<label for="email_form" class="form-label">${_('Email')}*</label>
<input type="email" class="form-control form-control-lg has-validation" id="email_form" name="email" autocomplete="off" minlength="4" required>
<div class="invalid-feedback">
${tlang('You need an email')}
${_('You need an email')}
</div>
</div>
<div class="mb-3">
<label for="password_form" class="form-label">Password*</label>
<input type="password" class="form-control form-control-lg has-validation" id="password_form" name="password" autocomplete="off" minlength="2" required>
<div class="invalid-feedback">
${tlang('You need a password')}
${_('You need a password')}
</div>
</div>
<div class="mb-3">
<label for="repeat_password_form" class="form-label">${tlang('Repeat password')}*</label>
<label for="repeat_password_form" class="form-label">${_('Repeat password')}*</label>
<input type="password" class="form-control form-control-lg has-validation" id="repeat_password_form" name="repeat_password" autocomplete="off" minlength="2" required>
<div class="invalid-feedback">
${tlang('You need the same password in this field and not empty')}
${_('You need the same password in this field and not empty')}
</div>
</div>
<button type="submit" id="login_submit" class="btn btn-primary">${tlang('Create user')}</button>
<button type="submit" id="login_submit" class="btn btn-primary">${_('Create user')}</button>
${csrf_token()|n}
</form>
</div>
@ -49,7 +49,7 @@ $(document).ready( function () {
console.log('No match');
$('#repeat_password_form').get(0).setCustomValidity("${tlang('Passwords doesn\'t match')}");
$('#repeat_password_form').get(0).setCustomValidity("${_('Passwords doesn\'t match')}");
}
else {
@ -105,7 +105,7 @@ $(document).ready( function () {
$('#loader-div').hide();
$('#login_submit').prop('disabled', false);
alert('${tlang("Error: please, try again later")}');
alert('${_("Error: please, try again later")}');
},
}).done(function(data) {