mirror of
https://github.com/eduardogsilva/wireguard_webadmin.git
synced 2025-04-19 00:45:16 +00:00
Add language selection feature and internationalization support
This commit is contained in:
parent
701f957642
commit
e430580aba
0
intl_tools/__init__.py
Normal file
0
intl_tools/__init__.py
Normal file
1
intl_tools/admin.py
Normal file
1
intl_tools/admin.py
Normal file
@ -0,0 +1 @@
|
||||
# Register your models here.
|
6
intl_tools/apps.py
Normal file
6
intl_tools/apps.py
Normal file
@ -0,0 +1,6 @@
|
||||
from django.apps import AppConfig
|
||||
|
||||
|
||||
class IntlToolsConfig(AppConfig):
|
||||
default_auto_field = 'django.db.models.BigAutoField'
|
||||
name = 'intl_tools'
|
23
intl_tools/forms.py
Normal file
23
intl_tools/forms.py
Normal file
@ -0,0 +1,23 @@
|
||||
from crispy_forms.helper import FormHelper
|
||||
from crispy_forms.layout import Column, Layout, Row, Submit
|
||||
from django import forms
|
||||
from django.conf import settings
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
|
||||
|
||||
class LanguageForm(forms.Form):
|
||||
language = forms.ChoiceField(
|
||||
choices=settings.LANGUAGES,
|
||||
label=_("Language"),
|
||||
)
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
self.helper = FormHelper()
|
||||
self.helper.form_method = 'post'
|
||||
self.helper.layout = Layout(
|
||||
Row(
|
||||
Column('language', css_class='col-md-6'),
|
||||
),
|
||||
Submit('submit', _("Change Language"), css_class='btn btn-primary')
|
||||
)
|
0
intl_tools/migrations/__init__.py
Normal file
0
intl_tools/migrations/__init__.py
Normal file
1
intl_tools/models.py
Normal file
1
intl_tools/models.py
Normal file
@ -0,0 +1 @@
|
||||
# Create your models here.
|
1
intl_tools/tests.py
Normal file
1
intl_tools/tests.py
Normal file
@ -0,0 +1 @@
|
||||
# Create your tests here.
|
25
intl_tools/views.py
Normal file
25
intl_tools/views.py
Normal file
@ -0,0 +1,25 @@
|
||||
from django.conf import settings
|
||||
from django.shortcuts import redirect, render
|
||||
from django.utils import translation
|
||||
|
||||
from .forms import LanguageForm
|
||||
|
||||
|
||||
def view_change_language(request):
|
||||
if request.method == 'POST':
|
||||
form = LanguageForm(request.POST)
|
||||
if form.is_valid():
|
||||
language = form.cleaned_data['language']
|
||||
translation.activate(language)
|
||||
request.session['django_language'] = language
|
||||
next_url = '/'
|
||||
response = redirect(next_url)
|
||||
response.set_cookie(settings.LANGUAGE_COOKIE_NAME, language)
|
||||
return response
|
||||
else:
|
||||
form = LanguageForm(initial={'language': translation.get_language()})
|
||||
|
||||
if request.user.is_authenticated:
|
||||
return render(request, 'generic_form.html', {'form': form})
|
||||
else:
|
||||
return render(request, 'generic_form_guest.html', {'form': form})
|
BIN
locale/pt_BR/LC_MESSAGES/django.mo
Normal file
BIN
locale/pt_BR/LC_MESSAGES/django.mo
Normal file
Binary file not shown.
87
locale/pt_BR/LC_MESSAGES/django.po
Normal file
87
locale/pt_BR/LC_MESSAGES/django.po
Normal file
@ -0,0 +1,87 @@
|
||||
# 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-04-14 15:34-0300\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=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n > 1);\n"
|
||||
|
||||
#: intl_tools/forms.py:11 templates/accounts/login.html:36
|
||||
msgid "Language"
|
||||
msgstr "Idioma"
|
||||
|
||||
#: intl_tools/forms.py:22 templates/base.html:80
|
||||
msgid "Change Language"
|
||||
msgstr "Alterar Idioma"
|
||||
|
||||
#: templates/accounts/login.html:14
|
||||
msgid "Username"
|
||||
msgstr "Usuário"
|
||||
|
||||
#: templates/accounts/login.html:23
|
||||
msgid "Password"
|
||||
msgstr "Senha"
|
||||
|
||||
#: templates/accounts/login.html:32
|
||||
msgid "Login"
|
||||
msgstr "Acessar"
|
||||
|
||||
#: templates/accounts/logout.html:11
|
||||
msgid "You have been successfully logged out."
|
||||
msgstr "Você foi desconectado com sucesso."
|
||||
|
||||
#: templates/accounts/logout.html:14
|
||||
msgid "Login again"
|
||||
msgstr "Acessar novamente"
|
||||
|
||||
#: templates/base.html:112
|
||||
msgid "Status"
|
||||
msgstr "Estado"
|
||||
|
||||
#: templates/base.html:158
|
||||
msgid "User Manager"
|
||||
msgstr "Configurar Usuários"
|
||||
|
||||
#: templates/base.html:176
|
||||
msgid "VPN Invite"
|
||||
msgstr "Convite para VPN"
|
||||
|
||||
#: templates/base.html:254
|
||||
msgid "Update Required"
|
||||
msgstr "Atualização Necessária"
|
||||
|
||||
#: templates/base.html:256
|
||||
msgid ""
|
||||
"Your WireGuard settings have been modified. To apply these changes, please "
|
||||
"update the configuration and reload the WireGuard service."
|
||||
msgstr ""
|
||||
"Suas configurações do WireGuard foram modificadas. Para aplicar essas "
|
||||
"mudanças, atualize a configuração e recarregue o serviço WireGuard."
|
||||
|
||||
#: templates/base.html:265
|
||||
msgid "Update and restart service"
|
||||
msgstr "Atualizar e reiniciar o serviço"
|
||||
|
||||
#: templates/base.html:273
|
||||
msgid "Update and reload service"
|
||||
msgstr "Atualizar e recarregar o serviço"
|
||||
|
||||
#: templates/base.html:286
|
||||
msgid "Update Available"
|
||||
msgstr "Atualização Disponível"
|
||||
|
||||
#: templates/base.html:288
|
||||
msgid "Version"
|
||||
msgstr "Versão"
|
@ -1,62 +1,50 @@
|
||||
{% extends "base_login.html" %}
|
||||
{% load i18n %}
|
||||
|
||||
{% block content %}
|
||||
<div class="register-box">
|
||||
<div class="register-logo">
|
||||
<a href="/"><b>wireguard-webadmin</b></a>
|
||||
</div>
|
||||
<div class="card">
|
||||
<div class="card-body register-card-body">
|
||||
<form action="/accounts/login/" method="post">
|
||||
{% csrf_token %}
|
||||
<div class="input-group mb-3">
|
||||
<input type="text" class="form-control" placeholder="{% trans 'Username' %}" name="username">
|
||||
<div class="input-group-append">
|
||||
<div class="input-group-text">
|
||||
<span class="fas fa-user"></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="register-box">
|
||||
<div class="register-logo">
|
||||
<a href="/"><b>wireguard-webadmin</b></a>
|
||||
<div class="input-group mb-3">
|
||||
<input type="password" class="form-control" placeholder="{% trans 'Password' %}" name="password">
|
||||
<div class="input-group-append">
|
||||
<div class="input-group-text">
|
||||
<span class="fas fa-lock"></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-md-6">
|
||||
<button type="submit" class="btn btn-primary btn-block">{% trans 'Login' %}</button>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<a class="btn btn-outline-primary btn-block" href="/change_language/">
|
||||
{% trans 'Language' %}
|
||||
</a>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<div class="card-body register-card-body">
|
||||
<form action="/accounts/login/" method="post">
|
||||
{% csrf_token %}
|
||||
<div class="input-group mb-3">
|
||||
<input type="text" class="form-control" placeholder="username" name="username">
|
||||
<div class="input-group-append">
|
||||
<div class="input-group-text">
|
||||
<span class="fas fa-user"></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="input-group mb-3">
|
||||
<input type="password" class="form-control" placeholder="Password" name="password">
|
||||
<div class="input-group-append">
|
||||
<div class="input-group-text">
|
||||
<span class="fas fa-lock"></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
<div class="row">
|
||||
<div class="col-8">
|
||||
</div>
|
||||
<div class="col-4">
|
||||
<button type="submit" class="btn btn-primary btn-block">Login</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
<!-- /.form-box -->
|
||||
</div><!-- /.card -->
|
||||
</div>
|
||||
<!-- /.register-box -->
|
||||
|
||||
|
||||
<script>
|
||||
document.querySelector('input[name="username"]').addEventListener('input', function() {
|
||||
this.value = this.value.toLowerCase().replace(/\s/g, '');
|
||||
});
|
||||
</script>
|
||||
|
||||
|
||||
|
||||
|
||||
{% endblock %}
|
||||
```
|
||||
<script>
|
||||
document.querySelector('input[name="username"]').addEventListener('input', function() {
|
||||
this.value = this.value.toLowerCase().replace(/\s/g, '');
|
||||
});
|
||||
</script>
|
||||
{% endblock %}
|
||||
|
@ -1,35 +1,20 @@
|
||||
{% extends "base_login.html" %}
|
||||
{% load i18n %}
|
||||
|
||||
{% block content %}
|
||||
|
||||
<div class="register-box">
|
||||
<div class="register-logo">
|
||||
<a href="/"><b>wireguard-webadmin</b></a>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<div class="card-body register-card-body">
|
||||
<p class="login-box-msg">You have been successfully logged out.</p>
|
||||
|
||||
|
||||
|
||||
|
||||
<div class="row">
|
||||
|
||||
<div class="col-12">
|
||||
<a href="/accounts/login/" class="btn btn-primary btn-block">Login again</a>
|
||||
<div class="register-box">
|
||||
<div class="register-logo">
|
||||
<a href="/"><b>wireguard-webadmin</b></a>
|
||||
</div>
|
||||
<div class="card">
|
||||
<div class="card-body register-card-body">
|
||||
<p class="login-box-msg">{% trans 'You have been successfully logged out.' %}</p>
|
||||
<div class="row">
|
||||
<div class="col-12">
|
||||
<a href="/accounts/login/" class="btn btn-primary btn-block">{% trans 'Login again' %}</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
<!-- /.form-box -->
|
||||
</div><!-- /.card -->
|
||||
</div>
|
||||
<!-- /.register-box -->
|
||||
|
||||
|
||||
|
||||
|
||||
{% endblock %}
|
||||
```
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
@ -1,5 +1,7 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
{% load i18n %}
|
||||
{% get_current_language as CURRENT_LANGUAGE %}
|
||||
<html lang="{{ CURRENT_LANGUAGE }}">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
@ -70,13 +72,16 @@
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" data-widget="pushmenu" href="#" role="button"><i class="fas fa-bars"></i></a>
|
||||
</li>
|
||||
<li class="nav-item d-none d-sm-inline-block">
|
||||
<a href="/status/" class="nav-link">Status</a>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<!-- Right navbar links -->
|
||||
<ul class="navbar-nav ml-auto">
|
||||
<li class="nav-item">
|
||||
<a href="/change_language/" class="nav-link" title="{% trans 'Change Language' %}">
|
||||
<i class="fas fa-language"></i>
|
||||
</a>
|
||||
</li>
|
||||
|
||||
<li class="nav-item">
|
||||
<a href="/accounts/logout/" class="nav-link">
|
||||
<i class="fas fa-sign-out-alt"></i>
|
||||
@ -104,7 +109,7 @@
|
||||
<a href="/status/" class="nav-link {% if '/status/' in request.path %}active{% endif %}">
|
||||
<i class="fas fa-tachometer-alt nav-icon"></i>
|
||||
<p>
|
||||
Status
|
||||
{% trans 'Status' %}
|
||||
</p>
|
||||
</a>
|
||||
</li>
|
||||
@ -150,7 +155,7 @@
|
||||
<a href="/user/list/" class="nav-link {% if '/user/' in request.path %}active{% endif %}">
|
||||
<i class="fas fa-users nav-icon"></i>
|
||||
<p>
|
||||
User Manager
|
||||
{% trans 'User Manager' %}
|
||||
</p>
|
||||
</a>
|
||||
</li>
|
||||
@ -159,7 +164,7 @@
|
||||
<a href="/server/manage/" class="nav-link {% if '/server/' in request.path %}active{% endif %}">
|
||||
<i class="fas fa-cogs nav-icon"></i>
|
||||
<p>
|
||||
Server Settings
|
||||
WireGuard
|
||||
</p>
|
||||
</a>
|
||||
</li>
|
||||
@ -168,7 +173,7 @@
|
||||
<a href="/vpn_invite/" class="nav-link {% if '/vpn_invite/' in request.path %}active{% endif %}">
|
||||
<i class="fas fa-share-square nav-icon"></i>
|
||||
<p>
|
||||
VPN Invite
|
||||
{% trans 'VPN Invite' %}
|
||||
</p>
|
||||
</a>
|
||||
</li>
|
||||
@ -246,9 +251,9 @@
|
||||
<div class="container-fluid">
|
||||
{% if pending_changes_warning %}
|
||||
<div class="alert alert-warning" role="alert">
|
||||
<h4 class="alert-heading">Update Required</h4>
|
||||
<h4 class="alert-heading">{% trans 'Update Required' %}</h4>
|
||||
<p>
|
||||
Your WireGuard settings have been modified. To apply these changes, please update the configuration and reload the WireGuard service.
|
||||
{% trans 'Your WireGuard settings have been modified. To apply these changes, please update the configuration and reload the WireGuard service.' %}
|
||||
</p>
|
||||
<p>
|
||||
<a
|
||||
@ -257,7 +262,7 @@
|
||||
{% else %}
|
||||
href="#" class="btn btn-secondary disabled"
|
||||
{% endif %}
|
||||
>Update and restart service</a>
|
||||
>{% trans 'Update and restart service' %}</a>
|
||||
|
||||
<a
|
||||
{% if user_acl.enable_reload %}
|
||||
@ -265,7 +270,7 @@
|
||||
{% else %}
|
||||
href="#" class="btn btn-secondary disabled"
|
||||
{% endif %}
|
||||
>Update and reload service</a>
|
||||
>{% trans 'Update and reload service' %}</a>
|
||||
</p>
|
||||
|
||||
</div>
|
||||
@ -278,9 +283,9 @@
|
||||
</div>
|
||||
<!-- /.content-wrapper -->
|
||||
<footer class="main-footer">
|
||||
{% if webadmin_version.update_available %}<a class='btn btn-sm btn-danger' id="btn_update_changelog">Update Available</a>{% else %}wireguard-webadmin {% endif %}
|
||||
{% if webadmin_version.update_available %}<a class='btn btn-sm btn-danger' id="btn_update_changelog">{% trans 'Update Available' %}</a>{% else %}wireguard-webadmin {% endif %}
|
||||
<div class="float-right d-none d-sm-inline-block">
|
||||
<b>Version</b> {{ webadmin_version.current_version }}
|
||||
<b>{% trans 'Version' %}</b> {{ webadmin_version.current_version }}
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
|
@ -1,5 +1,7 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
{% load i18n %}
|
||||
{% get_current_language as CURRENT_LANGUAGE %}
|
||||
<html lang="{{ CURRENT_LANGUAGE }}">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
|
17
templates/generic_form_guest.html
Normal file
17
templates/generic_form_guest.html
Normal file
@ -0,0 +1,17 @@
|
||||
{% extends "base_login.html" %}
|
||||
{% load crispy_forms_tags %}
|
||||
{% load i18n %}
|
||||
|
||||
{% block content %}
|
||||
<div class="register-box">
|
||||
<div class="register-logo">
|
||||
<a href="/"><b>wireguard-webadmin</b></a>
|
||||
</div>
|
||||
<div class="card">
|
||||
<div class="card-body register-card-body">
|
||||
{% csrf_token %}
|
||||
{% crispy form %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
3
update_messages.sh
Executable file
3
update_messages.sh
Executable file
@ -0,0 +1,3 @@
|
||||
#!/bin/bash
|
||||
django-admin makemessages -a --ignore=.venv/*
|
||||
django-admin compilemessages --ignore=.venv/*
|
@ -10,6 +10,7 @@ For the full list of settings and their values, see
|
||||
https://docs.djangoproject.com/en/5.0/ref/settings/
|
||||
"""
|
||||
|
||||
import os
|
||||
from pathlib import Path
|
||||
|
||||
# Build paths inside the project like this: BASE_DIR / 'subdir'.
|
||||
@ -38,6 +39,7 @@ INSTALLED_APPS = [
|
||||
'django.contrib.staticfiles',
|
||||
'crispy_forms',
|
||||
'crispy_bootstrap4',
|
||||
'intl_tools',
|
||||
'wireguard',
|
||||
'user_manager',
|
||||
'wireguard_tools',
|
||||
@ -49,6 +51,7 @@ INSTALLED_APPS = [
|
||||
MIDDLEWARE = [
|
||||
'django.middleware.security.SecurityMiddleware',
|
||||
'django.contrib.sessions.middleware.SessionMiddleware',
|
||||
'django.middleware.locale.LocaleMiddleware',
|
||||
'django.middleware.common.CommonMiddleware',
|
||||
'django.middleware.csrf.CsrfViewMiddleware',
|
||||
'django.contrib.auth.middleware.AuthenticationMiddleware',
|
||||
@ -113,17 +116,22 @@ AUTH_PASSWORD_VALIDATORS = [
|
||||
# Internationalization
|
||||
# https://docs.djangoproject.com/en/5.0/topics/i18n/
|
||||
|
||||
LANGUAGE_CODE = 'en-us'
|
||||
LANGUAGE_CODE = 'en'
|
||||
|
||||
TIME_ZONE = 'UTC'
|
||||
|
||||
USE_I18N = True
|
||||
|
||||
USE_L10N = True
|
||||
USE_TZ = True
|
||||
|
||||
LANGUAGES = [
|
||||
('pt-br', 'Português'),
|
||||
('en', 'English'),
|
||||
]
|
||||
|
||||
# Static files (CSS, JavaScript, Images)
|
||||
# https://docs.djangoproject.com/en/5.0/howto/static-files/
|
||||
LOCALE_PATHS = [
|
||||
os.path.join(BASE_DIR, 'locale'),
|
||||
]
|
||||
|
||||
STATIC_URL = 'static/'
|
||||
STATIC_ROOT = '/app_static_files/'
|
||||
|
@ -26,6 +26,7 @@ from dns.views import view_apply_dns_config, view_manage_dns_settings, view_mana
|
||||
from firewall.views import manage_firewall_rule, manage_redirect_rule, view_firewall_migration_required, \
|
||||
view_firewall_rule_list, view_generate_iptables_script, view_manage_firewall_settings, view_redirect_rule_list, \
|
||||
view_reset_firewall
|
||||
from intl_tools.views import view_change_language
|
||||
from user_manager.views import view_manage_user, view_peer_group_list, view_peer_group_manage, view_user_list
|
||||
from vpn_invite.views import view_email_settings, view_vpn_invite_list, view_vpn_invite_settings
|
||||
from vpn_invite_public.views import view_public_vpn_invite
|
||||
@ -85,4 +86,5 @@ urlpatterns = [
|
||||
path('vpn_invite/smtp_settings/', view_email_settings, name='email_settings'),
|
||||
path('invite/', view_public_vpn_invite, name='public_vpn_invite'),
|
||||
path('invite/download_config/', download_config_or_qrcode, name='download_config_or_qrcode'),
|
||||
path('change_language/', view_change_language, name='change_language'),
|
||||
]
|
||||
|
Loading…
x
Reference in New Issue
Block a user