babel integration
This commit is contained in:
parent
0bba066527
commit
cac572cb0e
|
@ -3,4 +3,5 @@
|
|||
app.db
|
||||
search.db
|
||||
flask
|
||||
*.mo
|
||||
|
||||
|
|
|
@ -4,6 +4,7 @@ from flask.ext.sqlalchemy import SQLAlchemy
|
|||
from flask.ext.login import LoginManager
|
||||
from flask.ext.openid import OpenID
|
||||
from flask.ext.mail import Mail
|
||||
from flask.ext.babel import Babel, lazy_gettext
|
||||
from config import basedir, ADMINS, MAIL_SERVER, MAIL_PORT, MAIL_USERNAME, MAIL_PASSWORD
|
||||
from momentjs import momentjs
|
||||
|
||||
|
@ -13,8 +14,10 @@ db = SQLAlchemy(app)
|
|||
lm = LoginManager()
|
||||
lm.init_app(app)
|
||||
lm.login_view = 'login'
|
||||
lm.login_message = lazy_gettext('Please log in to access this page.')
|
||||
oid = OpenID(app, os.path.join(basedir, 'tmp'))
|
||||
mail = Mail(app)
|
||||
babel = Babel(app)
|
||||
|
||||
if not app.debug:
|
||||
import logging
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
from flask.ext.wtf import Form, TextField, BooleanField, TextAreaField
|
||||
from flask.ext.wtf import Required, Length
|
||||
from flask.ext.babel import gettext
|
||||
from app.models import User
|
||||
|
||||
class LoginForm(Form):
|
||||
|
@ -19,9 +20,12 @@ class EditForm(Form):
|
|||
return False
|
||||
if self.nickname.data == self.original_nickname:
|
||||
return True
|
||||
if self.nickname.data != User.make_valid_nickname(self.nickname.data):
|
||||
self.nickname.errors.append(gettext('This nickname has invalid characters. Please use letters, numbers, dots and underscores only.'))
|
||||
return False
|
||||
user = User.query.filter_by(nickname = self.nickname.data).first()
|
||||
if user != None:
|
||||
self.nickname.errors.append('This nickname is already in use. Please choose another one.')
|
||||
self.nickname.errors.append(gettext('This nickname is already in use. Please choose another one.'))
|
||||
return False
|
||||
return True
|
||||
|
||||
|
|
|
@ -2,6 +2,7 @@ from hashlib import md5
|
|||
from app import db
|
||||
from app import app
|
||||
import flask.ext.whooshalchemy as whooshalchemy
|
||||
import re
|
||||
|
||||
ROLE_USER = 0
|
||||
ROLE_ADMIN = 1
|
||||
|
@ -26,6 +27,10 @@ class User(db.Model):
|
|||
backref = db.backref('followers', lazy = 'dynamic'),
|
||||
lazy = 'dynamic')
|
||||
|
||||
@staticmethod
|
||||
def make_valid_nickname(nickname):
|
||||
return re.sub('[^a-zA-Z0-9_\.]', '', nickname)
|
||||
|
||||
@staticmethod
|
||||
def make_unique_nickname(nickname):
|
||||
if User.query.filter_by(nickname = nickname).first() == None:
|
||||
|
|
|
@ -0,0 +1,4 @@
|
|||
// moment.js language configuration
|
||||
// language : spanish (es)
|
||||
// author : Julio Napurí : https://github.com/julionc
|
||||
(function(){function e(e){e.lang("es",{months:"enero_febrero_marzo_abril_mayo_junio_julio_agosto_septiembre_octubre_noviembre_diciembre".split("_"),monthsShort:"ene._feb._mar._abr._may._jun._jul._ago._sep._oct._nov._dic.".split("_"),weekdays:"domingo_lunes_martes_mi\u00e9rcoles_jueves_viernes_s\u00e1bado".split("_"),weekdaysShort:"dom._lun._mar._mi\u00e9._jue._vie._s\u00e1b.".split("_"),weekdaysMin:"Do_Lu_Ma_Mi_Ju_Vi_S\u00e1".split("_"),longDateFormat:{LT:"H:mm",L:"DD/MM/YYYY",LL:"D \\de MMMM \\de YYYY",LLL:"D \\de MMMM \\de YYYY LT",LLLL:"dddd, D \\de MMMM \\de YYYY LT"},calendar:{sameDay:function(){return"[hoy a la"+(this.hours()!==1?"s":"")+"] LT"},nextDay:function(){return"[ma\u00f1ana a la"+(this.hours()!==1?"s":"")+"] LT"},nextWeek:function(){return"dddd [a la"+(this.hours()!==1?"s":"")+"] LT"},lastDay:function(){return"[ayer a la"+(this.hours()!==1?"s":"")+"] LT"},lastWeek:function(){return"[el] dddd [pasado a la"+(this.hours()!==1?"s":"")+"] LT"},sameElse:"L"},relativeTime:{future:"en %s",past:"hace %s",s:"unos segundos",m:"un minuto",mm:"%d minutos",h:"una hora",hh:"%d horas",d:"un d\u00eda",dd:"%d d\u00edas",M:"un mes",MM:"%d meses",y:"un a\u00f1o",yy:"%d a\u00f1os"},ordinal:function(e){return"\u00ba"},week:{dow:1,doy:4}})}typeof define=="function"&&define.amd&&define(["moment"],e),typeof window!="undefined"&&window.moment&&e(window.moment)})();
|
|
@ -2,6 +2,6 @@
|
|||
{% extends "base.html" %}
|
||||
|
||||
{% block content %}
|
||||
<h1>File Not Found</h1>
|
||||
<p><a href="{{url_for('index')}}">Back</a></p>
|
||||
<h1>{{ _('File Not Found') }}</h1>
|
||||
<p><a href="{{url_for('index')}}">{{ _('Back') }}</a></p>
|
||||
{% endblock %}
|
|
@ -2,7 +2,7 @@
|
|||
{% extends "base.html" %}
|
||||
|
||||
{% block content %}
|
||||
<h1>An unexpected error has occurred</h1>
|
||||
<p>The administrator has been notified. Sorry for the inconvenience!</p>
|
||||
<p><a href="{{url_for('index')}}">Back</a></p>
|
||||
<h1>{{ _('An unexpected error has occurred') }}</h1>
|
||||
<p>{{ _('The administrator has been notified. Sorry for the inconvenience!') }}</p>
|
||||
<p><a href="{{url_for('index')}}">{{ _('Back') }}</a></p>
|
||||
{% endblock %}
|
|
@ -11,6 +11,9 @@
|
|||
<script src="http://code.jquery.com/jquery-latest.js"></script>
|
||||
<script src="/static/js/bootstrap.min.js"></script>
|
||||
<script src="/static/js/moment.min.js"></script>
|
||||
{% if g.locale != 'en' %}
|
||||
<script src="/static/js/moment-{{g.locale}}.min.js"></script>
|
||||
{% endif %}
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
</head>
|
||||
<body>
|
||||
|
@ -24,15 +27,15 @@
|
|||
</a>
|
||||
<a class="brand" href="/">microblog</a>
|
||||
<ul class="nav">
|
||||
<li><a href="{{ url_for('index') }}">Home</a></li>
|
||||
<li><a href="{{ url_for('index') }}">{{ _('Home') }}</a></li>
|
||||
{% if g.user.is_authenticated() %}
|
||||
<li><a href="{{ url_for('user', nickname = g.user.nickname) }}">Your Profile</a></li>
|
||||
<li><a href="{{ url_for('logout') }}">Logout</a></li>
|
||||
<li><a href="{{ url_for('user', nickname = g.user.nickname) }}">{{ _('Your Profile') }}</a></li>
|
||||
<li><a href="{{ url_for('logout') }}">{{ _('Logout') }}</a></li>
|
||||
{% endif %}
|
||||
</ul>
|
||||
<div class="nav-collapse collapse">
|
||||
{% if g.user.is_authenticated() %}
|
||||
<form class="navbar-search pull-right" action="{{url_for('search')}}" method="post" name="search">{{g.search_form.hidden_tag()}}{{g.search_form.search(size=20,placeholder="Search",class="search-query")}}</form>
|
||||
<form class="navbar-search pull-right" action="{{url_for('search')}}" method="post" name="search">{{g.search_form.hidden_tag()}}{{g.search_form.search(size=20,placeholder=_('Search'),class="search-query")}}</form>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
|
@ -45,3 +48,4 @@
|
|||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
|
|
|
@ -2,13 +2,13 @@
|
|||
{% extends "base.html" %}
|
||||
|
||||
{% block content %}
|
||||
<h1>Edit Your Profile</h1>
|
||||
<h1>{{ _('Edit Your Profile') }}</h1>
|
||||
{% include 'flash.html' %}
|
||||
<div class="well">
|
||||
<form class="form-horizontal" action="" method="post" name="edit">
|
||||
{{form.hidden_tag()}}
|
||||
<div class="control-group{% if form.errors.post %} error{% endif %}">
|
||||
<label class="control-label" for="nickname">Your nickname:</label>
|
||||
<label class="control-label" for="nickname">{{ _('Your nickname:') }}</label>
|
||||
<div class="controls">
|
||||
{{ form.nickname(maxlength = 64, class = "span4") }}
|
||||
{% for error in form.errors.nickname %}
|
||||
|
@ -17,7 +17,7 @@
|
|||
</div>
|
||||
</div>
|
||||
<div class="control-group{% if form.errors.post %} error{% endif %}">
|
||||
<label class="control-label" for="about_me">About yourself:</label>
|
||||
<label class="control-label" for="about_me">{{ _('About yourself:') }}</label>
|
||||
<div class="controls">
|
||||
{{ form.about_me(cols = 64, rows = 4, class = "span4") }}
|
||||
{% for error in form.errors.about_me %}
|
||||
|
@ -27,7 +27,7 @@
|
|||
</div>
|
||||
<div class="control-group">
|
||||
<div class="controls">
|
||||
<input class="btn btn-primary" type="submit" value="Save Changes">
|
||||
<input class="btn btn-primary" type="submit" value="{{ _('Save Changes') }}">
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<p>Dear {{user.nickname}},</p>
|
||||
<p><a href="{{url_for("user", nickname = follower.nickname, _external = True)}}">{{follower.nickname}}</a> is now a follower.</p>
|
||||
<p>{{ _('%(nickname)s is now a follower.', nickname = '<a href="' + url_for("user", nickname = follower.nickname, _external = True) + '">' + follower.nickname + '</a>') }}</p>
|
||||
<table>
|
||||
<tr valign="top">
|
||||
<td><img src="{{follower.avatar(50)}}"></td>
|
||||
|
@ -9,5 +9,5 @@
|
|||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<p>Regards,</p>
|
||||
<p>The <code>microblog</code> admin</p>
|
||||
<p>{{ _('Regards,') }}</p>
|
||||
<p>{{ _('The <code>microblog</code> admin') }}</p>
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
Dear {{user.nickname}},
|
||||
{{ _('Dear %(nickname)s,', nickname = user.nickname) }}
|
||||
|
||||
{{follower.nickname}} is now a follower. Click on the following link to visit {{follower.nickname}}'s profile page:
|
||||
{{ _('%(nickname)s is now a follower. Click on the following link to visit %(nickname)s\'s profile page:', nickname = follower.nickname) }}
|
||||
|
||||
{{url_for("user", nickname = follower.nickname, _external = True)}}
|
||||
|
||||
Regards,
|
||||
{{ _('Regards,') }}
|
||||
|
||||
The microblog admin
|
||||
{{ _('The microblog admin') }}
|
||||
|
|
|
@ -2,13 +2,13 @@
|
|||
{% extends "base.html" %}
|
||||
|
||||
{% block content %}
|
||||
<h1>Hi, {{g.user.nickname}}!</h1>
|
||||
<h1>{{ _('Hi, %(nickname)s!', nickname = g.user.nickname) }}</h1>
|
||||
{% include 'flash.html' %}
|
||||
<div class="well">
|
||||
<form class="form-horizontal" action="" method="post" name="post">
|
||||
{{form.hidden_tag()}}
|
||||
<div class="control-group{% if form.errors.post %} error{% endif %}">
|
||||
<label class="control-label" for="post">Say something:</label>
|
||||
<label class="control-label" for="post">{{ _('Say something:') }}</label>
|
||||
<div class="controls">
|
||||
{{ form.post(size = 30, maxlength = 140) }}
|
||||
{% for error in form.errors.post %}
|
||||
|
@ -18,7 +18,7 @@
|
|||
</div>
|
||||
<div class="control-group">
|
||||
<div class="controls">
|
||||
<input class="btn btn-primary" type="submit" value="Post!">
|
||||
<input class="btn btn-primary" type="submit" value="{{ _('Post!') }}">
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
|
@ -28,14 +28,14 @@
|
|||
{% endfor %}
|
||||
<ul class="pager">
|
||||
{% if posts.has_prev %}
|
||||
<li class="previous"><a href="{{ url_for('index', page = posts.prev_num) }}">Newer posts</a></li>
|
||||
<li class="previous"><a href="{{ url_for('index', page = posts.prev_num) }}">{{ _('Newer posts') }}</a></li>
|
||||
{% else %}
|
||||
<li class="previous disabled"><a href="#">Newer posts</a></li>
|
||||
<li class="previous disabled"><a href="#">{{ _('Newer posts') }}</a></li>
|
||||
{% endif %}
|
||||
{% if posts.has_next %}
|
||||
<li class="next"><a href="{{ url_for('index', page = posts.next_num) }}">Older posts</a></li>
|
||||
<li class="next"><a href="{{ url_for('index', page = posts.next_num) }}">{{ _('Older posts') }}</a></li>
|
||||
{% else %}
|
||||
<li class="next disabled"><a href="#">Older posts</a></li>
|
||||
<li class="next disabled"><a href="#">{{ _('Older posts') }}</a></li>
|
||||
{% endif %}
|
||||
</ul>
|
||||
{% endblock %}
|
||||
{% endblock %}
|
||||
|
|
|
@ -17,17 +17,17 @@ function set_openid(openid, pr)
|
|||
</script>
|
||||
{% include 'flash.html' %}
|
||||
<div class="well">
|
||||
<h3>Please Sign In</h3>
|
||||
<h3>{{ _('Please Sign In') }}</h3>
|
||||
<form class="form" action="" method="post" name="login">
|
||||
{{form.hidden_tag()}}
|
||||
<div class="help-block">Click on your OpenID provider below:</div>
|
||||
<div class="help-block">{{ _('Click on your OpenID provider below:') }}</div>
|
||||
<div class="control-group">
|
||||
{% for pr in providers %}
|
||||
<a href="javascript:set_openid('{{pr.url}}', '{{pr.name}}');"><img src="/static/img/{{pr.name.lower()}}.png" class="img-polaroid" style="margin:2px;" /></a>
|
||||
{% endfor %}
|
||||
</div>
|
||||
<div class="control-group{% if form.errors.openid %} error{% endif %}">
|
||||
<label class="control-label" for="openid">Or enter your OpenID here:</label>
|
||||
<label class="control-label" for="openid">{{ _('Or enter your OpenID here:') }}</label>
|
||||
<div class="controls">
|
||||
{{ form.openid(size = 80, class = "span4") }}
|
||||
{% for error in form.errors.openid %}
|
||||
|
@ -38,13 +38,13 @@ function set_openid(openid, pr)
|
|||
<div class="control-group">
|
||||
<div class="controls">
|
||||
<label class="checkbox" for="remember_me">
|
||||
{{ form.remember_me }} Remember Me
|
||||
{{ form.remember_me }} {{ _('Remember Me') }}
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="control-group">
|
||||
<div class="controls">
|
||||
<input class="btn btn-primary" type="submit" value="Sign In">
|
||||
<input class="btn btn-primary" type="submit" value="{{ _('Sign In') }}">
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
|
|
|
@ -2,7 +2,9 @@
|
|||
<tr>
|
||||
<td width="70px"><a href="{{url_for('user', nickname = post.author.nickname)}}"><img src="{{post.author.avatar(70)}}" /></a></td>
|
||||
<td>
|
||||
<p><a href="{{url_for('user', nickname = post.author.nickname)}}">{{post.author.nickname}}</a> said {{momentjs(post.timestamp).fromNow()}}:</p>
|
||||
{% autoescape false %}
|
||||
<p>{{ _('%(nickname)s said %(when)s:', nickname = '<a href="%s">%s</a>' % (url_for('user', nickname = post.author.nickname), post.author.nickname), when = momentjs(post.timestamp).fromNow()) }}</p>
|
||||
{% endautoescape %}
|
||||
<p><strong>{{post.body}}</strong></p>
|
||||
</td>
|
||||
</tr>
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
{% extends "base.html" %}
|
||||
|
||||
{% block content %}
|
||||
<h1>Search results for "{{query}}":</h1>
|
||||
<h1>{{ _('Search results for "%(query)s":', query = query) }}</h1>
|
||||
{% include 'flash.html' %}
|
||||
{% for post in results %}
|
||||
{% include 'post.html' %}
|
||||
|
|
|
@ -10,15 +10,15 @@
|
|||
<h1>{{user.nickname}}</h1>
|
||||
{% if user.about_me %}<p>{{user.about_me}}</p>{% endif %}
|
||||
{% if user.last_seen %}
|
||||
<p><em>Last seen: {{momentjs(user.last_seen).calendar()}}</em></p>
|
||||
<p><em>{{ _('Last seen:') }} {{ momentjs(user.last_seen).calendar() }}</em></p>
|
||||
{% endif %}
|
||||
<p>Followers: {{user.followers.count() - 1}} | Following: {{user.followed.count() - 1}} |
|
||||
<p>{{ _('Followers:') }} {{user.followers.count() - 1}} | {{ _('Following:') }} {{user.followed.count() - 1}} |
|
||||
{% if user.id == g.user.id %}
|
||||
<a href="{{url_for('edit')}}">Edit your profile</a>
|
||||
<a href="{{url_for('edit')}}">{{ _('Edit your profile') }}</a>
|
||||
{% elif not g.user.is_following(user) %}
|
||||
<a href="{{url_for('follow', nickname = user.nickname)}}">Follow</a>
|
||||
<a href="{{url_for('follow', nickname = user.nickname)}}">{{ _('Follow') }}</a>
|
||||
{% else %}
|
||||
<a href="{{url_for('unfollow', nickname = user.nickname)}}">Unfollow</a>
|
||||
<a href="{{url_for('unfollow', nickname = user.nickname)}}">{{ _('Unfollow') }}</a>
|
||||
{% endif %}
|
||||
</p>
|
||||
</div>
|
||||
|
@ -27,14 +27,14 @@
|
|||
{% endfor %}
|
||||
<ul class="pager">
|
||||
{% if posts.has_prev %}
|
||||
<li class="previous"><a href="{{ url_for('user', nickname = user.nickname, page = posts.prev_num) }}">Newer posts</a></li>
|
||||
<li class="previous"><a href="{{ url_for('user', nickname = user.nickname, page = posts.prev_num) }}">{{ _('Newer posts') }}</a></li>
|
||||
{% else %}
|
||||
<li class="previous disabled"><a href="#">Newer posts</a></li>
|
||||
<li class="previous disabled"><a href="#">{{ _('Newer posts') }}</a></li>
|
||||
{% endif %}
|
||||
{% if posts.has_next %}
|
||||
<li class="next"><a href="{{ url_for('user', nickname = user.nickname, page = posts.next_num) }}">Older posts</a></li>
|
||||
<li class="next"><a href="{{ url_for('user', nickname = user.nickname, page = posts.next_num) }}">{{ _('Older posts') }}</a></li>
|
||||
{% else %}
|
||||
<li class="next disabled"><a href="#">Older posts</a></li>
|
||||
<li class="next disabled"><a href="#">{{ _('Older posts') }}</a></li>
|
||||
{% endif %}
|
||||
</ul>
|
||||
{% endblock %}
|
||||
|
|
|
@ -0,0 +1,218 @@
|
|||
# Spanish translations for PROJECT.
|
||||
# Copyright (C) 2013 ORGANIZATION
|
||||
# This file is distributed under the same license as the PROJECT project.
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, 2013.
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PROJECT VERSION\n"
|
||||
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
|
||||
"POT-Creation-Date: 2013-01-31 23:19-0800\n"
|
||||
"PO-Revision-Date: 2013-01-31 23:19-0800\n"
|
||||
"Last-Translator: Miguel Grinberg <miguel.grinberg@gmail.com>\n"
|
||||
"Language-Team: es <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 0.9.6\n"
|
||||
"X-Generator: Poedit 1.5.4\n"
|
||||
|
||||
#: app/__init__.py:17
|
||||
msgid "Please log in to access this page."
|
||||
msgstr "Por favor regístrate para acceder a esta página."
|
||||
|
||||
#: app/forms.py:24
|
||||
msgid ""
|
||||
"This nickname has invalid characters. Please use letters, numbers, dots and "
|
||||
"underscores only."
|
||||
msgstr ""
|
||||
"Este nombre de usuario tiene caracteres inválidos. Por favor usa letras, "
|
||||
"números, puntos y underscores."
|
||||
|
||||
#: app/forms.py:28
|
||||
msgid "This nickname is already in use. Please choose another one."
|
||||
msgstr "Este nombre de usuario ya esta usado. Por favor elije otro."
|
||||
|
||||
#: app/views.py:49
|
||||
msgid "Your post is now live!"
|
||||
msgstr "¡Tu artículo ha sido publicado!"
|
||||
|
||||
#: app/views.py:74
|
||||
msgid "Invalid login. Please try again."
|
||||
msgstr "Credenciales inválidas. Por favor intenta de nuevo."
|
||||
|
||||
#: app/views.py:107
|
||||
#, python-format
|
||||
msgid "User %(nickname)s not found."
|
||||
msgstr "El usuario %(nickname)s no existe."
|
||||
|
||||
#: app/views.py:123
|
||||
msgid "Your changes have been saved."
|
||||
msgstr "Tus cambios han sido guardados."
|
||||
|
||||
#: app/views.py:139
|
||||
msgid "You can't follow yourself!"
|
||||
msgstr "¡No te puedes seguir a tí mismo!"
|
||||
|
||||
#: app/views.py:143
|
||||
#, python-format
|
||||
msgid "Cannot follow %(nickname)s."
|
||||
msgstr "No se pudo seguir a %(nickname)s."
|
||||
|
||||
#: app/views.py:147
|
||||
#, python-format
|
||||
msgid "You are now following %(nickname)s!"
|
||||
msgstr "¡Ya estás siguiendo a %(nickname)s!"
|
||||
|
||||
#: app/views.py:159
|
||||
msgid "You can't unfollow yourself!"
|
||||
msgstr "¡No te puedes dejar de seguir a tí mismo!"
|
||||
|
||||
#: app/views.py:163
|
||||
#, python-format
|
||||
msgid "Cannot unfollow %(nickname)s."
|
||||
msgstr "No se pudo dejar de seguir a %(nickname)s."
|
||||
|
||||
#: app/views.py:167
|
||||
#, python-format
|
||||
msgid "You have stopped following %(nickname)s."
|
||||
msgstr "Ya no sigues más a %(nickname)s."
|
||||
|
||||
#: app/templates/404.html:5
|
||||
msgid "File Not Found"
|
||||
msgstr "Archivo no encontrado"
|
||||
|
||||
#: app/templates/404.html:6 app/templates/500.html:7
|
||||
msgid "Back"
|
||||
msgstr "Volver"
|
||||
|
||||
#: app/templates/500.html:5
|
||||
msgid "An unexpected error has occurred"
|
||||
msgstr "Un error inesperado ha ocurrido"
|
||||
|
||||
#: app/templates/500.html:6
|
||||
msgid "The administrator has been notified. Sorry for the inconvenience!"
|
||||
msgstr "El administrador ha sido notificado. ¡Lo lamento!"
|
||||
|
||||
#: app/templates/base.html:30
|
||||
msgid "Home"
|
||||
msgstr "Inicio"
|
||||
|
||||
#: app/templates/base.html:32
|
||||
msgid "Your Profile"
|
||||
msgstr "Tu Perfil"
|
||||
|
||||
#: app/templates/base.html:33
|
||||
msgid "Logout"
|
||||
msgstr "Desconectarse"
|
||||
|
||||
#: app/templates/base.html:38
|
||||
msgid "Search"
|
||||
msgstr "Buscar"
|
||||
|
||||
#: app/templates/edit.html:5
|
||||
msgid "Edit Your Profile"
|
||||
msgstr "Editar Tu Perfil"
|
||||
|
||||
#: app/templates/edit.html:11
|
||||
msgid "Your nickname:"
|
||||
msgstr "Tu nombre de usuario:"
|
||||
|
||||
#: app/templates/edit.html:20
|
||||
msgid "About yourself:"
|
||||
msgstr "Acerca tuyo:"
|
||||
|
||||
#: app/templates/edit.html:30
|
||||
msgid "Save Changes"
|
||||
msgstr "Guardar"
|
||||
|
||||
#: app/templates/follower_email.html:2
|
||||
#, python-format
|
||||
msgid "%(nickname)s is now a follower."
|
||||
msgstr "%(nickname)s te está siguiendo."
|
||||
|
||||
#: app/templates/follower_email.html:12
|
||||
msgid "Regards,"
|
||||
msgstr "Cordialmente,"
|
||||
|
||||
#: app/templates/follower_email.html:13
|
||||
msgid "The <code>microblog</code> admin"
|
||||
msgstr "El administrador de <code>microblog</code>"
|
||||
|
||||
#: app/templates/index.html:5
|
||||
#, python-format
|
||||
msgid "Hi, %(nickname)s!"
|
||||
msgstr "¡Hola, %(nickname)s!"
|
||||
|
||||
#: app/templates/index.html:11
|
||||
msgid "Say something:"
|
||||
msgstr "Dí algo:"
|
||||
|
||||
#: app/templates/index.html:21
|
||||
msgid "Post!"
|
||||
msgstr "¡Publicar!"
|
||||
|
||||
#: app/templates/index.html:31 app/templates/index.html:33
|
||||
#: app/templates/user.html:30 app/templates/user.html:32
|
||||
msgid "Newer posts"
|
||||
msgstr "Artículos nuevos"
|
||||
|
||||
#: app/templates/index.html:36 app/templates/index.html:38
|
||||
#: app/templates/user.html:35 app/templates/user.html:37
|
||||
msgid "Older posts"
|
||||
msgstr "Artículos viejos"
|
||||
|
||||
#: app/templates/login.html:20
|
||||
msgid "Please Sign In"
|
||||
msgstr "Por Favor Regístrate"
|
||||
|
||||
#: app/templates/login.html:23
|
||||
msgid "Click on your OpenID provider below:"
|
||||
msgstr "Haz click en tu proveedor de OpenID:"
|
||||
|
||||
#: app/templates/login.html:30
|
||||
msgid "Or enter your OpenID here:"
|
||||
msgstr "O ingresa tu OpenID aquí:"
|
||||
|
||||
#: app/templates/login.html:41
|
||||
msgid "Remember Me"
|
||||
msgstr "Recordarme"
|
||||
|
||||
#: app/templates/login.html:47
|
||||
msgid "Sign In"
|
||||
msgstr "Ingresar"
|
||||
|
||||
#: app/templates/post.html:6
|
||||
#, python-format
|
||||
msgid "%(nickname)s said %(when)s:"
|
||||
msgstr "%(nickname)s dijo %(when)s:"
|
||||
|
||||
#: app/templates/search_results.html:5
|
||||
#, python-format
|
||||
msgid "Search results for \"%(query)s\":"
|
||||
msgstr "Resultados de búsqueda de \"%(query)s\":"
|
||||
|
||||
#: app/templates/user.html:13
|
||||
msgid "Last seen:"
|
||||
msgstr "Último acceso:"
|
||||
|
||||
#: app/templates/user.html:15
|
||||
msgid "Followers:"
|
||||
msgstr "Seguidores:"
|
||||
|
||||
#: app/templates/user.html:15
|
||||
msgid "Following:"
|
||||
msgstr "Siguiendo:"
|
||||
|
||||
#: app/templates/user.html:17
|
||||
msgid "Edit your profile"
|
||||
msgstr "Editar Tu Perfil"
|
||||
|
||||
#: app/templates/user.html:19
|
||||
msgid "Follow"
|
||||
msgstr "Seguir"
|
||||
|
||||
#: app/templates/user.html:21
|
||||
msgid "Unfollow"
|
||||
msgstr "Dejar de seguir"
|
30
app/views.py
30
app/views.py
|
@ -1,16 +1,22 @@
|
|||
from flask import render_template, flash, redirect, session, url_for, request, g
|
||||
from flask.ext.login import login_user, logout_user, current_user, login_required
|
||||
from app import app, db, lm, oid
|
||||
from flask.ext.babel import gettext
|
||||
from app import app, db, lm, oid, babel
|
||||
from forms import LoginForm, EditForm, PostForm, SearchForm
|
||||
from models import User, ROLE_USER, ROLE_ADMIN, Post
|
||||
from datetime import datetime
|
||||
from emails import follower_notification
|
||||
from config import POSTS_PER_PAGE, MAX_SEARCH_RESULTS
|
||||
from config import LANGUAGES
|
||||
|
||||
@lm.user_loader
|
||||
def load_user(id):
|
||||
return User.query.get(int(id))
|
||||
|
||||
@babel.localeselector
|
||||
def get_locale():
|
||||
return request.accept_languages.best_match(LANGUAGES.keys())
|
||||
|
||||
@app.before_request
|
||||
def before_request():
|
||||
g.user = current_user
|
||||
|
@ -19,6 +25,7 @@ def before_request():
|
|||
db.session.add(g.user)
|
||||
db.session.commit()
|
||||
g.search_form = SearchForm()
|
||||
g.locale = get_locale()
|
||||
|
||||
@app.errorhandler(404)
|
||||
def internal_error(error):
|
||||
|
@ -39,7 +46,7 @@ def index(page = 1):
|
|||
post = Post(body = form.post.data, timestamp = datetime.utcnow(), author = g.user)
|
||||
db.session.add(post)
|
||||
db.session.commit()
|
||||
flash('Your post is now live!')
|
||||
flash(gettext('Your post is now live!'))
|
||||
return redirect(url_for('index'))
|
||||
posts = g.user.followed_posts().paginate(page, POSTS_PER_PAGE, False)
|
||||
return render_template('index.html',
|
||||
|
@ -64,13 +71,14 @@ def login():
|
|||
@oid.after_login
|
||||
def after_login(resp):
|
||||
if resp.email is None or resp.email == "":
|
||||
flash('Invalid login. Please try again.')
|
||||
flash(gettext('Invalid login. Please try again.'))
|
||||
redirect(url_for('login'))
|
||||
user = User.query.filter_by(email = resp.email).first()
|
||||
if user is None:
|
||||
nickname = resp.nickname
|
||||
if nickname is None or nickname == "":
|
||||
nickname = resp.email.split('@')[0]
|
||||
nickname = User.make_valid_nickname(nickname)
|
||||
nickname = User.make_unique_nickname(nickname)
|
||||
user = User(nickname = nickname, email = resp.email, role = ROLE_USER)
|
||||
db.session.add(user)
|
||||
|
@ -96,7 +104,7 @@ def logout():
|
|||
def user(nickname, page = 1):
|
||||
user = User.query.filter_by(nickname = nickname).first()
|
||||
if user == None:
|
||||
flash('User ' + nickname + ' not found.')
|
||||
flash(gettext('User %(nickname)s not found.', nickname = nickname))
|
||||
return redirect(url_for('index'))
|
||||
posts = user.posts.paginate(page, POSTS_PER_PAGE, False)
|
||||
return render_template('user.html',
|
||||
|
@ -112,7 +120,7 @@ def edit():
|
|||
g.user.about_me = form.about_me.data
|
||||
db.session.add(g.user)
|
||||
db.session.commit()
|
||||
flash('Your changes have been saved.')
|
||||
flash(gettext('Your changes have been saved.'))
|
||||
return redirect(url_for('edit'))
|
||||
elif request.method != "POST":
|
||||
form.nickname.data = g.user.nickname
|
||||
|
@ -128,15 +136,15 @@ def follow(nickname):
|
|||
flash('User ' + nickname + ' not found.')
|
||||
return redirect(url_for('index'))
|
||||
if user == g.user:
|
||||
flash('You can\'t follow yourself!')
|
||||
flash(gettext('You can\'t follow yourself!'))
|
||||
return redirect(url_for('user', nickname = nickname))
|
||||
u = g.user.follow(user)
|
||||
if u is None:
|
||||
flash('Cannot follow ' + nickname + '.')
|
||||
flash(gettext('Cannot follow %(nickname)s.', nickname = nickname))
|
||||
return redirect(url_for('user', nickname = nickname))
|
||||
db.session.add(u)
|
||||
db.session.commit()
|
||||
flash('You are now following ' + nickname + '!')
|
||||
flash(gettext('You are now following %(nickname)s!', nickname = nickname))
|
||||
follower_notification(user, g.user)
|
||||
return redirect(url_for('user', nickname = nickname))
|
||||
|
||||
|
@ -148,15 +156,15 @@ def unfollow(nickname):
|
|||
flash('User ' + nickname + ' not found.')
|
||||
return redirect(url_for('index'))
|
||||
if user == g.user:
|
||||
flash('You can\'t unfollow yourself!')
|
||||
flash(gettext('You can\'t unfollow yourself!'))
|
||||
return redirect(url_for('user', nickname = nickname))
|
||||
u = g.user.unfollow(user)
|
||||
if u is None:
|
||||
flash('Cannot unfollow ' + nickname + '.')
|
||||
flash(gettext('Cannot unfollow %(nickname)s.', nickname = nickname))
|
||||
return redirect(url_for('user', nickname = nickname))
|
||||
db.session.add(u)
|
||||
db.session.commit()
|
||||
flash('You have stopped following ' + nickname + '.')
|
||||
flash(gettext('You have stopped following %(nickname)s.', nickname = nickname))
|
||||
return redirect(url_for('user', nickname = nickname))
|
||||
|
||||
@app.route('/search', methods = ['POST'])
|
||||
|
|
|
@ -0,0 +1,4 @@
|
|||
[python: **.py]
|
||||
[jinja2: **/templates/**.html]
|
||||
extensions=jinja2.ext.autoescape,jinja2.ext.with_
|
||||
|
|
@ -1,3 +1,4 @@
|
|||
# -*- coding: utf8 -*-
|
||||
import os
|
||||
basedir = os.path.abspath(os.path.dirname(__file__))
|
||||
|
||||
|
@ -23,6 +24,12 @@ MAIL_USE_SSL = False
|
|||
MAIL_USERNAME = 'you'
|
||||
MAIL_PASSWORD = 'your-password'
|
||||
|
||||
# available languages
|
||||
LANGUAGES = {
|
||||
'en': 'English',
|
||||
'es': 'Español'
|
||||
}
|
||||
|
||||
# administrator list
|
||||
ADMINS = ['you@example.com']
|
||||
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
#!flask/bin/python
|
||||
import os
|
||||
import sys
|
||||
if sys.platform == 'win32':
|
||||
pybabel = 'flask\\Scripts\\pybabel'
|
||||
else:
|
||||
pybabel = 'flask/bin/pybabel'
|
||||
os.system(pybabel + ' compile -d app/translations')
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
#!flask/bin/python
|
||||
import os
|
||||
import sys
|
||||
if sys.platform == 'win32':
|
||||
pybabel = 'flask\\Scripts\\pybabel'
|
||||
else:
|
||||
pybabel = 'flask/bin/pybabel'
|
||||
if len(sys.argv) != 2:
|
||||
print "usage: tr_init <language-code>"
|
||||
sys.exit(1)
|
||||
os.system(pybabel + ' extract -F babel.cfg -k lazy_gettext -o messages.pot app')
|
||||
os.system(pybabel + ' init -i messages.pot -d app/translations -l ' + sys.argv[1])
|
||||
os.unlink('messages.pot')
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
#!flask/bin/python
|
||||
import os
|
||||
import sys
|
||||
if sys.platform == 'wiin32':
|
||||
pybabel = 'flask\\Scripts\\pybabel'
|
||||
else:
|
||||
pybabel = 'flask/bin/pybabel'
|
||||
os.system(pybabel + ' extract -F babel.cfg -k lazy_gettext -o messages.pot app')
|
||||
os.system(pybabel + ' update -i messages.pot -d app/translations')
|
||||
os.unlink('messages.pot')
|
||||
|
Loading…
Reference in New Issue