mirror of
https://github.com/ziirish/burp-ui.git
synced 2026-05-15 06:05:58 -06:00
add: support translations
This commit is contained in:
parent
b27a836bdc
commit
d14d8fa58b
22 changed files with 437 additions and 62 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
|
@ -1,5 +1,6 @@
|
|||
*.pyc
|
||||
*.swp
|
||||
*.mo
|
||||
burpui-dev.cfg*
|
||||
burpui/RELEASE
|
||||
devel.sh
|
||||
|
|
|
|||
10
babel.cfg
Normal file
10
babel.cfg
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
[python: **.py]
|
||||
encoding = utf-8
|
||||
|
||||
[jinja2: **/templates/**.html]
|
||||
encoding = utf-8
|
||||
extensions=jinja2.ext.autoescape,jinja2.ext.with_
|
||||
|
||||
[jinja2: **/templates/**.js]
|
||||
encoding = utf-8
|
||||
extensions=jinja2.ext.autoescape,jinja2.ext.with_
|
||||
|
|
@ -179,6 +179,7 @@ def init(conf=None, verbose=0, logfile=None, gunicorn=True, unittest=False, debu
|
|||
|
||||
:returns: A :class:`burpui.server.BUIServer` object
|
||||
"""
|
||||
from flask import g
|
||||
from flask_login import LoginManager
|
||||
from flask_bower import Bower
|
||||
from .utils import basic_login_from_request, ReverseProxied, lookup_file
|
||||
|
|
@ -186,6 +187,7 @@ def init(conf=None, verbose=0, logfile=None, gunicorn=True, unittest=False, debu
|
|||
from .routes import view
|
||||
from .api import api, apibp
|
||||
from .ext.cache import cache
|
||||
from .ext.i18n import babel, get_locale
|
||||
|
||||
logger = logging.getLogger('burp-ui')
|
||||
|
||||
|
|
@ -261,6 +263,9 @@ def init(conf=None, verbose=0, logfile=None, gunicorn=True, unittest=False, debu
|
|||
app.gunicorn = gunicorn
|
||||
|
||||
app.config['CFG'] = None
|
||||
|
||||
# Some config
|
||||
|
||||
# FIXME: strange behavior when bundling errors
|
||||
# app.config['BUNDLE_ERRORS'] = True
|
||||
|
||||
|
|
@ -391,6 +396,10 @@ def init(conf=None, verbose=0, logfile=None, gunicorn=True, unittest=False, debu
|
|||
force_scheduling_now()
|
||||
except:
|
||||
pass
|
||||
|
||||
# Initialize i18n
|
||||
babel.init_app(app)
|
||||
|
||||
# Create SQLAlchemy if enabled
|
||||
create_db(app)
|
||||
|
||||
|
|
@ -447,6 +456,10 @@ def init(conf=None, verbose=0, logfile=None, gunicorn=True, unittest=False, debu
|
|||
if app.auth != 'none':
|
||||
return basic_login_from_request(request, app)
|
||||
|
||||
@app.before_request
|
||||
def before_request():
|
||||
g.locale = get_locale()
|
||||
|
||||
return app
|
||||
|
||||
|
||||
|
|
|
|||
28
burpui/ext/i18n.py
Normal file
28
burpui/ext/i18n.py
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
# -*- coding: utf8 -*-
|
||||
"""
|
||||
.. module:: burpui.ext.i18n
|
||||
:platform: Unix
|
||||
:synopsis: Burp-UI external Internationalization module.
|
||||
|
||||
.. moduleauthor:: Ziirish <hi+burpui@ziirish.me>
|
||||
|
||||
"""
|
||||
from flask import request
|
||||
from flask_babel import Babel
|
||||
from flask_login import current_user
|
||||
from ..config import config
|
||||
|
||||
babel = Babel()
|
||||
|
||||
LANGUAGES = {
|
||||
'en': 'English',
|
||||
'fr': 'Français',
|
||||
}
|
||||
config['LANGUAGES'] = LANGUAGES
|
||||
|
||||
@babel.localeselector
|
||||
def get_locale():
|
||||
locale = None
|
||||
if current_user and not current_user.is_anonymous:
|
||||
locale = getattr(current_user, 'language', None)
|
||||
return locale or request.accept_languages.best_match(config['LANGUAGES'].keys())
|
||||
|
|
@ -7,12 +7,15 @@
|
|||
.. moduleauthor:: Ziirish <hi+burpui@ziirish.me>
|
||||
|
||||
"""
|
||||
from .ext.i18n import LANGUAGES, get_locale
|
||||
|
||||
from flask_wtf import Form
|
||||
from wtforms import TextField, PasswordField, BooleanField, validators
|
||||
from flask_babel import gettext
|
||||
from wtforms import TextField, PasswordField, BooleanField, SelectField, validators
|
||||
|
||||
|
||||
class LoginForm(Form):
|
||||
username = TextField('Username', [validators.Length(min=2, max=25)])
|
||||
password = PasswordField('Password', [validators.Required()])
|
||||
remember = BooleanField('Remember me', [validators.Optional()])
|
||||
username = TextField(gettext('Username'), [validators.Length(min=2, max=25)])
|
||||
password = PasswordField(gettext('Password'), [validators.Required()])
|
||||
language = SelectField(gettext('Language'), choices=LANGUAGES.items(), default=get_locale)
|
||||
remember = BooleanField(gettext('Remember me'), [validators.Optional()])
|
||||
|
|
|
|||
|
|
@ -44,6 +44,25 @@ def create_manager():
|
|||
manager, migrate, app = create_manager()
|
||||
|
||||
|
||||
@manager.command
|
||||
def init_translation(language):
|
||||
os.system('pybabel extract -F babel.cfg -k lazy_gettext -o messages.pot burpui')
|
||||
os.system('pybabel init -i messages.pot -d burpui/translations -l {}'.format(language))
|
||||
os.unlink('messages.pot')
|
||||
|
||||
|
||||
@manager.command
|
||||
def update_translation():
|
||||
os.system('pybabel extract -F babel.cfg -k lazy_gettext -o messages.pot burpui')
|
||||
os.system('pybabel update -i messages.pot -d burpui/translations')
|
||||
os.unlink('messages.pot')
|
||||
|
||||
|
||||
@manager.command
|
||||
def compile_translation():
|
||||
os.system('pybabel compile -f -d burpui/translations')
|
||||
|
||||
|
||||
@manager.command
|
||||
def create_user(name, backend='BASIC', password=None, ask=False):
|
||||
print('[*] Adding \'{}\' user...'.format(name))
|
||||
|
|
|
|||
|
|
@ -49,6 +49,7 @@ class UserHandler(BUIuser):
|
|||
sess = session._get_current_object()
|
||||
self.active = False
|
||||
self.authenticated = sess.get('authenticated', False)
|
||||
self.language = sess.get('language', None)
|
||||
self.backends = backends
|
||||
self.back = None
|
||||
self.name = name
|
||||
|
|
@ -83,6 +84,7 @@ class UserHandler(BUIuser):
|
|||
self.authenticated = self.real.login(passwd)
|
||||
sess = session._get_current_object()
|
||||
sess['authenticated'] = self.authenticated
|
||||
sess['language'] = self.language
|
||||
return self.authenticated
|
||||
|
||||
def get_id(self):
|
||||
|
|
|
|||
|
|
@ -12,12 +12,14 @@ import math
|
|||
from flask import request, render_template, redirect, url_for, abort, \
|
||||
flash, Blueprint as FlaskBlueprint, session, current_app
|
||||
from flask_login import login_user, login_required, logout_user, current_user
|
||||
from flask_babel import gettext
|
||||
|
||||
from .server import BUIServer # noqa
|
||||
from ._compat import quote
|
||||
from .forms import LoginForm
|
||||
from .exceptions import BUIserverException
|
||||
from .utils import human_readable as _hr
|
||||
from .ext.i18n import LANGUAGES, get_locale
|
||||
|
||||
|
||||
class Blueprint(FlaskBlueprint):
|
||||
|
|
@ -164,14 +166,14 @@ def live_monitor(server=None, name=None):
|
|||
bui.cli.is_one_backup_running()
|
||||
if bui.standalone:
|
||||
if not bui.cli.running:
|
||||
flash('Sorry, there are no running backups', 'warning')
|
||||
flash(gettext('Sorry, there are no running backups'), 'warning')
|
||||
return redirect(url_for('.home'))
|
||||
else:
|
||||
run = False
|
||||
for a in bui.cli.servers:
|
||||
run = run or (a in bui.cli.running and bui.cli.running[a])
|
||||
if not run:
|
||||
flash('Sorry, there are no running backups', 'warning')
|
||||
flash(gettext('Sorry, there are no running backups'), 'warning')
|
||||
return redirect(url_for('.home'))
|
||||
|
||||
return render_template(
|
||||
|
|
@ -191,7 +193,9 @@ def edit_server_initiated_restore(server=None, name=None):
|
|||
to = None
|
||||
if not data or not data['found']:
|
||||
flash(
|
||||
'Sorry, there are no restore file found for this client',
|
||||
gettext(
|
||||
'Sorry, there are no restore file found for this client'
|
||||
),
|
||||
'warning'
|
||||
)
|
||||
return redirect(url_for('.home'))
|
||||
|
|
@ -227,8 +231,11 @@ def client_browse(server=None, name=None, backup=None, encrypted=None,
|
|||
edit = bui.cli.is_server_restore(to, server)
|
||||
if not edit or not edit['found']:
|
||||
flash(
|
||||
'Sorry, there are no restore file found for this client',
|
||||
gettext(
|
||||
'Sorry, there are no restore file found for this client'
|
||||
),
|
||||
'warning'
|
||||
|
||||
)
|
||||
edit = None
|
||||
else:
|
||||
|
|
@ -369,14 +376,16 @@ def servers_report():
|
|||
@view.route('/login', methods=['POST', 'GET'])
|
||||
def login():
|
||||
form = LoginForm(request.form)
|
||||
|
||||
if form.validate_on_submit():
|
||||
user = bui.uhandler.user(form.username.data)
|
||||
user.language = form.language.data
|
||||
if user.is_active and user.login(form.password.data):
|
||||
login_user(user, remember=form.remember.data)
|
||||
flash('Logged in successfully', 'success')
|
||||
flash(gettext('Logged in successfully'), 'success')
|
||||
return redirect(request.args.get("next") or url_for('.home'))
|
||||
else:
|
||||
flash('Wrong username or password', 'danger')
|
||||
flash(gettext('Wrong username or password'), 'danger')
|
||||
return render_template('login.html', form=form, login=True)
|
||||
|
||||
|
||||
|
|
@ -386,6 +395,8 @@ def logout():
|
|||
sess = session._get_current_object()
|
||||
if 'authenticated' in sess:
|
||||
sess.pop('authenticated')
|
||||
if 'language' in sess:
|
||||
sess.pop('language')
|
||||
logout_user()
|
||||
return redirect(url_for('.home'))
|
||||
|
||||
|
|
|
|||
|
|
@ -5,12 +5,12 @@
|
|||
{% include "small_topbar.html" %}
|
||||
<ul class="breadcrumb" style="margin-bottom: 5px;">
|
||||
{% if server -%}
|
||||
<li><a href="{{ url_for('view.home') }}">Home</a></li>
|
||||
<li><a href="{{ url_for('view.home') }}">{{ _('Home') }}</a></li>
|
||||
<li><a href="{{ url_for('view.clients', server=server) }}">{{ server }} clients</a></li>
|
||||
<li class="active">{{ cname }} overview</li>
|
||||
<li class="active">{{ cname }} {{ _('overview') }}</li>
|
||||
{% else -%}
|
||||
<li><a href="{{ url_for('view.home') }}">Home</a></li>
|
||||
<li class="active">{{ cname }} overview</li>
|
||||
<li><a href="{{ url_for('view.home') }}">{{ _('Home') }}</a></li>
|
||||
<li class="active">{{ cname }} {{ _('overview') }}</li>
|
||||
{% endif -%}
|
||||
</ul>
|
||||
<br />
|
||||
|
|
@ -18,22 +18,22 @@
|
|||
|
||||
<h2 class="sub-header">Backups</h2>
|
||||
<p>
|
||||
Toggle column: <a class="toggle-vis" data-column="0" href="#">Number</a> -
|
||||
Toggle column: <a class="toggle-vis" data-column="0" href="#">{{ _('Number') }}</a> -
|
||||
<a class="toggle-vis" data-column="1" href="#">Date</a> -
|
||||
<a class="toggle-vis" data-column="2" href="#">Bytes received</a> -
|
||||
<a class="toggle-vis" data-column="3" href="#">Estimated size</a> -
|
||||
<a class="toggle-vis" data-column="4" href="#">Deletable</a> -
|
||||
<a class="toggle-vis" data-column="2" href="#">{{ _('Bytes received') }}</a> -
|
||||
<a class="toggle-vis" data-column="3" href="#">{{ _('Estimated size') }}</a> -
|
||||
<a class="toggle-vis" data-column="4" href="#">{{ _('Deletable') }}</a> -
|
||||
<a class="toggle-vis" data-column="5" href="#">Status</a>
|
||||
</p>
|
||||
<div class="table-responsive">
|
||||
<table class="table table-striped table-hover nowrap" id="table-client" width="100%">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Number</th>
|
||||
<th>{{ _('Number') }}</th>
|
||||
<th class="desktop">Date</th>
|
||||
<th class="desktop">Bytes received</th>
|
||||
<th class="desktop">Estimated size</th>
|
||||
<th class="desktop">Deletable</th>
|
||||
<th class="desktop">{{ _('Bytes received') }}</th>
|
||||
<th class="desktop">{{ _('Estimated size') }}</th>
|
||||
<th class="desktop">{{ _('Deletable') }}</th>
|
||||
<th class="desktop">Status</th>
|
||||
</tr>
|
||||
</thead>
|
||||
|
|
@ -41,24 +41,24 @@
|
|||
</tbody>
|
||||
</table>
|
||||
<div class="alert alert-dismissable alert-danger" id="client-alert" style="display: none;">
|
||||
<span class="glyphicon glyphicon-exclamation-sign"></span> <strong>Sorry!</strong> There are no backups for this client.
|
||||
<span class="glyphicon glyphicon-exclamation-sign"></span> <strong>{{ _('Sorry!') }}</strong> {{ _('There are no backups for this client.') }}
|
||||
</div>
|
||||
</div>
|
||||
<br />
|
||||
<div id="left" class="form-inline col-md-6">
|
||||
<div class="edit-restore" style="display: none;">
|
||||
<a href="{{ url_for('view.edit_server_initiated_restore', name=cname, server=server) }}" id="btn-edit-restore" class="btn btn-info"><span class="glyphicon glyphicon-pencil"></span> Edit restore</a>
|
||||
<a href="{{ url_for('view.edit_server_initiated_restore', name=cname, server=server) }}" id="btn-edit-restore" class="btn btn-info"><span class="glyphicon glyphicon-pencil"></span> {{ _('Edit restore') }}</a>
|
||||
</div>
|
||||
<div class="scheduled-backup">
|
||||
<button type="button" id="btn-schedule-backup" class="btn btn-info"><span class="glyphicon glyphicon-time"></span> Schedule backup</button>
|
||||
<button type="button" id="btn-schedule-backup" class="btn btn-info"><span class="glyphicon glyphicon-time"></span> {{ _('Schedule backup') }}</button>
|
||||
</div>
|
||||
</div>
|
||||
<div id="right" class="form-inline col-md-6 text-right">
|
||||
<div class="edit-restore" style="display: none;">
|
||||
<button type="button" id="btn-cancel-restore" class="btn btn-danger"><span class="glyphicon glyphicon-trash"></span> Cancel restore</button>
|
||||
<button type="button" id="btn-cancel-restore" class="btn btn-danger"><span class="glyphicon glyphicon-trash"></span> {{ _('Cancel restore') }}</button>
|
||||
</div>
|
||||
<div class="cancel-backup" style="display: none;">
|
||||
<button type="button" id="btn-cancel-backup" class="btn btn-danger"><span class="glyphicon glyphicon-trash"></span> Cancel backup</button>
|
||||
<button type="button" id="btn-cancel-backup" class="btn btn-danger"><span class="glyphicon glyphicon-trash"></span> {{ _('Cancel backup') }}</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -5,10 +5,10 @@
|
|||
{% include "small_topbar.html" %}
|
||||
<ul class="breadcrumb" style="margin-bottom: 5px;">
|
||||
{% if server -%}
|
||||
<li><a href="{{ url_for('view.home') }}">Home</a></li>
|
||||
<li><a href="{{ url_for('view.home') }}">{{ _('Home') }}</a></li>
|
||||
<li class="active">{{ server }} clients</li>
|
||||
{% else -%}
|
||||
<li class="active">Home</li>
|
||||
<li class="active">{{ _('Home') }}</li>
|
||||
{% endif -%}
|
||||
</ul>
|
||||
<br />
|
||||
|
|
@ -19,9 +19,9 @@
|
|||
<table class="table table-striped table-hover nowrap" id="table-clients" width="100%">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Name</th>
|
||||
<th class="desktop">State</th>
|
||||
<th class="desktop">Last Backup</th>
|
||||
<th>{{ _('Name') }}</th>
|
||||
<th class="desktop">{{ _('State') }}</th>
|
||||
<th class="desktop">{{ _('Last Backup') }}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
|
|
|
|||
|
|
@ -56,6 +56,12 @@
|
|||
<!-- Typeadhead + Bloodhound Javascript
|
||||
================================================== -->
|
||||
<script src="{{ url_for('bower.static', filename='typeahead.js/dist/typeahead.bundle.min.js') }}"></script>
|
||||
<!-- MomentJS
|
||||
================================================== -->
|
||||
<script src="{{ url_for('bower.static', filename='moment/min/moment.min.js') }}"></script>
|
||||
{% if g.locale != 'en' -%}
|
||||
<script src="{{ url_for('bower.static', filename='moment/locale/{}.js'.format(g.locale)) }}"></script>
|
||||
{% endif -%}
|
||||
{% if report -%}
|
||||
<!-- d3 + nvd3 Javascript
|
||||
================================================== -->
|
||||
|
|
@ -101,7 +107,6 @@
|
|||
================================================== -->
|
||||
<script src="{{ url_for('bower.static', filename='angular-bootstrap/ui-bootstrap.min.js') }}"></script>
|
||||
<script src="{{ url_for('bower.static', filename='angular-bootstrap/ui-bootstrap-tpls.min.js') }}"></script>
|
||||
<script src="{{ url_for('bower.static', filename='moment/min/moment.min.js') }}"></script>
|
||||
<script src="{{ url_for('bower.static', filename='angular-ui-calendar/src/calendar.js') }}"></script>
|
||||
<script src="{{ url_for('bower.static', filename='fullcalendar/dist/fullcalendar.min.js') }}"></script>
|
||||
<script src="{{ url_for('bower.static', filename='fullcalendar/dist/gcal.js') }}"></script>
|
||||
|
|
|
|||
|
|
@ -4,9 +4,10 @@
|
|||
{% include "notifications.html" %}
|
||||
<div class="main">
|
||||
<div class="wrapper">
|
||||
{% call macros.render_form(form, action_text='Login', class_='form-signin', btn_class='btn btn-info btn-lg btn-primary btn-block') %}
|
||||
{{ macros.render_field(form.username, placeholder='Username', type='text', autofocus=true) }}
|
||||
{{ macros.render_field(form.password, placeholder='Password', type='password') }}
|
||||
{% call macros.render_form(form, action_text=_('Login'), class_='form-signin', btn_class='btn btn-info btn-lg btn-primary btn-block') %}
|
||||
{{ macros.render_field(form.username, placeholder=_('Username'), type='text', autofocus=true) }}
|
||||
{{ macros.render_field(form.password, placeholder=_('Password'), type='password') }}
|
||||
{{ macros.render_field(form.language) }}
|
||||
{{ macros.render_checkbox_field(form.remember) }}
|
||||
{% endcall %}
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -11,7 +11,6 @@
|
|||
{% macro render_field(field, label_visible=true) -%}
|
||||
|
||||
<div class="form-group {% if field.errors %}has-error{% endif %} {{ kwargs.pop('class_', '') }}">
|
||||
{# {% if (field.id != 'csrf_token' or field.type != 'HiddenField' or field.type !='CSRFTokenField') and label_visible %} #}
|
||||
{% if (field.id != 'csrf_token' or field.type != 'HiddenField') %}
|
||||
<label for="{{ field.id }}" class="control-label">{{ field.label }}</label>
|
||||
{% endif %}
|
||||
|
|
@ -88,6 +87,8 @@
|
|||
{{ render_checkbox_field(f) }}
|
||||
{% elif f.type == 'RadioField' %}
|
||||
{{ render_radio_field(f) }}
|
||||
{% elif f.type == 'SelectField' %}
|
||||
{{ render_select_field(f) }}
|
||||
{% else %}
|
||||
{{ render_field(f) }}
|
||||
{% endif %}
|
||||
|
|
|
|||
|
|
@ -4,16 +4,16 @@
|
|||
<div class="col-sm-9 col-sm-offset-3 col-md-10 col-md-offset-2 main">
|
||||
{% include "small_topbar.html" %}
|
||||
<ul class="breadcrumb" style="margin-bottom: 5px;">
|
||||
<li class="active">Home</li>
|
||||
<li class="active">{{ _('Home') }}</li>
|
||||
</ul>
|
||||
<br />
|
||||
<h1 class="page-header">Servers</h1>
|
||||
<h1 class="page-header">{{ _('Servers') }}</h1>
|
||||
|
||||
<div class="table-responsive">
|
||||
<table class="table table-striped table-hover nowrap" id="table-servers" width="100%">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Name</th>
|
||||
<th>{{ _('Name') }}</th>
|
||||
<th class="desktop">Clients</th>
|
||||
<th class="desktop">Status</th>
|
||||
</tr>
|
||||
|
|
|
|||
|
|
@ -11,32 +11,32 @@
|
|||
<ul class="nav nav-sidebar">
|
||||
<li {% if overview %}class="active"{% endif %}>
|
||||
{% if backup %}
|
||||
<a href="{{ url_for('view.client_browse', name=cname, server=server, backup=nbackup) }}"><span class="glyphicon glyphicon-th"></span> Overview</a>
|
||||
<a href="{{ url_for('view.client_browse', name=cname, server=server, backup=nbackup) }}"><span class="glyphicon glyphicon-th"></span> {{ _('Overview') }}</a>
|
||||
{% elif client %}
|
||||
<a href="{{ url_for('view.client', name=cname, server=server) }}"><span class="glyphicon glyphicon-th"></span> Overview</a>
|
||||
<a href="{{ url_for('view.client', name=cname, server=server) }}"><span class="glyphicon glyphicon-th"></span> {{ _('Overview') }}</a>
|
||||
{% elif clients %}
|
||||
<a href="{{ url_for('view.clients', server=server) }}"><span class="glyphicon glyphicon-th"></span> Overview</a>
|
||||
<a href="{{ url_for('view.clients', server=server) }}"><span class="glyphicon glyphicon-th"></span> {{ _('Overview') }}</a>
|
||||
{% elif servers %}
|
||||
<a href="{{ url_for('view.servers') }}"><span class="glyphicon glyphicon-th"></span> Overview</a>
|
||||
<a href="{{ url_for('view.servers') }}"><span class="glyphicon glyphicon-th"></span> {{ _('Overview') }}</a>
|
||||
{% else %}
|
||||
<a href="#"><span class="glyphicon glyphicon-th"></span> Overview</a>
|
||||
<a href="#"><span class="glyphicon glyphicon-th"></span> {{ _('Overview') }}</a>
|
||||
{% endif %}
|
||||
</li>
|
||||
<li {% if report %}class="active"{% endif %}>
|
||||
{% if client and not backup %}
|
||||
<a href="{{ url_for('view.client_report', name=cname, server=server) }}"><span class="glyphicon glyphicon-stats"></span> Reports</a>
|
||||
<a href="{{ url_for('view.client_report', name=cname, server=server) }}"><span class="glyphicon glyphicon-stats"></span> {{ _('Reports') }}</a>
|
||||
{% elif clients %}
|
||||
<a href="{{ url_for('view.clients_report', server=server) }}"><span class="glyphicon glyphicon-stats"></span> Reports</a>
|
||||
<a href="{{ url_for('view.clients_report', server=server) }}"><span class="glyphicon glyphicon-stats"></span> {{ _('Reports') }}</a>
|
||||
{% elif backup %}
|
||||
<a href="{{ url_for('view.backup_report', name=cname, backup=nbackup, server=server) }}"><span class="glyphicon glyphicon-stats"></span> Reports</a>
|
||||
<a href="{{ url_for('view.backup_report', name=cname, backup=nbackup, server=server) }}"><span class="glyphicon glyphicon-stats"></span> {{ _('Reports') }}</a>
|
||||
{% elif servers %}
|
||||
<a href="{{ url_for('view.servers_report') }}"><span class="glyphicon glyphicon-stats"></span> Reports</a>
|
||||
<a href="{{ url_for('view.servers_report') }}"><span class="glyphicon glyphicon-stats"></span> {{ _('Reports') }}</a>
|
||||
{% else %}
|
||||
<a href="#"><span class="glyphicon glyphicon-stats"></span> Reports</a>
|
||||
<a href="#"><span class="glyphicon glyphicon-stats"></span> {{ _('Reports') }}</a>
|
||||
{% endif %}
|
||||
</li>
|
||||
<li {% if calendar %} class="active"{% endif %}>
|
||||
<a href="{{ url_for('view.calendar', client=cname, server=server) }}"><span class="glyphicon glyphicon-calendar"></span> Calendar</a>
|
||||
<a href="{{ url_for('view.calendar', client=cname, server=server) }}"><span class="glyphicon glyphicon-calendar"></span> {{ _('Calendar') }}</a>
|
||||
</li>
|
||||
</ul>
|
||||
{% endif -%}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
|
||||
<div id="navbar-config">
|
||||
<h4>Configuration navigation</h4>
|
||||
<h4>{{ _('Configuration navigation') }}</h4>
|
||||
<ul class="nav nav-sidebar bui-scrollspy">
|
||||
<li class="active" data-target="#boolean"><a href="#boolean">Booleans</a></li>
|
||||
<li data-target="#string"><a href="#string">Strings</a></li>
|
||||
|
|
@ -8,7 +8,7 @@
|
|||
<li data-target="#multi"><a href="#multi">Multi</a></li>
|
||||
<li data-target="#includes_source"><a href="#includes_source">Includes</a></li>
|
||||
</ul>
|
||||
<h4>Client to configure</h4>
|
||||
<h4>{{ _('Client to configure') }}</h4>
|
||||
<ul class="nav nav-sidebar" ng-cloak>
|
||||
{% raw %}
|
||||
<li>
|
||||
|
|
@ -28,7 +28,7 @@
|
|||
<li>
|
||||
<form action="{{ url_for('api.new_client', server=server) }}" method="POST" ng-submit="createClient($event)">
|
||||
<div class="input-group">
|
||||
<input class="form-control" type="text" name="newclient" id="newclient" placeholder="Create new client">
|
||||
<input class="form-control" type="text" name="newclient" id="newclient" placeholder="{{ _('Create new client') }}">
|
||||
<span class="input-group-btn">
|
||||
<button class="btn btn-success" type="submit"><span class="glyphicon glyphicon-plus"></span></button>
|
||||
</span>
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
<div class="container-fluid">
|
||||
<div class="navbar-header">
|
||||
<button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse">
|
||||
<span class="sr-only">Toggle navigation</span>
|
||||
<span class="sr-only">{{ _('Toggle navigation') }}</span>
|
||||
<span class="icon-bar"></span>
|
||||
<span class="icon-bar"></span>
|
||||
<span class="icon-bar"></span>
|
||||
|
|
@ -13,14 +13,14 @@
|
|||
<ul class="nav navbar-nav navbar-right">
|
||||
<li class="detail {% if about %}active{% endif %}">
|
||||
<a href="{{ url_for('view.about') }}">
|
||||
<span class="glyphicon glyphicon-question-sign"></span><span class="dtl"> About</span>
|
||||
<span class="glyphicon glyphicon-question-sign"></span><span class="dtl"> {{ _('About') }}</span>
|
||||
</a>
|
||||
</li>
|
||||
{% if not login -%}
|
||||
{% if not config.STANDALONE -%}
|
||||
<li class="detail {% if not server and not about %}active{% endif %}">
|
||||
<a href="{{ url_for('view.home') }}">
|
||||
<span class="glyphicon glyphicon-hdd"></span><span class="dtl"> Servers</span>
|
||||
<span class="glyphicon glyphicon-hdd"></span><span class="dtl"> {{ _('Servers') }}</span>
|
||||
</a>
|
||||
</li>
|
||||
{% if server -%}
|
||||
|
|
@ -40,32 +40,32 @@
|
|||
{% if config.STANDALONE or server -%}
|
||||
<li class="detail {% if settings %}active{% endif %}">
|
||||
<a href="{{ url_for('view.settings', server=server) }}">
|
||||
<span class="glyphicon glyphicon-wrench"></span><span class="dtl"> Settings</span>
|
||||
<span class="glyphicon glyphicon-wrench"></span><span class="dtl"> {{ _('Settings') }}</span>
|
||||
</a>
|
||||
</li>
|
||||
{% endif -%}
|
||||
<li class="detail {% if live %}active{% endif %}">
|
||||
<a href="{{ url_for('view.live_monitor', server=server) }}">
|
||||
<span id="toblink" class="glyphicon glyphicon-screenshot"></span><span class="dtl"> Live monitor</span>
|
||||
<span id="toblink" class="glyphicon glyphicon-screenshot"></span><span class="dtl"> {{ _('Live monitor') }}</span>
|
||||
</a>
|
||||
</li>
|
||||
{% if current_user and current_user.is_authenticated -%}
|
||||
<li class="detail">
|
||||
<a href="{{ url_for('view.logout') }}">
|
||||
<span class="glyphicon glyphicon-log-out"></span><span class="dtl"> Logout<small>({{ current_user.get_id() }})</small></span>
|
||||
<span class="glyphicon glyphicon-log-out"></span><span class="dtl"> {{ _('Logout') }}<small>({{ current_user.get_id() }})</small></span>
|
||||
</a>
|
||||
</li>
|
||||
{% endif -%}
|
||||
<li {% if live %}ng-click="refresh"{% endif %}>
|
||||
<a id="refresh" href="#">
|
||||
<span class="glyphicon glyphicon-refresh"></span><span class="hidden-md hidden-lg"> Refresh</span>
|
||||
<span class="glyphicon glyphicon-refresh"></span><span class="hidden-md hidden-lg"> {{ _('Refresh') }}</span>
|
||||
</a>
|
||||
</li>
|
||||
{% endif -%}
|
||||
</ul>
|
||||
{% if not login -%}
|
||||
<form class="navbar-form navbar-right" id="search">
|
||||
<input type="text" class="form-control" id="input-client" placeholder="Search client..." autocomplete="off">
|
||||
<input type="text" class="form-control" id="input-client" placeholder="{{ _('Search client...') }}" autocomplete="off">
|
||||
</form>
|
||||
{% endif -%}
|
||||
</div>
|
||||
|
|
|
|||
178
burpui/translations/fr/LC_MESSAGES/messages.po
Normal file
178
burpui/translations/fr/LC_MESSAGES/messages.po
Normal file
|
|
@ -0,0 +1,178 @@
|
|||
# French translations for Burp-UI.
|
||||
# Copyright (C) 2016 ORGANIZATION
|
||||
# This file is distributed under the same license as the PROJECT project.
|
||||
# Ziirish <hi+burpui@ziirish.me>, 2016.
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PROJECT VERSION\n"
|
||||
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
|
||||
"POT-Creation-Date: 2016-08-25 17:17+0200\n"
|
||||
"PO-Revision-Date: 2016-08-25 15:19+0200\n"
|
||||
"Last-Translator: Ziirish <hi+burpui@ziirish.me>\n"
|
||||
"Language: fr\n"
|
||||
"Language-Team: fr <LL@li.org>\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n > 1)\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=utf-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Generated-By: Babel 2.3.4\n"
|
||||
|
||||
#: burpui/forms.py:18 burpui/templates/login.html:8
|
||||
msgid "Username"
|
||||
msgstr "Utilisateur"
|
||||
|
||||
#: burpui/forms.py:19 burpui/templates/login.html:9
|
||||
msgid "Password"
|
||||
msgstr "Mot de passe"
|
||||
|
||||
#: burpui/forms.py:20
|
||||
msgid "Language"
|
||||
msgstr "Langue"
|
||||
|
||||
#: burpui/forms.py:21
|
||||
msgid "Remember me"
|
||||
msgstr "Rester connecté"
|
||||
|
||||
#: burpui/routes.py:169 burpui/routes.py:176
|
||||
msgid "Sorry, there are no running backups"
|
||||
msgstr "Désolé, il n'y a pas de backups"
|
||||
|
||||
#: burpui/routes.py:196 burpui/routes.py:234
|
||||
msgid "Sorry, there are no restore file found for this client"
|
||||
msgstr "Désolé, il n'y a pas restoration prévue pour ce client"
|
||||
|
||||
#: burpui/routes.py:385
|
||||
msgid "Logged in successfully"
|
||||
msgstr "Connecté avec succès"
|
||||
|
||||
#: burpui/routes.py:388
|
||||
msgid "Wrong username or password"
|
||||
msgstr "Mauvais nom d'utilisateur ou mot de passe"
|
||||
|
||||
#: burpui/templates/client.html:8 burpui/templates/client.html:12
|
||||
#: burpui/templates/clients.html:8 burpui/templates/clients.html:11
|
||||
#: burpui/templates/servers.html:7
|
||||
msgid "Home"
|
||||
msgstr "Accueil"
|
||||
|
||||
#: burpui/templates/client.html:10 burpui/templates/client.html:13
|
||||
msgid "overview"
|
||||
msgstr "aperçu"
|
||||
|
||||
#: burpui/templates/client.html:21 burpui/templates/client.html:32
|
||||
msgid "Number"
|
||||
msgstr "Numéro"
|
||||
|
||||
#: burpui/templates/client.html:23 burpui/templates/client.html:34
|
||||
msgid "Bytes received"
|
||||
msgstr "Octets reçus"
|
||||
|
||||
#: burpui/templates/client.html:24 burpui/templates/client.html:35
|
||||
msgid "Estimated size"
|
||||
msgstr "Taille (estimation)"
|
||||
|
||||
#: burpui/templates/client.html:25 burpui/templates/client.html:36
|
||||
msgid "Deletable"
|
||||
msgstr "Supprimable"
|
||||
|
||||
#: burpui/templates/client.html:44
|
||||
msgid "Sorry!"
|
||||
msgstr "Désolé!"
|
||||
|
||||
#: burpui/templates/client.html:44
|
||||
msgid "There are no backups for this client."
|
||||
msgstr "Il n'y a pas de sauvegardes pour ce client."
|
||||
|
||||
#: burpui/templates/client.html:50
|
||||
msgid "Edit restore"
|
||||
msgstr "Éditer restauration"
|
||||
|
||||
#: burpui/templates/client.html:53
|
||||
msgid "Schedule backup"
|
||||
msgstr "Planifier sauvegarde"
|
||||
|
||||
#: burpui/templates/client.html:58
|
||||
msgid "Cancel restore"
|
||||
msgstr "Annuler restauration"
|
||||
|
||||
#: burpui/templates/client.html:61
|
||||
msgid "Cancel backup"
|
||||
msgstr "Annuler sauvegarde"
|
||||
|
||||
#: burpui/templates/clients.html:22 burpui/templates/servers.html:16
|
||||
msgid "Name"
|
||||
msgstr "Nom"
|
||||
|
||||
#: burpui/templates/clients.html:23
|
||||
msgid "State"
|
||||
msgstr "État"
|
||||
|
||||
#: burpui/templates/clients.html:24
|
||||
msgid "Last Backup"
|
||||
msgstr "Dernière sauvegarde"
|
||||
|
||||
#: burpui/templates/login.html:7
|
||||
msgid "Login"
|
||||
msgstr "Se connecter"
|
||||
|
||||
#: burpui/templates/servers.html:10 burpui/templates/topbar.html:23
|
||||
msgid "Servers"
|
||||
msgstr "Serveurs"
|
||||
|
||||
#: burpui/templates/sidebar.html:14 burpui/templates/sidebar.html:16
|
||||
#: burpui/templates/sidebar.html:18 burpui/templates/sidebar.html:20
|
||||
#: burpui/templates/sidebar.html:22
|
||||
msgid "Overview"
|
||||
msgstr "Aperçu"
|
||||
|
||||
#: burpui/templates/sidebar.html:27 burpui/templates/sidebar.html:29
|
||||
#: burpui/templates/sidebar.html:31 burpui/templates/sidebar.html:33
|
||||
#: burpui/templates/sidebar.html:35
|
||||
msgid "Reports"
|
||||
msgstr "Rapports"
|
||||
|
||||
#: burpui/templates/sidebar.html:39
|
||||
msgid "Calendar"
|
||||
msgstr "Calendrier"
|
||||
|
||||
#: burpui/templates/sideconfig.html:3
|
||||
msgid "Configuration navigation"
|
||||
msgstr "Navigation"
|
||||
|
||||
#: burpui/templates/sideconfig.html:11
|
||||
msgid "Client to configure"
|
||||
msgstr "Client à configurer"
|
||||
|
||||
#: burpui/templates/sideconfig.html:31
|
||||
msgid "Create new client"
|
||||
msgstr "Créer un nouveau client"
|
||||
|
||||
#: burpui/templates/topbar.html:5
|
||||
msgid "Toggle navigation"
|
||||
msgstr "Afficher menu"
|
||||
|
||||
#: burpui/templates/topbar.html:16
|
||||
msgid "About"
|
||||
msgstr "À propos"
|
||||
|
||||
#: burpui/templates/topbar.html:43
|
||||
msgid "Settings"
|
||||
msgstr "Paramètres"
|
||||
|
||||
#: burpui/templates/topbar.html:49
|
||||
msgid "Live monitor"
|
||||
msgstr "Moniteur temps réél"
|
||||
|
||||
#: burpui/templates/topbar.html:55
|
||||
msgid "Logout"
|
||||
msgstr "Se déconnecter"
|
||||
|
||||
#: burpui/templates/topbar.html:61
|
||||
msgid "Refresh"
|
||||
msgstr "Rafraîchir"
|
||||
|
||||
#: burpui/templates/topbar.html:68
|
||||
msgid "Search client..."
|
||||
msgstr "Rechercher client..."
|
||||
|
||||
|
|
@ -19,6 +19,105 @@ You can financially support the project if you find it useful or if you would
|
|||
like to sponsor a feature. Details on my `website <https://ziirish.info/>`__.
|
||||
|
||||
|
||||
Translating
|
||||
-----------
|
||||
|
||||
Translations are very welcome!
|
||||
If you are willing to help, you will need some tools:
|
||||
|
||||
::
|
||||
|
||||
pip install Flask-Babel
|
||||
|
||||
|
||||
Then you need to fork the project retrieve the sources:
|
||||
|
||||
::
|
||||
|
||||
git clone https://git.ziirish.me/<your_login>/burp-ui.git
|
||||
cd burp-ui
|
||||
|
||||
|
||||
You can have the list of available languages by running:
|
||||
|
||||
::
|
||||
|
||||
ls burpui/translations
|
||||
|
||||
|
||||
New language
|
||||
^^^^^^^^^^^^
|
||||
|
||||
If your language is not listed, you can create a new translation running the
|
||||
following command:
|
||||
|
||||
::
|
||||
|
||||
./bui-manage init_translation <country_code> # where <country_code> can be "de", "ru", etc.
|
||||
|
||||
|
||||
Update translation
|
||||
^^^^^^^^^^^^^^^^^^
|
||||
|
||||
If you want to update an existing (and/or un-complete) translation, you probably
|
||||
want to have a look at the *templates* files.
|
||||
|
||||
An un-translated file will contain things like:
|
||||
|
||||
::
|
||||
|
||||
<h1>Some title</h1>
|
||||
|
||||
|
||||
The string *Some title* won't be translated as is.
|
||||
You need to update the template like this:
|
||||
|
||||
::
|
||||
|
||||
<h1>{{ _('Some title') }}</h1>
|
||||
|
||||
|
||||
Then you can update the translation files with the following command:
|
||||
|
||||
::
|
||||
|
||||
./bui-manage update_translation
|
||||
|
||||
|
||||
Translation
|
||||
^^^^^^^^^^^
|
||||
|
||||
Now you can proceed the translation in the file
|
||||
*burpui/translations/<country_code>/LC_MESSAGES/messages.po*.
|
||||
|
||||
It looks like:
|
||||
|
||||
::
|
||||
|
||||
#: burpui/forms.py:18 burpui/templates/login.html:8
|
||||
msgid "Username"
|
||||
msgstr ""
|
||||
|
||||
|
||||
You just have to put the translations in the *msgstr* line like:
|
||||
|
||||
::
|
||||
|
||||
#: burpui/forms.py:18 burpui/templates/login.html:8
|
||||
msgid "Username"
|
||||
msgstr "Utilisateur"
|
||||
|
||||
|
||||
Once it's done, you can push the sources and create a Merge Request on GitLab:
|
||||
|
||||
::
|
||||
|
||||
git checkout -b translation-<country_code>
|
||||
git add burpui/translations/<country_code>/LC_MESSAGES/messages.po
|
||||
git commit -m "<country_code> translation"
|
||||
git push -u origin translation-<country_code>
|
||||
|
||||
|
||||
Issues / Bugs
|
||||
-------------
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
Flask==0.11.1
|
||||
Flask-Login==0.3.2
|
||||
Flask-Bower==1.2.1
|
||||
Flask-Babel==0.11.1
|
||||
Flask-WTF==0.12
|
||||
flask-restplus==0.9.2
|
||||
Flask-Cache==0.13.1
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
Flask==0.11.1
|
||||
Flask-Login==0.3.2
|
||||
Flask-Bower==1.2.1
|
||||
Flask-Babel==0.11.1
|
||||
Flask-WTF==0.12
|
||||
flask-restplus==0.9.2
|
||||
Flask-Cache==0.13.1
|
||||
|
|
|
|||
2
setup.py
2
setup.py
|
|
@ -71,6 +71,7 @@ class BuildStatic(Command):
|
|||
def run(self):
|
||||
os.chdir(ROOT)
|
||||
log.info("getting revision number")
|
||||
call('./bui-manage compile_translation'.split())
|
||||
try:
|
||||
branch = check_output('sed s@^.*/@@g .git/HEAD'.split()).rstrip()
|
||||
ver = open(os.path.join('burpui', 'VERSION')).read().rstrip()
|
||||
|
|
@ -122,6 +123,7 @@ class BuildStatic(Command):
|
|||
'burpui/static/vendor/angular-strap/dist/angular-strap.tpl.min.js',
|
||||
'burpui/static/vendor/angular-onbeforeunload/build/angular-onbeforeunload.js',
|
||||
'burpui/static/vendor/moment/min/moment.min.js',
|
||||
'burpui/static/vendor/moment/locale/fr.js',
|
||||
'burpui/static/vendor/angular-ui-calendar/src/calendar.js',
|
||||
'burpui/static/vendor/fullcalendar/dist/fullcalendar.min.css',
|
||||
'burpui/static/vendor/fullcalendar/dist/fullcalendar.print.css',
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue