Compare commits
4 commits
db7e9591e1
...
c23304052a
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c23304052a | ||
|
|
49e4562d31 | ||
|
|
6282bb9789 | ||
|
|
34dd3ca937 |
14 changed files with 1019 additions and 110 deletions
35
app.py
35
app.py
|
|
@ -8,10 +8,45 @@ from flask import Flask, render_template, request, redirect, url_for, flash
|
|||
import sqlite3
|
||||
import os
|
||||
from datetime import datetime
|
||||
from flask_babel import Babel, gettext, lazy_gettext
|
||||
|
||||
app = Flask(__name__)
|
||||
app.secret_key = 'your_secret_key_here'
|
||||
|
||||
# Configure supported languages
|
||||
app.config['BABEL_DEFAULT_LOCALE'] = 'es'
|
||||
app.config['LANGUAGES'] = {
|
||||
'en': 'English',
|
||||
'es': 'Español'
|
||||
}
|
||||
|
||||
# Configure translation directory
|
||||
app.config['BABEL_TRANSLATION_DIRECTORIES'] = 'translations'
|
||||
|
||||
# Locale selector function
|
||||
def get_locale():
|
||||
# Try to get language from URL parameter
|
||||
lang = request.args.get('lang')
|
||||
if lang and lang in app.config['LANGUAGES']:
|
||||
return lang
|
||||
# Try to get from session
|
||||
if hasattr(request, 'session') and 'language' in request.session:
|
||||
return request.session['language']
|
||||
# Try to get from browser preferences
|
||||
return request.accept_languages.best_match(app.config['LANGUAGES'].keys())
|
||||
|
||||
# Initialize Babel with locale selector
|
||||
babel = Babel(app, locale_selector=get_locale)
|
||||
|
||||
# Context processor to make language and config available in templates
|
||||
@app.context_processor
|
||||
def inject_global_variables():
|
||||
lang = get_locale()
|
||||
return {
|
||||
'language': lang,
|
||||
'config': app.config
|
||||
}
|
||||
|
||||
# Database setup
|
||||
DATABASE = 'tablets.db'
|
||||
|
||||
|
|
|
|||
BIN
assets/Schamann.png
Normal file
BIN
assets/Schamann.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 11 KiB |
24
compile_translations.py
Normal file
24
compile_translations.py
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
#!/usr/bin/env python3
|
||||
"""
|
||||
Compile .po files to .mo files for Flask-Babel
|
||||
"""
|
||||
import os
|
||||
from pathlib import Path
|
||||
|
||||
def compile_translations():
|
||||
translations_dir = Path('translations')
|
||||
|
||||
for lang_dir in translations_dir.iterdir():
|
||||
if lang_dir.is_dir():
|
||||
lc_messages_dir = lang_dir / 'LC_MESSAGES'
|
||||
if lc_messages_dir.exists():
|
||||
for po_file in lc_messages_dir.glob('*.po'):
|
||||
mo_file = lc_messages_dir / f"{po_file.stem}.mo"
|
||||
print(f"Compiling {po_file} -> {mo_file}")
|
||||
# Use msgfmt to compile
|
||||
os.system(f"msgfmt -o {mo_file} {po_file}")
|
||||
|
||||
print("✅ All translations compiled!")
|
||||
|
||||
if __name__ == '__main__':
|
||||
compile_translations()
|
||||
226
extract_translations.py
Normal file
226
extract_translations.py
Normal file
|
|
@ -0,0 +1,226 @@
|
|||
#!/usr/bin/env python3
|
||||
"""
|
||||
Extract strings for translation and create Spanish .po files
|
||||
"""
|
||||
import os
|
||||
import re
|
||||
from pathlib import Path
|
||||
|
||||
# Directories
|
||||
TEMPLATES_DIR = Path('templates')
|
||||
TRANSLATIONS_DIR = Path('translations')
|
||||
|
||||
# Find all template files
|
||||
def find_template_files():
|
||||
template_files = []
|
||||
for root, dirs, files in os.walk(TEMPLATES_DIR):
|
||||
for file in files:
|
||||
if file.endswith('.html'):
|
||||
template_files.append(Path(root) / file)
|
||||
return template_files
|
||||
|
||||
# Extract strings from templates
|
||||
def extract_strings_from_file(filepath):
|
||||
strings = set()
|
||||
with open(filepath, 'r', encoding='utf-8') as f:
|
||||
content = f.read()
|
||||
|
||||
# Find all _('...') and gettext('...') calls
|
||||
pattern = r"[\"'](?:_|gettext)\([\"']([^\"']+)[\"']\)"
|
||||
matches = re.findall(r"\{\{\s*_\('([^']+)'\)\s*\}\}", content)
|
||||
matches += re.findall(r"\{\{\s*gettext\('([^']+)'\)\s*\}\}", content)
|
||||
|
||||
return matches
|
||||
|
||||
# Create .pot file
|
||||
def create_pot_file(strings):
|
||||
pot_content = """msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: Tablet Management System\n"
|
||||
"POT-Creation-Date: 2026-06-20\n"
|
||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||
"Last-Translator: \n"
|
||||
"Language-Team: \n"
|
||||
"Language: en\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
|
||||
"""
|
||||
|
||||
for string in sorted(strings):
|
||||
pot_content += f'msgid "{string}"\n'
|
||||
pot_content += 'msgstr ""\n\n'
|
||||
|
||||
return pot_content
|
||||
|
||||
# Create Spanish .po file
|
||||
def create_es_po_file(strings):
|
||||
# Spanish translations
|
||||
translations = {
|
||||
# Navigation
|
||||
'Tablet Management System': 'Sistema de Gestión de Tablets',
|
||||
'Home': 'Inicio',
|
||||
'Add Tablet': 'Añadir Tablet',
|
||||
'Add User': 'Añadir Usuario',
|
||||
'Loan Tablet': 'Prestar Tablet',
|
||||
'History': 'Historial',
|
||||
'User Loans': 'Préstamos por Usuario',
|
||||
'Non-Loanable Devices': 'Dispositivos No Prestables',
|
||||
'Project Management': 'Gestión de Proyectos',
|
||||
|
||||
# Language
|
||||
'Language': 'Idioma',
|
||||
'English': 'Inglés',
|
||||
'Español': 'Español',
|
||||
|
||||
# Common
|
||||
'Search': 'Buscar',
|
||||
'Filter': 'Filtrar',
|
||||
'Status': 'Estado',
|
||||
'Actions': 'Acciones',
|
||||
'Details': 'Detalles',
|
||||
'View': 'Ver',
|
||||
'All': 'Todos',
|
||||
'Active': 'Activo',
|
||||
'Inactive': 'Inactivo',
|
||||
'Available': 'Disponible',
|
||||
'Returned': 'Devuelto',
|
||||
'Never': 'Nunca',
|
||||
'N/A': 'N/D',
|
||||
'Yes': 'Sí',
|
||||
'No': 'No',
|
||||
'Showing': 'Mostrando',
|
||||
'to': 'a',
|
||||
'of': 'de',
|
||||
'Previous': 'Anterior',
|
||||
'Next': 'Siguiente',
|
||||
'Page': 'Página',
|
||||
|
||||
# User Loans
|
||||
'User Loans': 'Préstamos por Usuario',
|
||||
'Search Users': 'Buscar Usuarios',
|
||||
'Loan Status': 'Estado de Préstamo',
|
||||
'All Users': 'Todos los Usuarios',
|
||||
'With Active Loans': 'Con Préstamos Activos',
|
||||
'No Active Loans': 'Sin Préstamos Activos',
|
||||
'Search by name or identification...': 'Buscar por nombre o identificación...',
|
||||
'users': 'usuarios',
|
||||
'No users found': 'No se encontraron usuarios',
|
||||
'No users match your search for': 'Ningún usuario coincide con tu búsqueda de',
|
||||
'Clear Filters': 'Limpiar Filtros',
|
||||
|
||||
# Table Headers
|
||||
'User': 'Usuario',
|
||||
'Identification': 'Identificación',
|
||||
'Active Loans': 'Préstamos Activos',
|
||||
'Last Loan Date': 'Fecha del Último Préstamo',
|
||||
'Tablet': 'Tablet',
|
||||
'Model': 'Modelo',
|
||||
'Serial Number': 'Número de Serie',
|
||||
'Notes': 'Notas',
|
||||
'Borrower': 'Prestatario',
|
||||
'Loan Date': 'Fecha de Préstamo',
|
||||
'Return Date': 'Fecha de Devolución',
|
||||
'Not returned': 'No devuelto',
|
||||
|
||||
# Buttons
|
||||
'Loan': 'Prestar',
|
||||
'Return': 'Devolver',
|
||||
'Add': 'Añadir',
|
||||
'Save': 'Guardar',
|
||||
'Cancel': 'Cancelar',
|
||||
'Delete': 'Eliminar',
|
||||
'Edit': 'Editar',
|
||||
'Update': 'Actualizar',
|
||||
|
||||
# Messages
|
||||
'Tablet Management System - Internal Tool': 'Sistema de Gestión de Tablets - Herramienta Interna',
|
||||
'No available tablets': 'No hay tablets disponibles',
|
||||
'No active loans': 'No hay préstamos activos',
|
||||
'No loan history for this user': 'Este usuario no tiene historial de préstamos',
|
||||
|
||||
# Forms
|
||||
'Brand': 'Marca',
|
||||
'Model': 'Modelo',
|
||||
'Serial Number': 'Número de Serie',
|
||||
'Name': 'Nombre',
|
||||
'Email': 'Correo Electrónico',
|
||||
'Phone': 'Teléfono',
|
||||
'Identification': 'Identificación',
|
||||
'Date': 'Fecha',
|
||||
'Notes': 'Notas',
|
||||
'Required field': 'Campo obligatorio',
|
||||
|
||||
# Status
|
||||
'Active Loans': 'Préstamos Activos',
|
||||
'Returned': 'Devueltos',
|
||||
}
|
||||
|
||||
po_content = """msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: Tablet Management System\n"
|
||||
"POT-Creation-Date: 2026-06-20\n"
|
||||
"PO-Revision-Date: 2026-06-20\n"
|
||||
"Last-Translator: Auto-generated\n"
|
||||
"Language-Team: \n"
|
||||
"Language: es\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||
|
||||
"""
|
||||
|
||||
for string in sorted(strings):
|
||||
msgid = string
|
||||
msgstr = translations.get(string, '')
|
||||
po_content += f'msgid "{msgid}"\n'
|
||||
po_content += f'msgstr "{msgstr}"\n\n'
|
||||
|
||||
return po_content
|
||||
|
||||
# Main
|
||||
def main():
|
||||
print("Extracting strings for translation...")
|
||||
|
||||
# Find all template files
|
||||
template_files = find_template_files()
|
||||
print(f"Found {len(template_files)} template files")
|
||||
|
||||
# Extract all strings
|
||||
all_strings = set()
|
||||
for filepath in template_files:
|
||||
strings = extract_strings_from_file(filepath)
|
||||
all_strings.update(strings)
|
||||
|
||||
print(f"Found {len(all_strings)} unique strings")
|
||||
|
||||
# Create .pot file
|
||||
pot_content = create_pot_file(all_strings)
|
||||
pot_path = TRANSLATIONS_DIR / 'messages.pot'
|
||||
with open(pot_path, 'w', encoding='utf-8') as f:
|
||||
f.write(pot_content)
|
||||
print(f"Created {pot_path}")
|
||||
|
||||
# Create Spanish .po file
|
||||
es_po_content = create_es_po_file(all_strings)
|
||||
es_dir = TRANSLATIONS_DIR / 'es' / 'LC_MESSAGES'
|
||||
es_dir.mkdir(parents=True, exist_ok=True)
|
||||
es_po_path = es_dir / 'messages.po'
|
||||
with open(es_po_path, 'w', encoding='utf-8') as f:
|
||||
f.write(es_po_content)
|
||||
print(f"Created {es_po_path}")
|
||||
|
||||
# Create English .po file
|
||||
en_dir = TRANSLATIONS_DIR / 'en' / 'LC_MESSAGES'
|
||||
en_dir.mkdir(parents=True, exist_ok=True)
|
||||
en_po_path = en_dir / 'messages.po'
|
||||
with open(en_po_path, 'w', encoding='utf-8') as f:
|
||||
f.write(create_pot_file(all_strings))
|
||||
print(f"Created {en_po_path}")
|
||||
|
||||
print("\n✅ Translation files created!")
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
|
|
@ -1,9 +1,9 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<html lang="{{ language or 'en' }}">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Tablet Management System</title>
|
||||
<title>{{ _('Tablet Management System') }}</title>
|
||||
|
||||
<!-- Tailwind CSS via CDN -->
|
||||
<script src="https://cdn.tailwindcss.com"></script>
|
||||
|
|
@ -48,16 +48,16 @@
|
|||
extend: {
|
||||
colors: {
|
||||
primary: {
|
||||
50: '#f0fdf4',
|
||||
100: '#dcfce7',
|
||||
200: '#bbf7d0',
|
||||
300: '#86efac',
|
||||
400: '#4ade80',
|
||||
500: '#22c55e',
|
||||
600: '#16a34a',
|
||||
700: '#15803d',
|
||||
800: '#166534',
|
||||
900: '#14532d',
|
||||
50: '#ecfdf5',
|
||||
100: '#d1fae5',
|
||||
200: '#a7f3d0',
|
||||
300: '#6ee7b7',
|
||||
400: '#34d399',
|
||||
500: '#10b981',
|
||||
600: '#059669',
|
||||
700: '#047857',
|
||||
800: '#065f46',
|
||||
900: '#064e3b',
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -65,25 +65,68 @@
|
|||
}
|
||||
</script>
|
||||
</head>
|
||||
<body class="bg-gray-50 min-h-screen">
|
||||
<div class="max-w-7xl mx-auto p-4 sm:p-6 lg:p-8">
|
||||
<body class="bg-gray-50 text-gray-900">
|
||||
<!-- Skip to main content -->
|
||||
<a href="#main-content" class="sr-only focus:not-sr-only">Skip to main content</a>
|
||||
|
||||
<!-- Container -->
|
||||
<div class="min-h-screen">
|
||||
<!-- Header -->
|
||||
<header class="mb-8">
|
||||
<h1 class="text-2xl sm:text-3xl font-bold text-gray-800 text-center mb-6">
|
||||
Tablet Management System
|
||||
</h1>
|
||||
|
||||
<header class="bg-primary-600 text-white shadow-lg">
|
||||
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
||||
<div class="flex items-center justify-between h-16">
|
||||
<!-- Logo / Title -->
|
||||
<div class="flex items-center gap-3">
|
||||
<svg class="w-8 h-8" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
|
||||
d="M12 19l9 2-9-18-9 18 9-2zm0 0v-8"></path>
|
||||
</svg>
|
||||
<h1 class="text-xl font-bold">{{ _('Tablet Management System') }}</h1>
|
||||
</div>
|
||||
|
||||
<!-- Language Switcher -->
|
||||
<div class="flex items-center gap-2">
|
||||
<span class="text-sm opacity-80">{{ _('Language') }}:</span>
|
||||
{% for lang_code, lang_name in config['LANGUAGES'].items() %}
|
||||
<a
|
||||
href="?lang={{ lang_code }}"
|
||||
class="px-2 py-1 text-sm rounded hover:bg-white/20 transition-colors
|
||||
{% if language == lang_code %}bg-white/30 font-medium{% endif %}"
|
||||
>
|
||||
{{ lang_name }}
|
||||
</a>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<!-- Main Content -->
|
||||
<main id="main-content" class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-8">
|
||||
<!-- Flash Messages -->
|
||||
{% with messages = get_flashed_messages(with_categories=true) %}
|
||||
{% if messages %}
|
||||
<div class="mb-6 space-y-3">
|
||||
{% for category, message in messages %}
|
||||
<div class="p-4 rounded-md
|
||||
{% if category == 'success' %}bg-green-100 text-green-800 border border-green-200
|
||||
{% elif category == 'error' %}bg-red-100 text-red-800 border border-red-200
|
||||
{% else %}bg-blue-100 text-blue-800 border border-blue-200
|
||||
{% endif %}">
|
||||
{{ message }}
|
||||
<div class="p-4 rounded-lg
|
||||
{% if category == 'success' %}bg-green-100 text-green-800
|
||||
{% elif category == 'error' %}bg-red-100 text-red-800
|
||||
{% elif category == 'warning' %}bg-yellow-100 text-yellow-800
|
||||
{% else %}bg-blue-100 text-blue-800{% endif %}">
|
||||
<div class="flex items-center gap-2">
|
||||
{% if category == 'success' %}
|
||||
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
|
||||
d="M5 13l4 4L19 7"></path>
|
||||
</svg>
|
||||
{% elif category == 'error' %}
|
||||
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
|
||||
d="M12 8v4m0 4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"></path>
|
||||
</svg>
|
||||
{% endif %}
|
||||
<span>{{ _(message) }}</span>
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
|
|
@ -91,50 +134,55 @@
|
|||
{% endwith %}
|
||||
|
||||
<!-- Navigation -->
|
||||
<nav class="bg-green-600 rounded-lg shadow-md mb-6">
|
||||
<nav class="bg-primary-600 rounded-lg shadow-md mb-6" aria-label="Main navigation">
|
||||
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
||||
<div class="flex flex-wrap justify-center sm:justify-start gap-1 sm:gap-2 py-3">
|
||||
<a href="/"
|
||||
class="px-3 py-2 text-sm sm:text-base text-white rounded hover:bg-green-700 transition-colors whitespace-nowrap">
|
||||
Home
|
||||
class="px-3 py-2 text-sm sm:text-base text-white rounded hover:bg-primary-700 transition-colors whitespace-nowrap">
|
||||
{{ _('Home') }}
|
||||
</a>
|
||||
<a href="/add_tablet"
|
||||
class="px-3 py-2 text-sm sm:text-base text-white rounded hover:bg-green-700 transition-colors whitespace-nowrap">
|
||||
Add Tablet
|
||||
class="px-3 py-2 text-sm sm:text-base text-white rounded hover:bg-primary-700 transition-colors whitespace-nowrap">
|
||||
{{ _('Add Tablet') }}
|
||||
</a>
|
||||
<a href="/add_user"
|
||||
class="px-3 py-2 text-sm sm:text-base text-white rounded hover:bg-green-700 transition-colors whitespace-nowrap">
|
||||
Add User
|
||||
class="px-3 py-2 text-sm sm:text-base text-white rounded hover:bg-primary-700 transition-colors whitespace-nowrap">
|
||||
{{ _('Add User') }}
|
||||
</a>
|
||||
<a href="/loan_tablet"
|
||||
class="px-3 py-2 text-sm sm:text-base text-white rounded hover:bg-green-700 transition-colors whitespace-nowrap">
|
||||
Loan Tablet
|
||||
class="px-3 py-2 text-sm sm:text-base text-white rounded hover:bg-primary-700 transition-colors whitespace-nowrap">
|
||||
{{ _('Loan Tablet') }}
|
||||
</a>
|
||||
<a href="/history"
|
||||
class="px-3 py-2 text-sm sm:text-base text-white rounded hover:bg-green-700 transition-colors whitespace-nowrap">
|
||||
Loan History
|
||||
class="px-3 py-2 text-sm sm:text-base text-white rounded hover:bg-primary-700 transition-colors whitespace-nowrap">
|
||||
{{ _('History') }}
|
||||
</a>
|
||||
<a href="/user_loans"
|
||||
class="px-3 py-2 text-sm sm:text-base text-white rounded hover:bg-green-700 transition-colors whitespace-nowrap">
|
||||
User Loans
|
||||
class="px-3 py-2 text-sm sm:text-base text-white rounded hover:bg-primary-700 transition-colors whitespace-nowrap">
|
||||
{{ _('User Loans') }}
|
||||
</a>
|
||||
<a href="/non_loanable_devices"
|
||||
class="px-3 py-2 text-sm sm:text-base text-white rounded hover:bg-green-700 transition-colors whitespace-nowrap">
|
||||
Non-Loanable Devices
|
||||
class="px-3 py-2 text-sm sm:text-base text-white rounded hover:bg-primary-700 transition-colors whitespace-nowrap">
|
||||
{{ _('Non-Loanable Devices') }}
|
||||
</a>
|
||||
<a href="/project_management"
|
||||
class="px-3 py-2 text-sm sm:text-base text-white rounded hover:bg-green-700 transition-colors whitespace-nowrap">
|
||||
Project Management
|
||||
class="px-3 py-2 text-sm sm:text-base text-white rounded hover:bg-primary-700 transition-colors whitespace-nowrap">
|
||||
{{ _('Project Management') }}
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
</header>
|
||||
|
||||
<!-- Main Content -->
|
||||
<main>
|
||||
|
||||
<!-- Page Content -->
|
||||
{% block content %}{% endblock %}
|
||||
</main>
|
||||
|
||||
<!-- Footer -->
|
||||
<footer class="mt-12 py-6 border-t border-gray-200">
|
||||
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 text-center text-sm text-gray-500">
|
||||
<p>{{ _('Tablet Management System - Internal Tool') }}</p>
|
||||
</div>
|
||||
</footer>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
|||
|
|
@ -7,19 +7,19 @@
|
|||
<thead class="bg-green-600 text-white">
|
||||
<tr>
|
||||
<th class="px-6 py-3 text-left text-xs font-medium uppercase tracking-wider">
|
||||
User
|
||||
{{ _('User') }}
|
||||
</th>
|
||||
<th class="px-6 py-3 text-left text-xs font-medium uppercase tracking-wider">
|
||||
Identification
|
||||
{{ _('Identification') }}
|
||||
</th>
|
||||
<th class="px-6 py-3 text-left text-xs font-medium uppercase tracking-wider">
|
||||
Active Loans
|
||||
{{ _('Active Loans') }}
|
||||
</th>
|
||||
<th class="px-6 py-3 text-left text-xs font-medium uppercase tracking-wider">
|
||||
Last Loan Date
|
||||
{{ _('Last Loan Date') }}
|
||||
</th>
|
||||
<th class="px-6 py-3 text-right text-xs font-medium uppercase tracking-wider">
|
||||
Actions
|
||||
{{ _('Actions') }}
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
|
|
@ -30,7 +30,7 @@
|
|||
<div class="font-medium text-gray-900">{{ user.name }}</div>
|
||||
</td>
|
||||
<td class="px-6 py-4 whitespace-nowrap text-gray-500">
|
||||
{{ user.identification or 'N/A' }}
|
||||
{{ user.identification or _('N/A') }}
|
||||
</td>
|
||||
<td class="px-6 py-4 whitespace-nowrap">
|
||||
<span class="px-2 inline-flex text-xs leading-5 font-semibold rounded-full
|
||||
|
|
@ -41,12 +41,12 @@
|
|||
</span>
|
||||
</td>
|
||||
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">
|
||||
{{ user.last_loan_date or 'Never' }}
|
||||
{{ user.last_loan_date or _('Never') }}
|
||||
</td>
|
||||
<td class="px-6 py-4 whitespace-nowrap text-right text-sm">
|
||||
<a href="/user_loans/{{ user.id }}"
|
||||
class="text-green-600 hover:text-green-800 font-medium">
|
||||
View Details
|
||||
{{ _('View Details') }}
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
|
|
@ -60,9 +60,9 @@
|
|||
<nav class="flex items-center justify-between pt-4" aria-label="Table navigation">
|
||||
<div class="flex items-center space-x-2">
|
||||
<span class="text-sm text-gray-500">
|
||||
Showing <span class="font-medium text-gray-900">{{ (page - 1) * per_page + 1 }}</span>
|
||||
to <span class="font-medium text-gray-900">{{ min(page * per_page, total_users) }}</span>
|
||||
of <span class="font-medium text-gray-900">{{ total_users }}</span> users
|
||||
{{ _('Showing') }} <span class="font-medium text-gray-900">{{ (page - 1) * per_page + 1 }}</span>
|
||||
{{ _('to') }} <span class="font-medium text-gray-900">{{ min(page * per_page, total_users) }}</span>
|
||||
{{ _('of') }} <span class="font-medium text-gray-900">{{ total_users }}</span> {{ _('users') }}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
|
|
@ -77,11 +77,11 @@
|
|||
hx-include="[name='search'], [name='status']"
|
||||
class="px-3 py-2 ml-0 leading-tight text-gray-500 bg-white border border-gray-300 rounded-l-lg hover:bg-gray-100 hover:text-gray-700"
|
||||
>
|
||||
Previous
|
||||
{{ _('Previous') }}
|
||||
</a>
|
||||
{%- else %}
|
||||
<span class="px-3 py-2 ml-0 leading-tight text-gray-300 bg-white border border-gray-300 rounded-l-lg cursor-not-allowed">
|
||||
Previous
|
||||
{{ _('Previous') }}
|
||||
</span>
|
||||
{%- endif %}
|
||||
|
||||
|
|
@ -168,11 +168,11 @@
|
|||
hx-include="[name='search'], [name='status']"
|
||||
class="px-3 py-2 leading-tight text-gray-500 bg-white border border-gray-300 rounded-r-lg hover:bg-gray-100 hover:text-gray-700"
|
||||
>
|
||||
Next
|
||||
{{ _('Next') }}
|
||||
</a>
|
||||
{%- else %}
|
||||
<span class="px-3 py-2 leading-tight text-gray-300 bg-white border border-gray-300 rounded-r-lg cursor-not-allowed">
|
||||
Next
|
||||
{{ _('Next') }}
|
||||
</span>
|
||||
{%- endif %}
|
||||
</div>
|
||||
|
|
@ -186,21 +186,21 @@
|
|||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
|
||||
d="M9 12h6m-6 4h6m2 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z"></path>
|
||||
</svg>
|
||||
<h3 class="text-lg font-medium text-gray-900 mb-2">No users found</h3>
|
||||
<h3 class="text-lg font-medium text-gray-900 mb-2">{{ _('No users found') }}</h3>
|
||||
<p class="text-gray-500 mb-4">
|
||||
{% if search %}
|
||||
No users match your search for "{{ search }}"
|
||||
{{ _('No users match your search for') }} "{{ search }}"
|
||||
{% elif status == 'with_loans' %}
|
||||
No users have active loans
|
||||
{{ _('No users have active loans') }}
|
||||
{% elif status == 'no_loans' %}
|
||||
All users have at least one active loan
|
||||
{{ _('All users have at least one active loan') }}
|
||||
{% else %}
|
||||
There are no users in the system yet
|
||||
{{ _('There are no users in the system yet') }}
|
||||
{% endif %}
|
||||
</p>
|
||||
<a href="/user_loans"
|
||||
class="inline-flex items-center px-4 py-2 border border-transparent text-sm font-medium rounded-md text-white bg-green-600 hover:bg-green-700 transition-colors">
|
||||
Clear Filters
|
||||
{{ _('Clear Filters') }}
|
||||
</a>
|
||||
</div>
|
||||
{%- endif %}
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@
|
|||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
|
||||
d="M12 19l9 2-9-18-9 18 9-2zm0 0v-8"></path>
|
||||
</svg>
|
||||
Available Tablets
|
||||
{{ _('Available Tablets') }}
|
||||
<span class="ml-2 px-2 py-1 bg-green-100 text-green-800 text-xs font-medium rounded-full">
|
||||
{{ available_tablets|length }}
|
||||
</span>
|
||||
|
|
@ -23,19 +23,19 @@
|
|||
<thead class="bg-gray-50">
|
||||
<tr>
|
||||
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
|
||||
Brand
|
||||
{{ _('Brand') }}
|
||||
</th>
|
||||
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
|
||||
Model
|
||||
{{ _('Model') }}
|
||||
</th>
|
||||
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
|
||||
Serial Number
|
||||
{{ _('Serial Number') }}
|
||||
</th>
|
||||
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
|
||||
Notes
|
||||
{{ _('Notes') }}
|
||||
</th>
|
||||
<th class="px-6 py-3 text-right text-xs font-medium text-gray-500 uppercase tracking-wider">
|
||||
Actions
|
||||
{{ _('Actions') }}
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
|
|
@ -61,7 +61,7 @@
|
|||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
|
||||
d="M12 6v6m0 0v6m0-6h6m-6 0H6"></path>
|
||||
</svg>
|
||||
Loan
|
||||
{{ _('Loan') }}
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
|
|
@ -75,10 +75,10 @@
|
|||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
|
||||
d="M20 7l-8-4-8 4m16 0l-8 4m8-4v10l-8 4m0-10L4 7m8 4v10M4 7v10l8 4"></path>
|
||||
</svg>
|
||||
<p>No available tablets</p>
|
||||
<p>{{ _('No available tablets') }}</p>
|
||||
<a href="/add_tablet"
|
||||
class="mt-4 inline-block px-4 py-2 bg-green-600 text-white rounded-lg hover:bg-green-700">
|
||||
Add Tablet
|
||||
{{ _('Add Tablet') }}
|
||||
</a>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
|
@ -92,7 +92,7 @@
|
|||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
|
||||
d="M12 8v4l3 3m6-3a9 9 0 11-18 0 9 9 0 0118 0z"></path>
|
||||
</svg>
|
||||
Active Loans
|
||||
{{ _('Active Loans') }}
|
||||
<span class="ml-2 px-2 py-1 bg-green-100 text-green-800 text-xs font-medium rounded-full">
|
||||
{{ active_loans|length }}
|
||||
</span>
|
||||
|
|
@ -105,19 +105,19 @@
|
|||
<thead class="bg-gray-50">
|
||||
<tr>
|
||||
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
|
||||
Tablet
|
||||
{{ _('Tablet') }}
|
||||
</th>
|
||||
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
|
||||
Serial Number
|
||||
{{ _('Serial Number') }}
|
||||
</th>
|
||||
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
|
||||
Borrower
|
||||
{{ _('Borrower') }}
|
||||
</th>
|
||||
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
|
||||
Loan Date
|
||||
{{ _('Loan Date') }}
|
||||
</th>
|
||||
<th class="px-6 py-3 text-right text-xs font-medium text-gray-500 uppercase tracking-wider">
|
||||
Actions
|
||||
{{ _('Actions') }}
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
|
|
@ -135,7 +135,7 @@
|
|||
<div class="text-sm text-gray-500">{{ loan.identification }}</div>
|
||||
</td>
|
||||
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">
|
||||
{{ loan.loan_date[:10] if loan.loan_date else 'N/A' }}
|
||||
{{ loan.loan_date[:10] if loan.loan_date else _('N/A') }}
|
||||
{{ loan.loan_date[11:16] if loan.loan_date else '' }}
|
||||
</td>
|
||||
<td class="px-6 py-4 whitespace-nowrap text-right">
|
||||
|
|
@ -145,7 +145,7 @@
|
|||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
|
||||
d="M9 5l7 7-7 7"></path>
|
||||
</svg>
|
||||
Return
|
||||
{{ _('Return') }}
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
|
|
@ -159,7 +159,7 @@
|
|||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
|
||||
d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z"></path>
|
||||
</svg>
|
||||
<p>No active loans</p>
|
||||
<p>{{ _('No active loans') }}</p>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -4,9 +4,9 @@
|
|||
<div class="space-y-6">
|
||||
<!-- Page Header -->
|
||||
<div class="flex flex-col sm:flex-row sm:items-center sm:justify-between gap-4">
|
||||
<h2 class="text-xl font-semibold text-gray-800">User Loans</h2>
|
||||
<h2 class="text-xl font-semibold text-gray-800">{{ _('User Loans') }}</h2>
|
||||
<div class="text-sm text-gray-500">
|
||||
<span id="result-count" hx-swap-oob="true">{{ total_users }} users</span>
|
||||
<span id="result-count" hx-swap-oob="true">{{ total_users }} {{ _('users') }}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
|
@ -24,7 +24,7 @@
|
|||
<!-- Search Input -->
|
||||
<div class="md:col-span-2">
|
||||
<label for="search" class="block text-sm font-medium text-gray-700 mb-1">
|
||||
Search Users
|
||||
{{ _('Search Users') }}
|
||||
</label>
|
||||
<div class="relative">
|
||||
<svg class="absolute left-3 top-1/2 -translate-y-1/2 w-5 h-5 text-gray-400"
|
||||
|
|
@ -37,7 +37,7 @@
|
|||
id="search"
|
||||
name="search"
|
||||
value="{{ search or '' }}"
|
||||
placeholder="Search by name or identification..."
|
||||
placeholder="{{ _('Search by name or identification...') }}"
|
||||
class="w-full pl-10 pr-4 py-2 border border-gray-300 rounded-md focus:ring-2 focus:ring-green-500 focus:border-green-500"
|
||||
>
|
||||
</div>
|
||||
|
|
@ -46,16 +46,16 @@
|
|||
<!-- Status Filter -->
|
||||
<div>
|
||||
<label for="status" class="block text-sm font-medium text-gray-700 mb-1">
|
||||
Loan Status
|
||||
{{ _('Loan Status') }}
|
||||
</label>
|
||||
<select
|
||||
id="status"
|
||||
name="status"
|
||||
class="w-full p-2 border border-gray-300 rounded-md focus:ring-2 focus:ring-green-500 focus:border-green-500"
|
||||
>
|
||||
<option value="" {% if not status %}selected{% endif %}>All Users</option>
|
||||
<option value="with_loans" {% if status == 'with_loans' %}selected{% endif %}>With Active Loans</option>
|
||||
<option value="no_loans" {% if status == 'no_loans' %}selected{% endif %}>No Active Loans</option>
|
||||
<option value="" {% if not status %}selected{% endif %}>{{ _('All Users') }}</option>
|
||||
<option value="with_loans" {% if status == 'with_loans' %}selected{% endif %}>{{ _('With Active Loans') }}</option>
|
||||
<option value="no_loans" {% if status == 'no_loans' %}selected{% endif %}>{{ _('No Active Loans') }}</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -67,7 +67,7 @@
|
|||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
|
||||
d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z"></path>
|
||||
</svg>
|
||||
Search
|
||||
{{ _('Search') }}
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
|
|
@ -83,7 +83,6 @@
|
|||
|
||||
<!-- HTMX Script to handle URL updates -->
|
||||
<script>
|
||||
// Update browser URL when HTMX does a GET request
|
||||
document.body.addEventListener('htmx:afterRequest', function(evt) {
|
||||
if (evt.detail.requestConfig.method === 'get' && evt.detail.successful) {
|
||||
// Update URL without reload
|
||||
|
|
@ -103,7 +102,6 @@ document.body.addEventListener('htmx:afterRequest', function(evt) {
|
|||
}
|
||||
});
|
||||
|
||||
// Restore form state from URL on page load
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
const urlParams = new URLSearchParams(window.location.search);
|
||||
const form = document.getElementById('search-form');
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@
|
|||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
|
||||
d="M15 19l-7-7 7-7"></path>
|
||||
</svg>
|
||||
Back to All Users
|
||||
{{ _('Back to All Users') }}
|
||||
</a>
|
||||
</div>
|
||||
|
||||
|
|
@ -25,16 +25,16 @@
|
|||
<div class="flex-1">
|
||||
<h1 class="text-xl font-bold text-gray-900">{{ user.name }}</h1>
|
||||
<p class="text-gray-500">
|
||||
ID: {{ user.id }} | Identification: {{ user.identification or 'N/A' }}
|
||||
{{ _('ID') }}: {{ user.id }} | {{ _('Identification') }}: {{ user.identification or _('N/A') }}
|
||||
</p>
|
||||
<div class="flex gap-4 mt-2">
|
||||
<div class="flex items-center gap-2">
|
||||
<span class="w-3 h-3 bg-green-500 rounded-full"></span>
|
||||
<span class="text-sm text-gray-600">{{ active_count }} Active Loans</span>
|
||||
<span class="text-sm text-gray-600">{{ active_count }} {{ _('Active Loans') }}</span>
|
||||
</div>
|
||||
<div class="flex items-center gap-2">
|
||||
<span class="w-3 h-3 bg-gray-400 rounded-full"></span>
|
||||
<span class="text-sm text-gray-600">{{ returned_count }} Returned</span>
|
||||
<span class="text-sm text-gray-600">{{ returned_count }} {{ _('Returned') }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -42,13 +42,13 @@
|
|||
{% if user.email %}
|
||||
<a href="mailto:{{ user.email }}"
|
||||
class="px-3 py-1 bg-blue-100 text-blue-700 rounded-lg text-sm hover:bg-blue-200">
|
||||
Email
|
||||
{{ _('Email') }}
|
||||
</a>
|
||||
{% endif %}
|
||||
{% if user.phone %}
|
||||
<a href="tel:{{ user.phone }}"
|
||||
class="px-3 py-1 bg-purple-100 text-purple-700 rounded-lg text-sm hover:bg-purple-200">
|
||||
Call
|
||||
{{ _('Call') }}
|
||||
</a>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
|
@ -58,7 +58,7 @@
|
|||
<!-- Loan History -->
|
||||
<div class="bg-white rounded-lg shadow">
|
||||
<div class="p-6 border-b border-gray-200">
|
||||
<h2 class="text-lg font-semibold text-gray-800">Loan History</h2>
|
||||
<h2 class="text-lg font-semibold text-gray-800">{{ _('Loan History') }}</h2>
|
||||
</div>
|
||||
|
||||
{% if loans %}
|
||||
|
|
@ -67,16 +67,16 @@
|
|||
<thead class="bg-gray-50">
|
||||
<tr>
|
||||
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
|
||||
Tablet
|
||||
{{ _('Tablet') }}
|
||||
</th>
|
||||
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
|
||||
Loan Date
|
||||
{{ _('Loan Date') }}
|
||||
</th>
|
||||
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
|
||||
Return Date
|
||||
{{ _('Return Date') }}
|
||||
</th>
|
||||
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
|
||||
Status
|
||||
{{ _('Status') }}
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
|
|
@ -88,14 +88,14 @@
|
|||
<div class="text-sm text-gray-500">{{ loan.serial_number }}</div>
|
||||
</td>
|
||||
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">
|
||||
{{ loan.loan_date[:10] if loan.loan_date else 'N/A' }}
|
||||
{{ loan.loan_date[:10] if loan.loan_date else _('N/A') }}
|
||||
{{ loan.loan_date[11:16] if loan.loan_date else '' }}
|
||||
</td>
|
||||
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">
|
||||
{% if loan.return_date %}
|
||||
{{ loan.return_date[:10] }} {{ loan.return_date[11:16] }}
|
||||
{% else %}
|
||||
<span class="text-gray-400 italic">Not returned</span>
|
||||
<span class="text-gray-400 italic">{{ _('Not returned') }}</span>
|
||||
{% endif %}
|
||||
</td>
|
||||
<td class="px-6 py-4 whitespace-nowrap">
|
||||
|
|
@ -118,7 +118,7 @@
|
|||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
|
||||
d="M9 12h6m-6 4h6m2 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z"></path>
|
||||
</svg>
|
||||
<p>No loan history for this user</p>
|
||||
<p>{{ _('No loan history for this user') }}</p>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
|
|
|||
BIN
translations/en/LC_MESSAGES/messages.mo
Normal file
BIN
translations/en/LC_MESSAGES/messages.mo
Normal file
Binary file not shown.
191
translations/en/LC_MESSAGES/messages.po
Normal file
191
translations/en/LC_MESSAGES/messages.po
Normal file
|
|
@ -0,0 +1,191 @@
|
|||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: Tablet Management System\n"
|
||||
"POT-Creation-Date: 2026-06-20\n"
|
||||
"PO-Revision-Date: 2026-06-20\n"
|
||||
"Last-Translator: Auto-generated\n"
|
||||
"Language-Team: \n"
|
||||
"Language: en\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
|
||||
msgid "Actions"
|
||||
msgstr ""
|
||||
|
||||
msgid "Active Loans"
|
||||
msgstr ""
|
||||
|
||||
msgid "Add Tablet"
|
||||
msgstr ""
|
||||
|
||||
msgid "Add User"
|
||||
msgstr ""
|
||||
|
||||
msgid "All Users"
|
||||
msgstr ""
|
||||
|
||||
msgid "All users have at least one active loan"
|
||||
msgstr ""
|
||||
|
||||
msgid "Available Tablets"
|
||||
msgstr ""
|
||||
|
||||
msgid "Back to All Users"
|
||||
msgstr ""
|
||||
|
||||
msgid "Borrower"
|
||||
msgstr ""
|
||||
|
||||
msgid "Brand"
|
||||
msgstr ""
|
||||
|
||||
msgid "Call"
|
||||
msgstr ""
|
||||
|
||||
msgid "Clear Filters"
|
||||
msgstr ""
|
||||
|
||||
msgid "Email"
|
||||
msgstr ""
|
||||
|
||||
msgid "English"
|
||||
msgstr ""
|
||||
|
||||
msgid "Español"
|
||||
msgstr ""
|
||||
|
||||
msgid "History"
|
||||
msgstr ""
|
||||
|
||||
msgid "Home"
|
||||
msgstr ""
|
||||
|
||||
msgid "ID"
|
||||
msgstr ""
|
||||
|
||||
msgid "Identification"
|
||||
msgstr ""
|
||||
|
||||
msgid "Language"
|
||||
msgstr ""
|
||||
|
||||
msgid "Last Loan Date"
|
||||
msgstr ""
|
||||
|
||||
msgid "Loan"
|
||||
msgstr ""
|
||||
|
||||
msgid "Loan Date"
|
||||
msgstr ""
|
||||
|
||||
msgid "Loan History"
|
||||
msgstr ""
|
||||
|
||||
msgid "Loan Status"
|
||||
msgstr ""
|
||||
|
||||
msgid "Loan Tablet"
|
||||
msgstr ""
|
||||
|
||||
msgid "Model"
|
||||
msgstr ""
|
||||
|
||||
msgid "Next"
|
||||
msgstr ""
|
||||
|
||||
msgid "No Active Loans"
|
||||
msgstr ""
|
||||
|
||||
msgid "No active loans"
|
||||
msgstr ""
|
||||
|
||||
msgid "No available tablets"
|
||||
msgstr ""
|
||||
|
||||
msgid "No loan history for this user"
|
||||
msgstr ""
|
||||
|
||||
msgid "No users found"
|
||||
msgstr ""
|
||||
|
||||
msgid "No users have active loans"
|
||||
msgstr ""
|
||||
|
||||
msgid "No users match your search for"
|
||||
msgstr ""
|
||||
|
||||
msgid "Non-Loanable Devices"
|
||||
msgstr ""
|
||||
|
||||
msgid "Notes"
|
||||
msgstr ""
|
||||
|
||||
msgid "N/A"
|
||||
msgstr ""
|
||||
|
||||
msgid "of"
|
||||
msgstr ""
|
||||
|
||||
msgid "Previous"
|
||||
msgstr ""
|
||||
|
||||
msgid "Project Management"
|
||||
msgstr ""
|
||||
|
||||
msgid "Return"
|
||||
msgstr ""
|
||||
|
||||
msgid "Return Date"
|
||||
msgstr ""
|
||||
|
||||
msgid "Search"
|
||||
msgstr ""
|
||||
|
||||
msgid "Search by name or identification..."
|
||||
msgstr ""
|
||||
|
||||
msgid "Search Users"
|
||||
msgstr ""
|
||||
|
||||
msgid "Serial Number"
|
||||
msgstr ""
|
||||
|
||||
msgid "Showing"
|
||||
msgstr ""
|
||||
|
||||
msgid "Status"
|
||||
msgstr ""
|
||||
|
||||
msgid "Tablet"
|
||||
msgstr ""
|
||||
|
||||
msgid "Tablet Management System"
|
||||
msgstr ""
|
||||
|
||||
msgid "Tablet Management System - Internal Tool"
|
||||
msgstr ""
|
||||
|
||||
msgid "There are no users in the system yet"
|
||||
msgstr ""
|
||||
|
||||
msgid "to"
|
||||
msgstr ""
|
||||
|
||||
msgid "User"
|
||||
msgstr ""
|
||||
|
||||
msgid "User Loans"
|
||||
msgstr ""
|
||||
|
||||
msgid "users"
|
||||
msgstr ""
|
||||
|
||||
msgid "View"
|
||||
msgstr ""
|
||||
|
||||
msgid "View Details"
|
||||
msgstr ""
|
||||
|
||||
msgid "With Active Loans"
|
||||
msgstr ""
|
||||
BIN
translations/es/LC_MESSAGES/messages.mo
Normal file
BIN
translations/es/LC_MESSAGES/messages.mo
Normal file
Binary file not shown.
192
translations/es/LC_MESSAGES/messages.po
Normal file
192
translations/es/LC_MESSAGES/messages.po
Normal file
|
|
@ -0,0 +1,192 @@
|
|||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: Tablet Management System\n"
|
||||
"POT-Creation-Date: 2026-06-20\n"
|
||||
"PO-Revision-Date: 2026-06-20\n"
|
||||
"Last-Translator: Auto-generated\n"
|
||||
"Language-Team: \n"
|
||||
"Language: es\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||
|
||||
msgid "Actions"
|
||||
msgstr "Acciones"
|
||||
|
||||
msgid "Active Loans"
|
||||
msgstr "Préstamos Activos"
|
||||
|
||||
msgid "Add Tablet"
|
||||
msgstr "Añadir Tablet"
|
||||
|
||||
msgid "Add User"
|
||||
msgstr "Añadir Usuario"
|
||||
|
||||
msgid "All Users"
|
||||
msgstr "Todos los Usuarios"
|
||||
|
||||
msgid "All users have at least one active loan"
|
||||
msgstr "Todos los usuarios tienen al menos un préstamo activo"
|
||||
|
||||
msgid "Available Tablets"
|
||||
msgstr "Tablets Disponibles"
|
||||
|
||||
msgid "Back to All Users"
|
||||
msgstr "Volver a Todos los Usuarios"
|
||||
|
||||
msgid "Borrower"
|
||||
msgstr "Prestatario"
|
||||
|
||||
msgid "Brand"
|
||||
msgstr "Marca"
|
||||
|
||||
msgid "Call"
|
||||
msgstr "Llamar"
|
||||
|
||||
msgid "Clear Filters"
|
||||
msgstr "Limpiar Filtros"
|
||||
|
||||
msgid "Email"
|
||||
msgstr "Correo Electrónico"
|
||||
|
||||
msgid "English"
|
||||
msgstr "Inglés"
|
||||
|
||||
msgid "Español"
|
||||
msgstr "Español"
|
||||
|
||||
msgid "History"
|
||||
msgstr "Historial"
|
||||
|
||||
msgid "Home"
|
||||
msgstr "Inicio"
|
||||
|
||||
msgid "ID"
|
||||
msgstr "ID"
|
||||
|
||||
msgid "Identification"
|
||||
msgstr "Identificación"
|
||||
|
||||
msgid "Language"
|
||||
msgstr "Idioma"
|
||||
|
||||
msgid "Last Loan Date"
|
||||
msgstr "Fecha del Último Préstamo"
|
||||
|
||||
msgid "Loan"
|
||||
msgstr "Prestar"
|
||||
|
||||
msgid "Loan Date"
|
||||
msgstr "Fecha de Préstamo"
|
||||
|
||||
msgid "Loan History"
|
||||
msgstr "Historial de Préstamos"
|
||||
|
||||
msgid "Loan Status"
|
||||
msgstr "Estado de Préstamo"
|
||||
|
||||
msgid "Loan Tablet"
|
||||
msgstr "Prestar Tablet"
|
||||
|
||||
msgid "Model"
|
||||
msgstr "Modelo"
|
||||
|
||||
msgid "Next"
|
||||
msgstr "Siguiente"
|
||||
|
||||
msgid "No Active Loans"
|
||||
msgstr "Sin Préstamos Activos"
|
||||
|
||||
msgid "No active loans"
|
||||
msgstr "No hay préstamos activos"
|
||||
|
||||
msgid "No available tablets"
|
||||
msgstr "No hay tablets disponibles"
|
||||
|
||||
msgid "No loan history for this user"
|
||||
msgstr "Este usuario no tiene historial de préstamos"
|
||||
|
||||
msgid "No users found"
|
||||
msgstr "No se encontraron usuarios"
|
||||
|
||||
msgid "No users have active loans"
|
||||
msgstr "No hay usuarios con préstamos activos"
|
||||
|
||||
msgid "No users match your search for"
|
||||
msgstr "Ningún usuario coincide con tu búsqueda de"
|
||||
|
||||
msgid "Non-Loanable Devices"
|
||||
msgstr "Dispositivos No Prestables"
|
||||
|
||||
msgid "Notes"
|
||||
msgstr "Notas"
|
||||
|
||||
msgid "N/A"
|
||||
msgstr "N/D"
|
||||
|
||||
msgid "of"
|
||||
msgstr "de"
|
||||
|
||||
msgid "Previous"
|
||||
msgstr "Anterior"
|
||||
|
||||
msgid "Project Management"
|
||||
msgstr "Gestión de Proyectos"
|
||||
|
||||
msgid "Return"
|
||||
msgstr "Devolver"
|
||||
|
||||
msgid "Return Date"
|
||||
msgstr "Fecha de Devolución"
|
||||
|
||||
msgid "Search"
|
||||
msgstr "Buscar"
|
||||
|
||||
msgid "Search by name or identification..."
|
||||
msgstr "Buscar por nombre o identificación..."
|
||||
|
||||
msgid "Search Users"
|
||||
msgstr "Buscar Usuarios"
|
||||
|
||||
msgid "Serial Number"
|
||||
msgstr "Número de Serie"
|
||||
|
||||
msgid "Showing"
|
||||
msgstr "Mostrando"
|
||||
|
||||
msgid "Status"
|
||||
msgstr "Estado"
|
||||
|
||||
msgid "Tablet"
|
||||
msgstr "Tablet"
|
||||
|
||||
msgid "Tablet Management System"
|
||||
msgstr "Sistema de Gestión de Tablets"
|
||||
|
||||
msgid "Tablet Management System - Internal Tool"
|
||||
msgstr "Sistema de Gestión de Tablets - Herramienta Interna"
|
||||
|
||||
msgid "There are no users in the system yet"
|
||||
msgstr "Aún no hay usuarios en el sistema"
|
||||
|
||||
msgid "to"
|
||||
msgstr "a"
|
||||
|
||||
msgid "User"
|
||||
msgstr "Usuario"
|
||||
|
||||
msgid "User Loans"
|
||||
msgstr "Préstamos por Usuario"
|
||||
|
||||
msgid "users"
|
||||
msgstr "usuarios"
|
||||
|
||||
msgid "View"
|
||||
msgstr "Ver"
|
||||
|
||||
msgid "View Details"
|
||||
msgstr "Ver Detalles"
|
||||
|
||||
msgid "With Active Loans"
|
||||
msgstr "Con Préstamos Activos"
|
||||
195
translations/messages.pot
Normal file
195
translations/messages.pot
Normal file
|
|
@ -0,0 +1,195 @@
|
|||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: Tablet Management System
|
||||
"
|
||||
"POT-Creation-Date: 2026-06-20
|
||||
"
|
||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE
|
||||
"
|
||||
"Last-Translator:
|
||||
"
|
||||
"Language-Team:
|
||||
"
|
||||
"Language: en
|
||||
"
|
||||
"MIME-Version: 1.0
|
||||
"
|
||||
"Content-Type: text/plain; charset=UTF-8
|
||||
"
|
||||
"Content-Transfer-Encoding: 8bit
|
||||
"
|
||||
|
||||
msgid "Actions"
|
||||
msgstr ""
|
||||
|
||||
msgid "Active Loans"
|
||||
msgstr ""
|
||||
|
||||
msgid "Add Tablet"
|
||||
msgstr ""
|
||||
|
||||
msgid "Add User"
|
||||
msgstr ""
|
||||
|
||||
msgid "All Users"
|
||||
msgstr ""
|
||||
|
||||
msgid "All users have at least one active loan"
|
||||
msgstr ""
|
||||
|
||||
msgid "Available Tablets"
|
||||
msgstr ""
|
||||
|
||||
msgid "Back to All Users"
|
||||
msgstr ""
|
||||
|
||||
msgid "Borrower"
|
||||
msgstr ""
|
||||
|
||||
msgid "Brand"
|
||||
msgstr ""
|
||||
|
||||
msgid "Call"
|
||||
msgstr ""
|
||||
|
||||
msgid "Clear Filters"
|
||||
msgstr ""
|
||||
|
||||
msgid "Email"
|
||||
msgstr ""
|
||||
|
||||
msgid "History"
|
||||
msgstr ""
|
||||
|
||||
msgid "Home"
|
||||
msgstr ""
|
||||
|
||||
msgid "ID"
|
||||
msgstr ""
|
||||
|
||||
msgid "Identification"
|
||||
msgstr ""
|
||||
|
||||
msgid "Language"
|
||||
msgstr ""
|
||||
|
||||
msgid "Last Loan Date"
|
||||
msgstr ""
|
||||
|
||||
msgid "Loan"
|
||||
msgstr ""
|
||||
|
||||
msgid "Loan Date"
|
||||
msgstr ""
|
||||
|
||||
msgid "Loan History"
|
||||
msgstr ""
|
||||
|
||||
msgid "Loan Status"
|
||||
msgstr ""
|
||||
|
||||
msgid "Loan Tablet"
|
||||
msgstr ""
|
||||
|
||||
msgid "Model"
|
||||
msgstr ""
|
||||
|
||||
msgid "Next"
|
||||
msgstr ""
|
||||
|
||||
msgid "No Active Loans"
|
||||
msgstr ""
|
||||
|
||||
msgid "No active loans"
|
||||
msgstr ""
|
||||
|
||||
msgid "No available tablets"
|
||||
msgstr ""
|
||||
|
||||
msgid "No loan history for this user"
|
||||
msgstr ""
|
||||
|
||||
msgid "No users found"
|
||||
msgstr ""
|
||||
|
||||
msgid "No users have active loans"
|
||||
msgstr ""
|
||||
|
||||
msgid "No users match your search for"
|
||||
msgstr ""
|
||||
|
||||
msgid "Non-Loanable Devices"
|
||||
msgstr ""
|
||||
|
||||
msgid "Not returned"
|
||||
msgstr ""
|
||||
|
||||
msgid "Notes"
|
||||
msgstr ""
|
||||
|
||||
msgid "Previous"
|
||||
msgstr ""
|
||||
|
||||
msgid "Project Management"
|
||||
msgstr ""
|
||||
|
||||
msgid "Return"
|
||||
msgstr ""
|
||||
|
||||
msgid "Return Date"
|
||||
msgstr ""
|
||||
|
||||
msgid "Returned"
|
||||
msgstr ""
|
||||
|
||||
msgid "Search"
|
||||
msgstr ""
|
||||
|
||||
msgid "Search Users"
|
||||
msgstr ""
|
||||
|
||||
msgid "Search by name or identification..."
|
||||
msgstr ""
|
||||
|
||||
msgid "Serial Number"
|
||||
msgstr ""
|
||||
|
||||
msgid "Showing"
|
||||
msgstr ""
|
||||
|
||||
msgid "Status"
|
||||
msgstr ""
|
||||
|
||||
msgid "Tablet"
|
||||
msgstr ""
|
||||
|
||||
msgid "Tablet Management System"
|
||||
msgstr ""
|
||||
|
||||
msgid "Tablet Management System - Internal Tool"
|
||||
msgstr ""
|
||||
|
||||
msgid "There are no users in the system yet"
|
||||
msgstr ""
|
||||
|
||||
msgid "User"
|
||||
msgstr ""
|
||||
|
||||
msgid "User Loans"
|
||||
msgstr ""
|
||||
|
||||
msgid "View Details"
|
||||
msgstr ""
|
||||
|
||||
msgid "With Active Loans"
|
||||
msgstr ""
|
||||
|
||||
msgid "of"
|
||||
msgstr ""
|
||||
|
||||
msgid "to"
|
||||
msgstr ""
|
||||
|
||||
msgid "users"
|
||||
msgstr ""
|
||||
|
||||
Loading…
Add table
Add a link
Reference in a new issue