Skip to content

Commit

Permalink
fix #47 and improve l10n
Browse files Browse the repository at this point in the history
  • Loading branch information
zeratax committed Dec 15, 2020
1 parent 8698bd5 commit 6e7561f
Show file tree
Hide file tree
Showing 10 changed files with 82 additions and 175 deletions.
5 changes: 0 additions & 5 deletions babel.cfg

This file was deleted.

2 changes: 1 addition & 1 deletion matrix_registration/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,5 @@
from . import tokens
from . import config

__version__ = '0.8.0.dev0'
__version__ = '0.8.0.dev1'
name = 'matrix_registration'
17 changes: 10 additions & 7 deletions matrix_registration/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,13 @@
PasswordField,
validators
)
from flask.ext.babel import Babel, gettext

# Local imports...
from .matrix_api import create_account
from . import config
from . import tokens
from .translation import get_translations


auth = HTTPTokenAuth(scheme='SharedSecret')
logger = logging.getLogger(__name__)
Expand Down Expand Up @@ -126,11 +127,6 @@ class RegistrationForm(Form):
])


@babel.localeselector
def get_locale():
return request.args.get('lang') or request.accept_languages.best


@auth.verify_token
def verify_token(token):
return token == config.config.admin_secret
Expand Down Expand Up @@ -212,11 +208,18 @@ def register():
else:
server_name = config.config.server_name
pw_length = config.config.password['min_length']
lang = request.args.get('lang') or request.accept_languages.best
replacements = {
'server_name': server_name,
'pw_length': pw_length
}
translations = get_translations(lang, replacements)
return render_template('register.html',
server_name=server_name,
pw_length=pw_length,
riot_instance=config.config.riot_instance,
base_url=config.config.base_url)
base_url=config.config.base_url,
translations=translations)


@api.route('/token', methods=['GET', 'POST'])
Expand Down
2 changes: 0 additions & 2 deletions matrix_registration/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
import json

from flask import Flask
from flask.ext.babel import Babel, gettext
from flask.cli import FlaskGroup, pass_script_info
from flask_limiter import Limiter
from flask_limiter.util import get_ipaddr
Expand All @@ -19,7 +18,6 @@
def create_app(testing=False):
app = Flask(__name__)
app.testing = testing
babel = Babel(app)

with app.app_context():
from .api import api
Expand Down
2 changes: 0 additions & 2 deletions matrix_registration/static/css/style.css
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ body {
}

body {
background-image: url("/static/images/valley.jpg");
background-size: cover;
background-attachment: fixed;
overflow: hidden;
Expand Down Expand Up @@ -207,7 +206,6 @@ label {
z-index: -1;
width: 100%;
height: 100%;
background-image: url("/static/images/valley.jpg");
background-attachment: fixed;
background-size: cover;
opacity: 0.20;
Expand Down
64 changes: 35 additions & 29 deletions matrix_registration/templates/register.html
Original file line number Diff line number Diff line change
Expand Up @@ -4,28 +4,33 @@
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width initial-scale=1.0" />
<meta property="og:title" content='{{ gettext("%(server_name)s registration", server_name=server_name) }}'>
<meta property="og:title" content="{{ translations.server_registration }}">
<meta property="og:site_name" content="{{ server_name }}">
<meta property="og:type" content="website" />
<meta name="og:description" content='{{ gettext("registrate an account on %(server_name)s", server_name=server_name) }}'/>
<meta name="og:description" content="{{ translations.register_account }}"/>
<meta name="og:image" content="{{ url_for('static', filename='images/icon.png') }}" />
<link rel="apple-touch-icon" sizes="180x180" href="{{ url_for('static', filename='images/icon.png') }}">
<link rel="icon" type="image/png" href="{{ url_for('static', filename='images/icon32x32.png') }}" sizes="32x32">
<link rel="shortcut icon" href="{{ url_for('static', filename='images/favicon.ico') }}">
<meta name="msapplication-TileImage" content="{{ url_for('static', filename='images/tile.png') }}">
<meta name="msapplication-TileColor" content="#fff">
<title>'{{ gettext("%(server_name)s registration", server_name=server_name) }}'</title>
<title>{{ translations.server_registration }}</title>
<link rel="stylesheet" href="{{ url_for('static', filename='css/style.css') }}">
<link href="https://fonts.googleapis.com/css?family=Nunito" rel="stylesheet">
<style>
body, .widget::before {
background-image: url("/static/images/valley.jpg");

This comment has been minimized.

Copy link
@spantaleev

spantaleev Dec 16, 2020

Perhaps {{ base_url }}/static/images/valley.jpg or url_for('static', filename='images/valley.jpg')?

}
</style>
</head>

<body class="blur">
<article class="widget register">
<div class="center">
<header>
<h1>{{ gettext("%(server_name)s registration", server_name=server_name) }}</h1>
<p>{{ gettext("the registration requires a secret token") }}<br>
{{ gettext("registration does not require an email, just a username and a password that\'s longer than %(pw_length)d characters.", pw_length=pw_length) }}</p>
<h1>{{ translations.server_registration }}</h1>
<p>{{ translations.requires_token }}<br>
{{ translations.requires_username_and_password }}</p>
</header>
<section>
<form id="registration" action="{{ base_url }}/register" method="post">
Expand All @@ -35,29 +40,29 @@ <h1>{{ gettext("%(server_name)s registration", server_name=server_name) }}</h1>
maxlength="200">
<span class="highlight"></span>
<span class="bar"></span>
<label for="username">{{ gettext("Username") }}</label>
<label for="username">{{ translations.username }}</label>
</div>
<div class="group">
<input id="password" name="password" type="password" placeholder=" " required minlength="{{ pw_length }}"
maxlength="128">
<span class="highlight"></span>
<span class="bar"></span>
<label for="password">{{ gettext("Password") }}</label>
<label for="password">{{ translations.password }}</label>
</div>
<div class="group">
<input id="confirm_password" name="confirm" type="password" placeholder=" " required>
<span class="highlight"></span>
<span class="bar"></span>
<label for="confirm_password">{{ gettext("Confirm") }}</label>
<label for="confirm_password">{{ translations.confirm }}</label>
</div>
<div class="group">
<input id="token" name="token" type="text" placeholder=" " required pattern="^([A-Z][a-z]+)+$">
<span class="highlight"></span>
<span class="bar"></span>
<label for="token">{{ gettext("Token") }}</label>
<label for="token">{{ translations.token }}</label>
</div>
<div class="btn-box">
<input class="btn btn-submit" type="submit" value='{{ gettext("register") }}'>
<input class="btn btn-submit" type="submit" value="{{ translations.register }}">
</div>
</form>
</section>
Expand All @@ -69,20 +74,20 @@ <h1>{{ gettext("%(server_name)s registration", server_name=server_name) }}</h1>
<h2 id="welcome"></h2>
</header>
<section>
<p> {{ gettext("Click here to login in:") }}</p>
<h3><a href="{{ riot_instance }}"><img src="static/images/riot.png" height="50px"></a></h3>
<p>{{ gettext("or choose one of the many other clients here:") }} <a href="https://matrix.org/docs/projects/clients-matrix"
<p> {{ translations.click_to_login }}</p>
<h3><a href="{{ riot_instance }}"><img src="{{ url_for('static', filename='images/icon32x32.png') }}" height="100px"></a></h3>
<p>{{ translations.choose_client }} <a href="https://matrix.org/docs/projects/clients-matrix"
a>https://matrix.org/docs/projects/clients-matrix</a></p>
</section>
</div>
</article>
<article id="error" class="widget modal hidden">
<div class="center">
<header>
<h2>{{ gettext("Error") }}</h2>
<h2>{{ translations.error }}</h2>
</header>
<section>
<p>{{ gettext("There was an error while trying to register you.") }}</p>
<p>{{ translations.error_long }}</p>
<h3 id="error_message" class="error"></h3>
<p id="error_dialog"></p>
</section>
Expand Down Expand Up @@ -127,9 +132,10 @@ <h3 id="error_message" class="error"></h3>
document.getElementById("token").value = urlParams.get("token")

// set "?lang=" parameter to user lang
const userLang = getCookie('lang') || navigator.language || navigator.userLanguage
if (!urlParams.has("lang")) {
const userLang = navigator.language || navigator.userLanguage
if (!urlParams.has("lang")) {
urlParams.append("lang", userLang)
window.history.replaceState({}, '', `${location.pathname}?${urlParams}`);
}

// html5 validators
Expand All @@ -140,31 +146,31 @@ <h3 id="error_message" class="error"></h3>

username.addEventListener("input", function (event) {
if (username.validity.typeMismatch) {
username.setCustomValidity('{{ gettext("format: @username:%(server_name)s", server_name=server_name) }}')
username.setCustomValidity("{{ translations.username_format }}")
} else {
username.setCustomValidity("")
}
})

token.addEventListener("input", function (event) {
if (token.validity.typeMismatch) {
token.setCustomValidity('{{ gettext("case-sensitive, e.g: SardineImpactReport") }}')
token.setCustomValidity("{{ translations.case_sensitive }}")
} else {
token.setCustomValidity("")
}
})

password.addEventListener("input", function (event) {
if (password.validity.typeMismatch) {
password.setCustomValidity('{{ gettext("atleast %(pw_length)s characters long", pw_length=pw_length) }}')
password.setCustomValidity('{{ translations.password_too_short }}')
} else {
password.setCustomValidity("")
}
})

function validatePassword() {
if (password.value != confirm_password.value) {
confirm_password.setCustomValidity('{{ gettext("passwords don\'t match") }}')
confirm_password.setCustomValidity("{{ translations.password_do_not_match }}")
} else {
confirm_password.setCustomValidity("")
}
Expand Down Expand Up @@ -198,33 +204,33 @@ <h3 id="error_message" class="error"></h3>
console.log(response)
} catch (e) {
if (e instanceof SyntaxError) {
showError('{{ gettext("Internal Server Error!") }}, {{ gettext("Please contact the server admin about this.") }}')
showError("{{ translations.internal_error }}")
return
}
}
if ("errcode" in response) {
if (response["errcode"] == "MR_BAD_USER_REQUEST") {
if ("token" in response["error"]) {
showError('{{ gettext("Token Error") }}', response["error"]["token"][0])
showError(" {{ translations.token_error }} ", response["error"]["token"][0])
} else if ("password" in response["error"]) {
showError('{{ gettext("Password Error") }}', response["error"]["password"][0])
showError("{{ translations.password_error }}", response["error"]["password"][0])
} else if ("username" in response["error"]) {
showError('{{ gettext("Username Error") }}', response["error"]["username"][0])
showError("{{ translations.username_error }}", response["error"]["username"][0])
}
return
} else {
showError('{{ gettext("Homeserver Error") }}', response["error"])
showError("{{ translations.homeserver_error }}", response["error"])
}
} else {
document.getElementById("welcome").innerHTML = '{{ gettext("Welcome") }}' + response['user_id']
document.getElementById("welcome").innerHTML = "{{ translations.welcome }}" + response['user_id']
document.getElementById("success").classList.remove("hidden")
}

})

// Define what happens in case of error
XHR.addEventListener("error", function (event) {
showError('{{ gettext("Internal Server Error!") }}, {{ gettext("Please contact the server admin about this.") }}')
showError("{{ translations.internal_error }}")
})

// Set up our request
Expand Down
36 changes: 36 additions & 0 deletions matrix_registration/translation.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import os
import re

import yaml

from .constants import __location__


replace_pattern = re.compile(r'{{\s*(?P<name>.[a-zA-Z_\-]+)\s*}}')


def get_translations(lang='en', replacements={}):
default = _get_translations(replacements=replacements)
try:
selected = _get_translations(lang=lang, replacements=replacements)
return {**default, **selected}
except IOError:
return default


def _get_translations(lang='en', replacements={}):
path = os.path.join(__location__, f'translations/messages.{lang}.yaml')

with open(path, 'r') as stream:
translations = yaml.load(stream, Loader=yaml.SafeLoader)

interpolated_translations = {}
for key, value in translations['weblate'].items():
match = re.search(replace_pattern, value)
while match:
value = value.replace(match.group(0), str(replacements[match.group('name')]))
match = re.search(replace_pattern, value)

interpolated_translations[key] = value

return interpolated_translations
1 change: 0 additions & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,6 @@ def find_version(*file_paths):
install_requires=[
"appdirs~=1.4.3",
"Flask~=1.1",
"Flask-Babel>=1.0.0"
"Flask-SQLAlchemy~=2.4.1",
"flask-cors~=3.0.7",
"flask-httpauth>=3.3.0",
Expand Down
1 change: 0 additions & 1 deletion shell.nix
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ buildPythonPackage rec {
pkgs.libsndfile
appdirs
flask
flask-babel
flask-cors
flask-httpauth
flask-limiter
Expand Down

0 comments on commit 6e7561f

Please sign in to comment.