aboutsummaryrefslogtreecommitdiff
path: root/pyaggr3g470r
diff options
context:
space:
mode:
Diffstat (limited to 'pyaggr3g470r')
-rw-r--r--pyaggr3g470r/__init__.py3
-rw-r--r--pyaggr3g470r/templates/home.html12
-rw-r--r--pyaggr3g470r/translations/fr/LC_MESSAGES/messages.mobin0 -> 2717 bytes
-rw-r--r--pyaggr3g470r/translations/fr/LC_MESSAGES/messages.po155
-rw-r--r--pyaggr3g470r/views.py71
5 files changed, 204 insertions, 37 deletions
diff --git a/pyaggr3g470r/__init__.py b/pyaggr3g470r/__init__.py
index 9ba33849..da978128 100644
--- a/pyaggr3g470r/__init__.py
+++ b/pyaggr3g470r/__init__.py
@@ -4,6 +4,7 @@
import os
from flask import Flask
from flask.ext.sqlalchemy import SQLAlchemy
+from flask.ext.babel import Babel
from flask.ext.gravatar import Gravatar
import conf
@@ -27,6 +28,8 @@ def allowed_file(filename):
return '.' in filename and \
filename.rsplit('.', 1)[1] in ALLOWED_EXTENSIONS
+babel = Babel(app)
+
# Gravatar
gravatar = Gravatar(app, size=100, rating='g', default='retro',
force_default=False, use_ssl=False, base_url=None)
diff --git a/pyaggr3g470r/templates/home.html b/pyaggr3g470r/templates/home.html
index 6448fc15..43fdbb97 100644
--- a/pyaggr3g470r/templates/home.html
+++ b/pyaggr3g470r/templates/home.html
@@ -2,19 +2,19 @@
{% block content %}
<div class="container">
{% if result|count == 0 %}
- <h1>You are not subscribed to any feed. <a href="/create_feed/">Fix this</a>.</h1>
+ <h1>{{ _('You are not subscribed to any feed.') }} <a href="/create_feed/">{{ _('Fix this') }}</a>.</h1>
{% else %}
{% for feed in result|sort(attribute="title") %}
<div class="row">
<div class="col-md-6 col-md-offset-3">
<h1>{{ feed.title|safe }}</h1>
- <a href="/articles/{{ feed.id }}/100"><i class="glyphicon glyphicon-th-list" title="More articles"></i></a>
- <a href="/feed/{{ feed.id }}"><i class="glyphicon glyphicon-info-sign" title="Details"></i></a>
- <a href="/edit_feed/{{ feed.id }}"><i class="glyphicon glyphicon-edit" title="Edit this feed"></i></a>
+ <a href="/articles/{{ feed.id }}/100"><i class="glyphicon glyphicon-th-list" title="{{ _('More articles') }}"></i></a>
+ <a href="/feed/{{ feed.id }}"><i class="glyphicon glyphicon-info-sign" title="{{ _('Details') }}"></i></a>
+ <a href="/edit_feed/{{ feed.id }}"><i class="glyphicon glyphicon-edit" title="{{ _('Edit this feed') }}"></i></a>
{% if feed.enabled %}
- <a href="/fetch/{{ feed.id }}"><i class="glyphicon glyphicon-cloud-download" title="Fetch this feed"></i></a>
+ <a href="/fetch/{{ feed.id }}"><i class="glyphicon glyphicon-cloud-download" title="{{ _('Fetch this feed') }}"></i></a>
{% endif %}
- <a href="/mark_as_read/{{ feed.id }}"><i class="glyphicon glyphicon-check" title="Mark all as read"></i></a>
+ <a href="/mark_as_read/{{ feed.id }}"><i class="glyphicon glyphicon-check" title="{{ _('Mark all as read') }}"></i></a>
</div>
</div>
{% for number in range(0, feed.articles.all()|count-(feed.articles.all()|count % 3), 3) %}
diff --git a/pyaggr3g470r/translations/fr/LC_MESSAGES/messages.mo b/pyaggr3g470r/translations/fr/LC_MESSAGES/messages.mo
new file mode 100644
index 00000000..e2f373d0
--- /dev/null
+++ b/pyaggr3g470r/translations/fr/LC_MESSAGES/messages.mo
Binary files differ
diff --git a/pyaggr3g470r/translations/fr/LC_MESSAGES/messages.po b/pyaggr3g470r/translations/fr/LC_MESSAGES/messages.po
new file mode 100644
index 00000000..bcb85625
--- /dev/null
+++ b/pyaggr3g470r/translations/fr/LC_MESSAGES/messages.po
@@ -0,0 +1,155 @@
+# French translations for PROJECT.
+# Copyright (C) 2014 ORGANIZATION
+# This file is distributed under the same license as the PROJECT project.
+# FIRST AUTHOR <EMAIL@ADDRESS>, 2014.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: PROJECT VERSION\n"
+"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
+"POT-Creation-Date: 2014-05-01 11:10+0200\n"
+"PO-Revision-Date: 2014-05-01 11:12+0100\n"
+"Last-Translator: Cédric Bonhomme <cedric@cedricbonhomme.org>\n"
+"Language-Team: fr <LL@li.org>\n"
+"Language: fr\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"
+"Generated-By: Babel 1.3\n"
+"X-Generator: Poedit 1.5.4\n"
+
+#: pyaggr3g470r/views.py:93
+msgid "Authentication required."
+msgstr "Authentification requise."
+
+#: pyaggr3g470r/views.py:98
+msgid "Forbidden."
+msgstr "Interdit."
+
+#: pyaggr3g470r/views.py:141
+msgid "Logged in successfully."
+msgstr "Connecté avec succès."
+
+#: pyaggr3g470r/views.py:161
+msgid "Logged out successfully."
+msgstr "Déconnecté avec succès."
+
+#: pyaggr3g470r/views.py:193
+msgid "Downloading articles..."
+msgstr "Téléchargement des articles."
+
+#: pyaggr3g470r/views.py:281
+msgid "Articles marked as read."
+msgstr "Articles marqués comme lus."
+
+#: pyaggr3g470r/views.py:284
+msgid "All articles marked as read"
+msgstr "Tous les articles marqués comme lus."
+
+#: pyaggr3g470r/views.py:315
+msgid "Article"
+msgstr "Article"
+
+#: pyaggr3g470r/views.py:315
+msgid "deleted."
+msgstr "supprimé."
+
+#: pyaggr3g470r/views.py:318
+msgid "This article do not exist."
+msgstr "Cet article n'existe pas."
+
+#: pyaggr3g470r/views.py:411
+msgid "Database indexed."
+msgstr "Base de données indexée."
+
+#: pyaggr3g470r/views.py:413 pyaggr3g470r/views.py:482
+msgid "An error occured"
+msgstr "Une erreur est survenue."
+
+#: pyaggr3g470r/views.py:416
+msgid "Option not available on Heroku."
+msgstr "Option non disponible sur Heroku."
+
+#: pyaggr3g470r/views.py:431 pyaggr3g470r/views.py:441
+msgid "Error when exporting articles."
+msgstr "Erreur lors de l'export des articles."
+
+#: pyaggr3g470r/views.py:447
+msgid "Export format not supported."
+msgstr "Ce format d'export n'est pas supporté."
+
+#: pyaggr3g470r/views.py:470
+msgid "Full text search is not yet implemented for Heroku."
+msgstr "La recherche rapide n'est pas supporté sur Heroku."
+
+#: pyaggr3g470r/views.py:508
+msgid "File not allowed."
+msgstr "Fichier non autorisé."
+
+#: pyaggr3g470r/views.py:514
+msgid "feeds imported."
+msgstr "flux importés."
+
+#: pyaggr3g470r/views.py:516
+msgid "Impossible to import the new feeds."
+msgstr "Impossible d'importer les nouveaux flux."
+
+#: pyaggr3g470r/views.py:552 pyaggr3g470r/views.py:564
+#: pyaggr3g470r/views.py:567 pyaggr3g470r/views.py:590
+msgid "Feed"
+msgstr "Flux"
+
+#: pyaggr3g470r/views.py:552 pyaggr3g470r/views.py:608
+#: pyaggr3g470r/views.py:652
+msgid "successfully updated."
+msgstr "mis à jour avec succès."
+
+#: pyaggr3g470r/views.py:564 pyaggr3g470r/views.py:663
+msgid "successfully created."
+msgstr "créé avec succès."
+
+#: pyaggr3g470r/views.py:567
+msgid "already in the database."
+msgstr "déjà dans la base de données."
+
+#: pyaggr3g470r/views.py:590 pyaggr3g470r/views.py:703
+msgid "successfully deleted."
+msgstr "supprimé avec succès."
+
+#: pyaggr3g470r/views.py:608 pyaggr3g470r/views.py:652
+#: pyaggr3g470r/views.py:663 pyaggr3g470r/views.py:703
+msgid "User"
+msgstr "Utilisateur"
+
+#: pyaggr3g470r/views.py:689 pyaggr3g470r/views.py:705
+msgid "This user does not exist."
+msgstr "Cet utilisateur n'existe pas."
+
+#: pyaggr3g470r/templates/home.html:5
+msgid "You are not subscribed to any feed."
+msgstr "Vous êtes abonné à aucun flux."
+
+#: pyaggr3g470r/templates/home.html:5
+msgid "Fix this"
+msgstr "Résolvez ce problème."
+
+#: pyaggr3g470r/templates/home.html:11
+msgid "More articles"
+msgstr "Plus d'articles"
+
+#: pyaggr3g470r/templates/home.html:12
+msgid "Details"
+msgstr "Détails"
+
+#: pyaggr3g470r/templates/home.html:13
+msgid "Edit this feed"
+msgstr "Éditer ce flux"
+
+#: pyaggr3g470r/templates/home.html:15
+msgid "Fetch this feed"
+msgstr "Récupérer ce flux"
+
+#: pyaggr3g470r/templates/home.html:17
+msgid "Mark all as read"
+msgstr "Marquer tout comme lu"
diff --git a/pyaggr3g470r/views.py b/pyaggr3g470r/views.py
index 6d2a3b99..05b7e0f6 100644
--- a/pyaggr3g470r/views.py
+++ b/pyaggr3g470r/views.py
@@ -32,6 +32,7 @@ import datetime
from flask import render_template, request, flash, session, url_for, redirect, g, current_app, make_response
from flask.ext.login import LoginManager, login_user, logout_user, login_required, current_user, AnonymousUserMixin
from flask.ext.principal import Principal, Identity, AnonymousIdentity, identity_changed, identity_loaded, Permission, RoleNeed, UserNeed
+from flask.ext.babel import gettext
from sqlalchemy import desc
from werkzeug import generate_password_hash
@@ -41,7 +42,7 @@ import export
if not conf.ON_HEROKU:
import search as fastsearch
from forms import SigninForm, AddFeedForm, ProfileForm
-from pyaggr3g470r import app, db, allowed_file
+from pyaggr3g470r import app, db, allowed_file, babel
from pyaggr3g470r.models import User, Feed, Article, Role
from pyaggr3g470r.decorators import feed_access_required
@@ -89,12 +90,12 @@ def load_user(email):
#
@app.errorhandler(401)
def authentication_required(e):
- flash('Authentication required.', 'info')
+ flash(gettext('Authentication required.'), 'info')
return redirect(url_for('login'))
@app.errorhandler(403)
def authentication_failed(e):
- flash('Forbidden.', 'danger')
+ flash(gettext('Forbidden.'), 'danger')
return redirect(url_for('home'))
@app.errorhandler(404)
@@ -112,6 +113,14 @@ def redirect_url(default='home'):
url_for(default)
+@babel.localeselector
+def get_locale():
+ """
+ Called before each request to give us a chance to choose
+ the language to use when producing its response.
+ """
+ return request.accept_languages.best_match(conf.LANGUAGES.keys())
+
#
# Views.
@@ -129,7 +138,7 @@ def login():
login_user(user)
g.user = user
identity_changed.send(current_app._get_current_object(), identity=Identity(user.id))
- flash("Logged in successfully.", 'success')
+ flash(gettext("Logged in successfully."), 'success')
return redirect(url_for('home'))
return render_template('login.html', form=form)
@@ -149,7 +158,7 @@ def logout():
# Tell Flask-Principal the user is anonymous
identity_changed.send(current_app._get_current_object(), identity=AnonymousIdentity())
- flash("Logged out successfully.", 'success')
+ flash(gettext("Logged out successfully."), 'success')
return redirect(url_for('login'))
@app.route('/')
@@ -181,7 +190,7 @@ def fetch(feed_id=None):
"""
cmd = ['python', conf.basedir+'/fetch.py', g.user.email, str(feed_id)]
p = subprocess.Popen(cmd, stdout=subprocess.PIPE)
- flash("Downloading articles...", 'success')
+ flash(gettext("Downloading articles..."), 'success')
return redirect(redirect_url())
@app.route('/about/', methods=['GET'])
@@ -269,10 +278,10 @@ def mark_as_read(feed_id=None):
if feed_id is not None:
Article.query.filter(Article.user_id == g.user.id, Article.feed_id == feed_id,
Article.readed == False).update({"readed": True})
- flash('Articles marked as read.', 'info')
+ flash(gettext('Articles marked as read.'), 'info')
else:
Article.query.filter(Article.user_id == g.user.id, Article.readed == False).update({"readed": True})
- flash("All articles marked as read", 'info')
+ flash(gettext("All articles marked as read"), 'info')
db.session.commit()
return redirect(redirect_url())
@@ -303,10 +312,10 @@ def delete(article_id=None):
fastsearch.delete_article(g.user.id, article.feed_id, article.id)
except:
pass
- flash('Article "' + article.title + '" deleted.', 'success')
+ flash(gettext('Article') + ' ' + article.title + ' ' + gettext('deleted.'), 'success')
return redirect(url_for('home'))
else:
- flash('This article do not exist.', 'danger')
+ flash(gettext('This article do not exist.'), 'danger')
return redirect(url_for('home'))
@app.route('/articles/<feed_id>/', methods=['GET'])
@@ -399,12 +408,12 @@ def index_database():
user = User.query.filter(User.id == g.user.id).first()
try:
fastsearch.create_index(user)
- flash('Database indexed.', 'success')
+ flash(gettext('Database indexed.'), 'success')
except Exception as e:
- flash('An error occured (%s).' % e, 'danger')
+ flash(gettext('An error occured') + ' (%s).' % e, 'danger')
return redirect(url_for('home'))
else:
- flash('Option not available on Heroku.', 'success')
+ flash(gettext('Option not available on Heroku.'), 'success')
return redirect(url_for('home'))
@app.route('/export/', methods=['GET'])
@@ -419,7 +428,7 @@ def export_articles():
try:
archive_file, archive_file_name = export.export_html(user)
except:
- flash("Error when exporting articles.", 'danger')
+ flash(gettext("Error when exporting articles."), 'danger')
return redirect(redirect_url())
response = make_response(archive_file)
response.headers['Content-Type'] = 'application/x-compressed'
@@ -429,13 +438,13 @@ def export_articles():
try:
json_result = export.export_json(user)
except:
- flash("Error when exporting articles.", 'danger')
+ flash(gettext("Error when exporting articles."), 'danger')
return redirect(redirect_url())
response = make_response(json_result)
response.mimetype = 'application/json'
response.headers["Content-Disposition"] = 'attachment; filename=articles.json'
else:
- flash('Export format not supported.', 'warning')
+ flash(gettext('Export format not supported.'), 'warning')
return redirect(redirect_url())
return response
@@ -458,7 +467,7 @@ def search():
Search articles corresponding to the query.
"""
if conf.ON_HEROKU:
- flash("Full text search is not yet implemented for Heroku.", "warning")
+ flash(gettext("Full text search is not yet implemented for Heroku."), "warning")
return redirect(url_for('home'))
user = User.query.filter(User.id == g.user.id).first()
@@ -470,7 +479,7 @@ def search():
try:
search_result, nb_articles = fastsearch.search(user.id, query)
except Exception as e:
- flash('An error occured (%s).' % e, 'danger')
+ flash(gettext('An error occured') + ' (%s).' % e, 'danger')
for feed_id in search_result:
for feed in user.feeds:
if feed.id == feed_id:
@@ -496,15 +505,15 @@ def management():
# Import an OPML file
data = request.files.get('opmlfile', None)
if None == data or not allowed_file(data.filename):
- flash('File not allowed.', 'danger')
+ flash(gettext('File not allowed.'), 'danger')
else:
opml_path = os.path.join("./pyaggr3g470r/var/", data.filename)
data.save(opml_path)
try:
nb = utils.import_opml(g.user.email, opml_path)
- flash(str(nb) + " feeds imported.", "success")
+ flash(str(nb) + ' ' + gettext('feeds imported.'), "success")
except Exception as e:
- flash("Impossible to import the new feeds.", "danger")
+ flash(gettext("Impossible to import the new feeds."), "danger")
form = AddFeedForm()
@@ -540,7 +549,7 @@ def edit_feed(feed_id=None):
# Edit an existing feed
form.populate_obj(feed)
db.session.commit()
- flash('Feed "' + feed.title + '" successfully updated.', 'success')
+ flash(gettext('Feed') + ' ' + feed.title + ' ' + gettext('successfully updated.'), 'success')
return redirect('/edit_feed/' + str(feed_id))
else:
# Create a new feed
@@ -552,10 +561,10 @@ def edit_feed(feed_id=None):
g.user.feeds.append(new_feed)
#user.feeds = sorted(user.feeds, key=lambda t: t.title.lower())
db.session.commit()
- flash('Feed "' + new_feed.title + '" successfully created.', 'success')
+ flash(gettext('Feed') + ' ' + new_feed.title + ' ' + gettext('successfully created.'), 'success')
return redirect('/edit_feed/' + str(new_feed.id))
else:
- flash('Feed "' + existing_feed[0].title + '" already in the database.', 'warning')
+ flash(gettext('Feed') + ' ' + existing_feed[0].title + ' ' + gettext('already in the database.'), 'warning')
return redirect('/edit_feed/' + str(existing_feed[0].id))
if request.method == 'GET':
@@ -578,7 +587,7 @@ def delete_feed(feed_id=None):
feed = Feed.query.filter(Feed.id == feed_id).first()
db.session.delete(feed)
db.session.commit()
- flash('Feed "' + feed.title + '" successfully deleted.', 'success')
+ flash(gettext('Feed') + ' ' + feed.title + ' ' + gettext('successfully deleted.'), 'success')
return redirect(redirect_url())
@app.route('/profile/', methods=['GET', 'POST'])
@@ -596,7 +605,7 @@ def profile():
if form.password.data != "":
user.set_password(form.password.data)
db.session.commit()
- flash('User "' + user.firstname + '" successfully updated.', 'success')
+ flash(gettext('User') + ' ' + user.firstname + ' ' + gettext('successfully updated.'), 'success')
return redirect(url_for('profile'))
else:
return render_template('profile.html', form=form)
@@ -640,7 +649,7 @@ def create_user(user_id=None):
if form.password.data != "":
user.set_password(form.password.data)
db.session.commit()
- flash('User "' + user.firstname + '" successfully updated.', 'success')
+ flash(gettext('User') + ' ' + user.firstname + ' ' + gettext('successfully updated.'), 'success')
else:
# Create a new user
role_user = Role.query.filter(Role.name == "user").first()
@@ -651,7 +660,7 @@ def create_user(user_id=None):
user.roles.extend([role_user])
db.session.add(user)
db.session.commit()
- flash('User "' + user.firstname + '" successfully created.', 'success')
+ flash(gettext('User') + ' ' + user.firstname + ' ' + gettext('successfully created.'), 'success')
return redirect("/admin/edit_user/"+str(user.id)+"/")
else:
return render_template('profile.html', form=form)
@@ -677,7 +686,7 @@ def user(user_id=None):
if user is not None:
return render_template('/admin/user.html', user=user)
else:
- flash('This user does not exist.', 'danger')
+ flash(gettext('This user does not exist.'), 'danger')
return redirect(redirect_url())
@app.route('/admin/delete_user/<int:user_id>/', methods=['GET'])
@@ -691,7 +700,7 @@ def delete_user(user_id=None):
if user is not None:
db.session.delete(user)
db.session.commit()
- flash('User "' + user.firstname + '" successfully deleted.', 'success')
+ flash(gettext('User') + ' ' + user.firstname + ' ' + gettext('successfully deleted.'), 'success')
else:
- flash('This user does not exist.', 'danger')
+ flash(gettext('This user does not exist.'), 'danger')
return redirect(redirect_url())
bgstack15