aboutsummaryrefslogtreecommitdiff
path: root/ihatemoney
diff options
context:
space:
mode:
Diffstat (limited to 'ihatemoney')
-rw-r--r--ihatemoney/default_settings.py1
-rw-r--r--ihatemoney/run.py10
-rw-r--r--ihatemoney/static/css/main.css13
-rw-r--r--ihatemoney/static/images/globe.svg1
-rw-r--r--ihatemoney/static/images/glyphicons-halflings-white.pngbin4352 -> 0 bytes
-rw-r--r--ihatemoney/static/images/glyphicons-halflings.pngbin4352 -> 0 bytes
-rw-r--r--ihatemoney/templates/layout.html86
-rw-r--r--ihatemoney/utils.py14
-rw-r--r--ihatemoney/web.py7
9 files changed, 93 insertions, 39 deletions
diff --git a/ihatemoney/default_settings.py b/ihatemoney/default_settings.py
index 6033d0a..82e6a43 100644
--- a/ihatemoney/default_settings.py
+++ b/ihatemoney/default_settings.py
@@ -8,3 +8,4 @@ ACTIVATE_DEMO_PROJECT = True
ADMIN_PASSWORD = ""
ALLOW_PUBLIC_PROJECT_CREATION = True
ACTIVATE_ADMIN_DASHBOARD = False
+SUPPORTED_LANGUAGES = ['en', 'fr', 'nl']
diff --git a/ihatemoney/run.py b/ihatemoney/run.py
index e9b3ce1..41598ce 100644
--- a/ihatemoney/run.py
+++ b/ihatemoney/run.py
@@ -10,7 +10,8 @@ from werkzeug.contrib.fixers import ProxyFix
from ihatemoney.api import api
from ihatemoney.models import db
-from ihatemoney.utils import PrefixedWSGI, minimal_round, IhmJSONEncoder
+from ihatemoney.utils import (IhmJSONEncoder, PrefixedWSGI, locale_from_iso,
+ minimal_round, static_include)
from ihatemoney.web import main as web_interface
from ihatemoney import default_settings
@@ -135,6 +136,8 @@ def create_app(configuration=None, instance_path='/etc/ihatemoney',
app.mail = mail
# Jinja filters
+ app.jinja_env.globals['static_include'] = static_include
+ app.jinja_env.globals['locale_from_iso'] = locale_from_iso
app.jinja_env.filters['minimal_round'] = minimal_round
# Translations
@@ -144,7 +147,10 @@ def create_app(configuration=None, instance_path='/etc/ihatemoney',
def get_locale():
# get the lang from the session if defined, fallback on the browser "accept
# languages" header.
- lang = session.get('lang', request.accept_languages.best_match(['fr', 'en']))
+ lang = session.get(
+ 'lang',
+ request.accept_languages.best_match(app.config['SUPPORTED_LANGUAGES'])
+ )
setattr(g, 'lang', lang)
return lang
diff --git a/ihatemoney/static/css/main.css b/ihatemoney/static/css/main.css
index ae056c8..47ede77 100644
--- a/ihatemoney/static/css/main.css
+++ b/ihatemoney/static/css/main.css
@@ -328,3 +328,16 @@ tr:hover .extra-info {
.row-fluid > .offset1 {
margin-left: 8.5%;
}
+
+.globe-europe svg {
+ display: inline-block;
+ border-bottom: 0.2em solid transparent;
+ height: 1.2em;
+ fill: rgba(255,255,255,.5)
+}
+.navbar-nav .dropdown-toggle:hover .globe-europe svg {
+ fill: rgba(255,255,255,.75);
+}
+.navbar-dark .navbar-nav .show > .nav-link svg {
+ fill: white;
+} \ No newline at end of file
diff --git a/ihatemoney/static/images/globe.svg b/ihatemoney/static/images/globe.svg
new file mode 100644
index 0000000..5982330
--- /dev/null
+++ b/ihatemoney/static/images/globe.svg
@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 496 512"><path d="M248 8C111 8 0 119 0 256s111 248 248 248 248-111 248-248S385 8 248 8zm200 248c0 22.5-3.9 44.2-10.8 64.4h-20.3c-4.3 0-8.4-1.7-11.4-4.8l-32-32.6c-4.5-4.6-4.5-12.1.1-16.7l12.5-12.5v-8.7c0-3-1.2-5.9-3.3-8l-9.4-9.4c-2.1-2.1-5-3.3-8-3.3h-16c-6.2 0-11.3-5.1-11.3-11.3 0-3 1.2-5.9 3.3-8l9.4-9.4c2.1-2.1 5-3.3 8-3.3h32c6.2 0 11.3-5.1 11.3-11.3v-9.4c0-6.2-5.1-11.3-11.3-11.3h-36.7c-8.8 0-16 7.2-16 16v4.5c0 6.9-4.4 13-10.9 15.2l-31.6 10.5c-3.3 1.1-5.5 4.1-5.5 7.6v2.2c0 4.4-3.6 8-8 8h-16c-4.4 0-8-3.6-8-8s-3.6-8-8-8H247c-3 0-5.8 1.7-7.2 4.4l-9.4 18.7c-2.7 5.4-8.2 8.8-14.3 8.8H194c-8.8 0-16-7.2-16-16V199c0-4.2 1.7-8.3 4.7-11.3l20.1-20.1c4.6-4.6 7.2-10.9 7.2-17.5 0-3.4 2.2-6.5 5.5-7.6l40-13.3c1.7-.6 3.2-1.5 4.4-2.7l26.8-26.8c2.1-2.1 3.3-5 3.3-8 0-6.2-5.1-11.3-11.3-11.3H258l-16 16v8c0 4.4-3.6 8-8 8h-16c-4.4 0-8-3.6-8-8v-20c0-2.5 1.2-4.9 3.2-6.4l28.9-21.7c1.9-.1 3.8-.3 5.7-.3C358.3 56 448 145.7 448 256zM130.1 149.1c0-3 1.2-5.9 3.3-8l25.4-25.4c2.1-2.1 5-3.3 8-3.3 6.2 0 11.3 5.1 11.3 11.3v16c0 3-1.2 5.9-3.3 8l-9.4 9.4c-2.1 2.1-5 3.3-8 3.3h-16c-6.2 0-11.3-5.1-11.3-11.3zm128 306.4v-7.1c0-8.8-7.2-16-16-16h-20.2c-10.8 0-26.7-5.3-35.4-11.8l-22.2-16.7c-11.5-8.6-18.2-22.1-18.2-36.4v-23.9c0-16 8.4-30.8 22.1-39l42.9-25.7c7.1-4.2 15.2-6.5 23.4-6.5h31.2c10.9 0 21.4 3.9 29.6 10.9l43.2 37.1h18.3c8.5 0 16.6 3.4 22.6 9.4l17.3 17.3c3.4 3.4 8.1 5.3 12.9 5.3H423c-32.4 58.9-93.8 99.5-164.9 103.1z"/></svg> \ No newline at end of file
diff --git a/ihatemoney/static/images/glyphicons-halflings-white.png b/ihatemoney/static/images/glyphicons-halflings-white.png
deleted file mode 100644
index a20760b..0000000
--- a/ihatemoney/static/images/glyphicons-halflings-white.png
+++ /dev/null
Binary files differ
diff --git a/ihatemoney/static/images/glyphicons-halflings.png b/ihatemoney/static/images/glyphicons-halflings.png
deleted file mode 100644
index 92d4445..0000000
--- a/ihatemoney/static/images/glyphicons-halflings.png
+++ /dev/null
Binary files differ
diff --git a/ihatemoney/templates/layout.html b/ihatemoney/templates/layout.html
index 84e75b4..10bb628 100644
--- a/ihatemoney/templates/layout.html
+++ b/ihatemoney/templates/layout.html
@@ -28,56 +28,72 @@
</head>
<body>
<div class="container">
- <nav class="navbar navbar-expand-sm fixed-top navbar-dark bg-dark">
+ <nav class="navbar navbar-expand-lg fixed-top navbar-dark bg-dark">
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarToggler" aria-controls="navbarToggler" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<h1><a class="navbar-brand" href="{{ url_for("main.home") }}">#! money?</a></h1>
- {% if g.project %}<strong class="d-block d-sm-none text-white">{{ g.project.name }}</strong>{% endif %}
+ {% if g.project %}
+ <ul class="navbar-nav mr-auto">
+ <li class="nav-item dropdown">
+ <a href="#" class="nav-link dropdown-toggle" id="navbarProjectsLinks" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
+ <strong class="text-white">{{ g.project.name }}</strong>
+ <b class="caret"></b>
+ </a>
+ <ul class="dropdown-menu" aria-labelledby="navbarProjectsLinks">
+ <li><a class="dropdown-item" href="{{ url_for("main.create_project") }}">{{ _("Start a new project") }}</a></li>
+
+ {% if (session['projects'] | length) > 1 %}
+ <li class="dropdown-divider"></li>
+ <li class="dropdown-header">{{ _('Other projects :') }}</li>
+ {% for id, name in session['projects'] %}
+ {% if id != g.project.id %}
+ <li><a class="dropdown-item" href="{{ url_for("main.list_bills", project_id=id) }}">{{ _("switch to") }} {{ name }}</a></li>
+ {% endif %}
+ {% endfor %}
+ {% endif %}
+ </ul>
+ </li>
+ </ul>
+ {% endif %}
<div class="collapse navbar-collapse" id="navbarToggler">
<ul class="navbar-nav ml-auto mr-auto">
{% if g.project %}
- <li class="nav-item">
- </li>
-
- {% block navbar %}
- <li class="nav-item{% if current_view == 'list_bills' %} active{% endif %}"><a class="nav-link" href="{{ url_for("main.list_bills") }}">{{ _("Bills") }}</a></li>
- <li class="nav-item{% if current_view == 'settle_bill' %} active{% endif %}"><a class="nav-link" href="{{ url_for("main.settle_bill") }}">{{ _("Settle") }}</a></li>
- <li class="nav-item{% if current_view == 'statistics' %} active{% endif %}"><a class="nav-link" href="{{ url_for("main.statistics") }}">{{ _("Statistics") }}</a></li>
- {% endblock %}
+ {% block navbar %}
+ <li class="nav-item{% if current_view == 'list_bills' %} active{% endif %}"><a class="nav-link" href="{{ url_for("main.list_bills") }}">{{ _("Bills") }}</a></li>
+ <li class="nav-item{% if current_view == 'settle_bill' %} active{% endif %}"><a class="nav-link" href="{{ url_for("main.settle_bill") }}">{{ _("Settle") }}</a></li>
+ <li class="nav-item{% if current_view == 'statistics' %} active{% endif %}"><a class="nav-link" href="{{ url_for("main.statistics") }}">{{ _("Statistics") }}</a></li>
+ <li class="nav-item{% if current_view == 'edit_project' %} active{% endif %}""><a class="nav-link" href="{{ url_for("main.edit_project") }}">{{ _("Settings") }}</a></li>
+ {% endblock %}
{% endif %}
- {% if g.project %}
+ </ul>
+ <ul class="navbar-nav ml-auto">
<li class="nav-item dropdown">
- <a href="#" class="nav-link dropdown-toggle" id="navbarDropdownMenuLink" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
- <strong class="d-none d-sm-inline">{{ g.project.name }}</strong> {{ _("options") }}
+ <a class="nav-link dropdown-toggle" href="#" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false" id="langMenuButton">
+ <i class="globe-europe">{{ static_include("images/globe.svg") | safe }}</i>
+ {% if g.lang %}
+ {{ locale_from_iso(g.lang).display_name | capitalize }}
+ {% else %}
+ {{ _('Languages') }}
+ {% endif %}
<b class="caret"></b>
</a>
- <ul class="dropdown-menu" aria-labelledby="navbarDropdownMenuLink">
- <li><a class="dropdown-item" href="{{ url_for("main.edit_project") }}">{{ _("Project settings") }}</a></li>
- <li class="dropdown-divider"></li>
- {% for id, name in session['projects'] %}
- {% if id != g.project.id %}
- <li><a class="dropdown-item" href="{{ url_for("main.list_bills", project_id=id) }}">{{ _("switch to") }} {{ name }}</a></li>
- {% endif %}
- {% endfor %}
- <li><a class="dropdown-item" href="{{ url_for("main.create_project") }}">{{ _("Start a new project") }}</a></li>
- {% if g.show_admin_dashboard_link %}
- <li class="dropdown-divider"></li>
- <li class="nav-item{% if request.url_rule.endpoint == "main.dashboard" %} active{% endif %}">
- <a class="dropdown-item" href="{{ url_for("main.dashboard") }}">{{ _("Dashboard") }}</a>
- </li>
- {% endif %}
- <li class="dropdown-divider"></li>
- <li><a class="dropdown-item" href="{{ url_for("main.exit") }}">{{ _("Logout") }}</a></li>
- </ul>
+ <div class="dropdown-menu" aria-labelledby="langMenuButton">
+ <h6 class="dropdown-header">{{ _('Languages') }}</h6>
+ {% for lang in config['SUPPORTED_LANGUAGES'] %}
+ {% if g.lang != lang %}
+ <a class="dropdown-item" href="{{ url_for("main.change_lang", lang=lang)}}">{{ locale_from_iso(lang).display_name | capitalize }}</a>
+ {% endif %}
+ {% endfor %}
+ </div>
+ </li>
+ {% if (session['projects'] | length) > 0 or session['is_admin'] %}
+ <li class="nav-item">
+ <a class="nav-link" href="{{ url_for("main.exit") }}">{{ _("Logout") }}</a>
</li>
{% endif %}
</ul>
- <ul class="navbar-nav secondary-nav">
- <li class="nav-item{% if g.lang == "fr" %} active{% endif %}"><a class="nav-link" href="{{ url_for("main.change_lang", lang="fr") }}">fr</a></li>
- <li class="nav-item{% if g.lang == "en" %} active{% endif %}"><a class="nav-link" href="{{ url_for("main.change_lang", lang="en") }}">en</a></li>
- </ul>
</div>
</nav>
</div>
diff --git a/ihatemoney/utils.py b/ihatemoney/utils.py
index 2fac4ef..393667e 100644
--- a/ihatemoney/utils.py
+++ b/ihatemoney/utils.py
@@ -1,13 +1,15 @@
from __future__ import division
import base64
import re
+import os
import ast
import operator
from io import BytesIO, StringIO
import jinja2
from json import dumps, JSONEncoder
-from flask import redirect
+from flask import redirect, current_app
+from babel import Locale
from werkzeug.routing import HTTPException, RoutingException
import six
from datetime import datetime, timedelta
@@ -93,6 +95,16 @@ def minimal_round(*args, **kw):
return (res if res != ires else ires)
+def static_include(filename):
+ fullpath = os.path.join(current_app.static_folder, filename)
+ with open(fullpath, 'r') as f:
+ return f.read()
+
+
+def locale_from_iso(iso_code):
+ return Locale(iso_code)
+
+
def list_of_dicts2json(dict_to_convert):
"""Take a list of dictionnaries and turns it into
a json in-memory file
diff --git a/ihatemoney/web.py b/ihatemoney/web.py
index f6f04af..b70bc5f 100644
--- a/ihatemoney/web.py
+++ b/ihatemoney/web.py
@@ -343,7 +343,12 @@ def edit_project():
edit_form.name.data = g.project.name
edit_form.contact_email.data = g.project.contact_email
- return render_template("edit_project.html", edit_form=edit_form, export_form=export_form)
+ return render_template(
+ "edit_project.html",
+ edit_form=edit_form,
+ export_form=export_form,
+ current_view="edit_project"
+ )
@main.route("/<project_id>/delete")