add i18n to Snappass

This commit is contained in:
systeembeheerder 2024-02-14 21:38:23 +01:00
parent 455db36189
commit 6d294c63fd
10 changed files with 157 additions and 28 deletions

4
.gitignore vendored
View file

@ -50,3 +50,7 @@ htmlcov/
# virtualenv # virtualenv
venv/ venv/
ENV/ ENV/
# Translatio catalogs
*.mo
*.pot

10
babel.cfg Normal file
View file

@ -0,0 +1,10 @@
# Update Translations:
# (venv) $ pybabel extract -F babel.cfg -o messages.pot .
# (venv) $ pybabel update -i messages.pot -d snappass/translations
# (venv) $ pybabel compile -d snappass/translations
# Add a new language:
# (venv) $ pybabel extract -F babel.cfg -o messages.pot .
# (venv) $ pybabel init -i messages.pot -d snapppass/translations -l <language_code>
[python: snappass/**.py]
[jinja2: snappass/templates/**.html]

View file

@ -5,18 +5,18 @@ import uuid
import redis import redis
from cryptography.fernet import Fernet from cryptography.fernet import Fernet
from flask import abort, Flask, render_template, request, jsonify from flask import abort, Flask, render_template, request, jsonify, g
from redis.exceptions import ConnectionError from redis.exceptions import ConnectionError
from urllib.parse import quote_plus from urllib.parse import quote_plus
from urllib.parse import unquote_plus from urllib.parse import unquote_plus
from distutils.util import strtobool from distutils.util import strtobool
from flask_babel import Babel
NO_SSL = bool(strtobool(os.environ.get('NO_SSL', 'False'))) NO_SSL = bool(strtobool(os.environ.get('NO_SSL', 'False')))
URL_PREFIX = os.environ.get('URL_PREFIX', None) URL_PREFIX = os.environ.get('URL_PREFIX', None)
HOST_OVERRIDE = os.environ.get('HOST_OVERRIDE', None) HOST_OVERRIDE = os.environ.get('HOST_OVERRIDE', None)
TOKEN_SEPARATOR = '~' TOKEN_SEPARATOR = '~'
# Initialize Flask Application # Initialize Flask Application
app = Flask(__name__) app = Flask(__name__)
if os.environ.get('DEBUG'): if os.environ.get('DEBUG'):
@ -25,6 +25,11 @@ app.secret_key = os.environ.get('SECRET_KEY', 'Secret Key')
app.config.update( app.config.update(
dict(STATIC_URL=os.environ.get('STATIC_URL', 'static'))) dict(STATIC_URL=os.environ.get('STATIC_URL', 'static')))
# Set up Babel
def get_locale():
return request.accept_languages.best_match(['en', 'nl'])
babel = Babel(app, locale_selector=get_locale)
# Initialize Redis # Initialize Redis
if os.environ.get('MOCK_REDIS'): if os.environ.get('MOCK_REDIS'):
from fakeredis import FakeStrictRedis from fakeredis import FakeStrictRedis
@ -56,7 +61,6 @@ def check_redis_alive(fn):
return abort(500) return abort(500)
return inner return inner
def encrypt(password): def encrypt(password):
""" """
Take a password string, encrypt it with Fernet symmetric encryption, Take a password string, encrypt it with Fernet symmetric encryption,
@ -212,6 +216,5 @@ def health_check():
def main(): def main():
app.run(host='0.0.0.0') app.run(host='0.0.0.0')
if __name__ == '__main__': if __name__ == '__main__':
main() main()

View file

@ -1,7 +1,7 @@
<!DOCTYPE html> <!DOCTYPE html>
<html lang="en"> <html lang="{{ lang }}">
<head> <head>
<title>Snappass - Share Secrets</title> <title>{{ _('Snappass - Share Secrets') }}</title>
<meta charset="UTF-8"> <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1.0">
@ -13,7 +13,7 @@
<nav class="navbar navbar-default navbar-static-top"> <nav class="navbar navbar-default navbar-static-top">
<div class="container"> <div class="container">
<div class="navbar-header"> <div class="navbar-header">
<a class="navbar-brand" href="/">Share Secret</a> <a class="navbar-brand" href="/">{{ _('Share Secret') }}</a>
</div> </div>
</div> </div>
</nav> </nav>

View file

@ -3,15 +3,15 @@
{% block content %} {% block content %}
<div class="container"> <div class="container">
<section> <section>
<div class="page-header"><h1>Share Secret Link</h1></div> <div class="page-header"><h1>{{ _('Share Secret Link') }}</h1></div>
<p>The secret has been temporarily saved. Send the following URL to your intended recipient.</p> <p>{{ _('The secret has been temporarily saved. Send the following URL to your intended recipient.') }}</p>
<div class="row"> <div class="row">
<div class="col-sm-6 margin-bottom-10"> <div class="col-sm-6 margin-bottom-10">
<input type="text" class="form-control" id="password-link" value="{{ password_link }}" readonly="readonly"> <input type="text" class="form-control" id="password-link" value="{{ password_link }}" readonly="readonly">
</div> </div>
<div class="col-sm-6"> <div class="col-sm-6">
<button title="Copy to clipboard" type="button" class="btn btn-primary copy-clipboard-btn" <button title="{{ _('Copy to clipboard') }}" type="button" class="btn btn-primary copy-clipboard-btn"
id="copy-clipboard-btn" data-clipboard-target="#password-link" id="copy-clipboard-btn" data-clipboard-target="#password-link"
data-placement='bottom'> data-placement='bottom'>
<i class="fa fa-clipboard"></i> <i class="fa fa-clipboard"></i>

View file

@ -3,9 +3,9 @@
{% block content %} {% block content %}
<div class="container"> <div class="container">
<section> <section>
<div class="page-header"><h1>Secret not found</h1></div> <div class="page-header"><h1>{{ _('Secret not found') }}</h1></div>
<p class="lead">The requested URL was not found on the server. This could be because this URL never contained a secret, or because it expired or was revealed earlier.</p> <p class="lead">{{ _('The requested URL was not found on the server. This could be because this URL never contained a secret, or because it expired or was revealed earlier.') }}</p>
<p class="lead">If this URL was sent to you by someone, make sure to check your spelling or ask the person who sent it to you to send a new secret.</p> <p class="lead">{{ _('If this URL was sent to you by someone, make sure to check your spelling or ask the person who sent it to you to send a new secret.') }}</p>
</section> </section>
</div> </div>
{% endblock %} {% endblock %}

View file

@ -3,22 +3,22 @@
{% block content %} {% block content %}
<div class="container"> <div class="container">
<section> <section>
<div class="page-header"><h1>Secret</h1></div> <div class="page-header"><h1>{{ _('Secret') }}</h1></div>
<p>Save the following secret to a secure location.</p> <p>{{ _('Save the following secret to a secure location.') }}</p>
<div class="row"> <div class="row">
<div class="col-sm-6 margin-bottom-10"> <div class="col-sm-6 margin-bottom-10">
<textarea class="form-control" rows="10" cols="50" id="password-text" name="password-text" readonly="readonly">{{ password }}</textarea> <textarea class="form-control" rows="10" cols="50" id="password-text" name="password-text" readonly="readonly">{{ password }}</textarea>
</div> </div>
<div class="col-sm-6"> <div class="col-sm-6">
<button title="Copy to clipboard" type="button" class="btn btn-primary copy-clipboard-btn" <button title="{{ _('Copy to clipboard') }}" type="button" class="btn btn-primary copy-clipboard-btn"
id="copy-clipboard-btn" data-clipboard-target="#password-text" id="copy-clipboard-btn" data-clipboard-target="#password-text"
data-placement='bottom'> data-placement='bottom'>
<i class="fa fa-clipboard"></i> <i class="fa fa-clipboard"></i>
</button> </button>
</div> </div>
</div> </div>
<p>The secret has now been permanently deleted from the system, and the URL will no longer work. Refresh this page to verify.</p> <p>{{ _('The secret has now been permanently deleted from the system, and the URL will no longer work. Refresh this page to verify.' }}</p>
</section> </section>
</div> </div>
{% endblock %} {% endblock %}

View file

@ -4,12 +4,12 @@
<div class="container"> <div class="container">
<section> <section>
<div class="page-header"> <div class="page-header">
<h1>Secret</h1> <h1>{{ _('Secret') }}</h1>
</div> </div>
<p class="lead">You can only reveal the secret once!</p> <p class="lead">{{ _('You can only reveal the secret once!') }}</p>
<div class="row"> <div class="row">
<div class="col-sm-6 margin-bottom-10"> <div class="col-sm-6 margin-bottom-10">
<button id="revealSecret" type="button" class="btn-lg btn-primary">Reveal secret</button> <button id="revealSecret" type="button" class="btn-lg btn-primary">{{ _('Reveal secret') }}</button>
</div> </div>
</div> </div>
</section> </section>

View file

@ -3,27 +3,27 @@
{% block content %} {% block content %}
<div class="container"> <div class="container">
<section> <section>
<div class="page-header"><h1>Set Secret</h1></div> <div class="page-header"><h1>{{ _('Set Secret') }}</h1></div>
<div class="row"> <div class="row">
<form role="form" id="password_create" method="post" autocomplete="off"> <form role="form" id="password_create" method="post" autocomplete="off">
<div class="col-sm-6 margin-bottom-10"> <div class="col-sm-6 margin-bottom-10">
<div class="input-group"> <div class="input-group">
<span class="input-group-addon" id="basic-addon1"><span class="glyphicon glyphicon-lock" aria-hidden="true"></span></span> <span class="input-group-addon" id="basic-addon1"><span class="glyphicon glyphicon-lock" aria-hidden="true"></span></span>
<textarea rows="10" cols="50" id="password" name="password" autofocus="true" class="form-control" placeholder="SnapPass allows you to share secrets in a secure, ephemeral way. Input a single or multi-line secret, its expiration time, and click Generate URL. Share the one-time use URL with your intended recipient." aria-describedby="basic-addon1" autocomplete="off" required></textarea> <textarea rows="10" cols="50" id="password" name="password" autofocus="true" class="form-control" placeholder="{{ _('SnapPass allows you to share secrets in a secure, ephemeral way. Input a single or multi-line secret, its expiration time, and click Generate URL. Share the one-time use URL with your intended recipient.') }}" aria-describedby="basic-addon1" autocomplete="off" required></textarea>
</div> </div>
</div> </div>
<div class="col-sm-2 margin-bottom-10"> <div class="col-sm-2 margin-bottom-10">
<select class="form-control" name="ttl"> <select class="form-control" name="ttl">
<option value="Two Weeks">Two Weeks</option> <option value="Two Weeks">{{ _('Two Weeks') }}</option>
<option value="Week" selected="selected">Week</option> <option value="Week" selected="selected">{{ _('Week') }}</option>
<option value="Day">Day</option> <option value="Day">{{ _('Day') }}</option>
<option value="Hour">Hour</option> <option value="Hour">{{ _('Hour') }}</option>
</select> </select>
</div> </div>
<div class="col-sm-4"> <div class="col-sm-4">
<button type="submit" class="btn btn-primary" id="submit">Generate URL</button> <button type="submit" class="btn btn-primary" id="submit">{{ _('Generate URL') }}</button>
</div> </div>
</form> </form>
</div> </div>

View file

@ -0,0 +1,112 @@
# Dutch translations for PROJECT.
# Copyright (C) 2024 ORGANIZATION
# This file is distributed under the same license as the PROJECT project.
# FIRST AUTHOR <EMAIL@ADDRESS>, 2024.
#
msgid ""
msgstr ""
"Project-Id-Version: PROJECT VERSION\n"
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
"POT-Creation-Date: 2024-02-14 21:09+0100\n"
"PO-Revision-Date: 2024-02-14 21:16+0100\n"
"Last-Translator: \n"
"Language: nl\n"
"Language-Team: nl <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.14.0\n"
#: snappass/templates/base.html:4
msgid "Snappass - Share Secrets"
msgstr ""
#: snappass/templates/base.html:16
msgid "Share Secret"
msgstr "Stel wachtwoord in"
#: snappass/templates/confirm.html:6
msgid "Share Secret Link"
msgstr "Deel wachtwoord link"
#: snappass/templates/confirm.html:7
msgid ""
"The secret has been temporarily saved. Send the following URL to your "
"intended recipient."
msgstr ""
"Het wachtwoord is tijdelijk opgeslagen. Deel de volgende URL aan de "
"bedoelde ontvanger."
#: snappass/templates/confirm.html:14
msgid "Copy to clipboard"
msgstr "Kopieer naar het klembord"
#: snappass/templates/expired.html:6
msgid "Secret not found"
msgstr "Wachtwoord niet gevonden"
#: snappass/templates/expired.html:7
msgid ""
"The requested URL was not found on the server. This could be because this"
" URL never contained a secret, or because it expired or was revealed "
"earlier."
msgstr ""
"De gevraagde URL is niet gevonden op de server. Dat kan omdat deze geen "
"wachtwoord bevat, het is verlopen of het al eerder getoond is."
#: snappass/templates/expired.html:8
msgid ""
"If this URL was sent to you by someone, make sure to check your spelling "
"or ask the person who sent it to you to send a new secret."
msgstr ""
"Als deze URL naar u is toegestuurd, controleer de spelling of vraag de "
"verzender om een nieuw wachtwoord link te versturen."
#: snappass/templates/preview.html:7
msgid "Secret"
msgstr "Wachtwoord"
#: snappass/templates/preview.html:9
msgid "You can only reveal the secret once!"
msgstr "Het wachtwoord wordt slechts eenmaal getoond!"
#: snappass/templates/preview.html:12
msgid "Reveal secret"
msgstr "Onthul wachtwoord"
#: snappass/templates/set_password.html:6
msgid "Set Secret"
msgstr "Stel wachtwoord in"
#: snappass/templates/set_password.html:12
msgid ""
"SnapPass allows you to share secrets in a secure, ephemeral way. Input a "
"single or multi-line secret, its expiration time, and click Generate URL."
" Share the one-time use URL with your intended recipient."
msgstr ""
"We stellen je in staat om wachtwoorden op een veilige, tijdelijke manier "
"te delen. Voer een enkel- of meerregelig wachwoord in, stel de vervaltijd"
" in, en klik op 'URL genereren'. Deel de eenmalig te gebruiken URL met de"
" beoogde ontvanger."
#: snappass/templates/set_password.html:18
msgid "Two Weeks"
msgstr "Twee weken"
#: snappass/templates/set_password.html:19
msgid "Week"
msgstr "Week"
#: snappass/templates/set_password.html:20
msgid "Day"
msgstr "Dag"
#: snappass/templates/set_password.html:21
msgid "Hour"
msgstr "Uur"
#: snappass/templates/set_password.html:26
msgid "Generate URL"
msgstr "URL genereren"