Chapter 14: Ajax (v0.14)

This commit is contained in:
Miguel Grinberg 2017-10-05 15:34:15 -07:00
parent 8a56c34ce2
commit 7f7c8ef5d7
No known key found for this signature in database
GPG Key ID: 36848B262DF5F06C
9 changed files with 123 additions and 16 deletions

View File

@ -86,6 +86,7 @@ class Post(db.Model):
body = db.Column(db.String(140))
timestamp = db.Column(db.DateTime, index=True, default=datetime.utcnow)
user_id = db.Column(db.Integer, db.ForeignKey('user.id'))
language = db.Column(db.String(5))
def __repr__(self):
return '<Post {}>'.format(self.body)

View File

@ -1,13 +1,16 @@
from datetime import datetime
from flask import render_template, flash, redirect, url_for, request, g
from flask import render_template, flash, redirect, url_for, request, g, \
jsonify
from flask_login import login_user, logout_user, current_user, login_required
from werkzeug.urls import url_parse
from flask_babel import _, get_locale
from langdetect import detect, LangDetectException
from app import app, db
from app.forms import LoginForm, RegistrationForm, EditProfileForm, \
EmptyForm, PostForm, ResetPasswordRequestForm, ResetPasswordForm
from app.models import User, Post
from app.email import send_password_reset_email
from app.translate import translate
@app.before_request
@ -24,7 +27,12 @@ def before_request():
def index():
form = PostForm()
if form.validate_on_submit():
post = Post(body=form.post.data, author=current_user)
try:
language = detect(form.post.data)
except LangDetectException:
language = ''
post = Post(body=form.post.data, author=current_user,
language=language)
db.session.add(post)
db.session.commit()
flash(_('Your post is now live!'))
@ -198,3 +206,11 @@ def unfollow(username):
return redirect(url_for('user', username=username))
else:
return redirect(url_for('index'))
@app.route('/translate', methods=['POST'])
@login_required
def translate_text():
return jsonify({'text': translate(request.form['text'],
request.form['source_language'],
request.form['dest_language'])})

BIN
app/static/loading.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 673 B

View File

@ -14,7 +14,17 @@
{{ _('%(username)s said %(when)s',
username=user_link, when=moment(post.timestamp).fromNow()) }}
<br>
{{ post.body }}
<span id="post{{ post.id }}">{{ post.body }}</span>
{% if post.language and post.language != g.locale %}
<br><br>
<span id="translation{{ post.id }}">
<a href="javascript:translate(
'#post{{ post.id }}',
'#translation{{ post.id }}',
'{{ post.language }}',
'{{ g.locale }}');">{{ _('Translate') }}</a>
</span>
{% endif %}
</td>
</tr>
</table>

View File

@ -53,4 +53,18 @@
{{ super() }}
{{ moment.include_moment() }}
{{ moment.lang(g.locale) }}
<script>
function translate(sourceElem, destElem, sourceLang, destLang) {
$(destElem).html('<img src="{{ url_for('static', filename='loading.gif') }}">');
$.post('/translate', {
text: $(sourceElem).text(),
source_language: sourceLang,
dest_language: destLang
}).done(function(response) {
$(destElem).text(response['text'])
}).fail(function() {
$(destElem).text("{{ _('Error: Could not contact server.') }}");
});
}
</script>
{% endblock %}

21
app/translate.py Normal file
View File

@ -0,0 +1,21 @@
import json
import requests
from flask_babel import _
from app import app
def translate(text, source_language, dest_language):
if 'MS_TRANSLATOR_KEY' not in app.config or \
not app.config['MS_TRANSLATOR_KEY']:
return _('Error: the translation service is not configured.')
auth = {
'Ocp-Apim-Subscription-Key': app.config['MS_TRANSLATOR_KEY'],
'Ocp-Apim-Subscription-Region': 'westus2'}
r = requests.post(
'https://api.cognitive.microsofttranslator.com'
'/translate?api-version=3.0&from={}&to={}'.format(
source_language, dest_language), headers=auth, json=[
{'Text': text}])
if r.status_code != 200:
return _('Error: the translation service failed.')
return r.json()[0]['translations'][0]['text']

View File

@ -7,7 +7,7 @@ msgid ""
msgstr ""
"Project-Id-Version: PROJECT VERSION\n"
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
"POT-Creation-Date: 2017-10-03 15:49-0700\n"
"POT-Creation-Date: 2017-10-05 15:32-0700\n"
"PO-Revision-Date: 2017-09-29 23:25-0700\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language: es\n"
@ -82,57 +82,65 @@ msgstr "Dí algo"
msgid "Search"
msgstr "Buscar"
#: app/routes.py:30
#: app/routes.py:37
msgid "Your post is now live!"
msgstr "¡Tu artículo ha sido publicado!"
#: app/routes.py:66
#: app/routes.py:73
msgid "Invalid username or password"
msgstr "Nombre de usuario o contraseña inválidos"
#: app/routes.py:92
#: app/routes.py:99
msgid "Congratulations, you are now a registered user!"
msgstr "¡Felicitaciones, ya eres un usuario registrado!"
#: app/routes.py:107
#: app/routes.py:114
msgid "Check your email for the instructions to reset your password"
msgstr "Busca en tu email las instrucciones para crear una nueva contraseña"
#: app/routes.py:124
#: app/routes.py:131
msgid "Your password has been reset."
msgstr "Tu contraseña ha sido cambiada."
#: app/routes.py:152
#: app/routes.py:159
msgid "Your changes have been saved."
msgstr "Tus cambios han sido salvados."
#: app/routes.py:157 app/templates/edit_profile.html:5
#: app/routes.py:164 app/templates/edit_profile.html:5
msgid "Edit Profile"
msgstr "Editar Perfil"
#: app/routes.py:166 app/routes.py:182
#: app/routes.py:173 app/routes.py:189
#, python-format
msgid "User %(username)s not found."
msgstr "El usuario %(username)s no ha sido encontrado."
#: app/routes.py:169
#: app/routes.py:176
msgid "You cannot follow yourself!"
msgstr "¡No te puedes seguir a tí mismo!"
#: app/routes.py:173
#: app/routes.py:180
#, python-format
msgid "You are following %(username)s!"
msgstr "¡Ahora estás siguiendo a %(username)s!"
#: app/routes.py:185
#: app/routes.py:192
msgid "You cannot unfollow yourself!"
msgstr "¡No te puedes dejar de seguir a tí mismo!"
#: app/routes.py:189
#: app/routes.py:196
#, python-format
msgid "You are not following %(username)s."
msgstr "No estás siguiendo a %(username)s."
#: app/translate.py:10
msgid "Error: the translation service is not configured."
msgstr "Error: el servicio de traducciones no está configurado."
#: app/translate.py:17
msgid "Error: the translation service failed."
msgstr "Error el servicio de traducciones ha fallado."
#: app/templates/404.html:4
msgid "Not Found"
msgstr "Página No Encontrada"
@ -154,6 +162,10 @@ msgstr "El administrador ha sido notificado. ¡Lamentamos la inconveniencia!"
msgid "%(username)s said %(when)s"
msgstr "%(username)s dijo %(when)s"
#: app/templates/_post.html:19
msgid "Translate"
msgstr "Traducir"
#: app/templates/base.html:4
msgid "Welcome to Microblog"
msgstr "Bienvenido a Microblog"
@ -178,6 +190,10 @@ msgstr "Perfil"
msgid "Logout"
msgstr "Salir"
#: app/templates/base.html:73
msgid "Error: Could not contact server."
msgstr "Error: el servidor no pudo ser contactado."
#: app/templates/index.html:5
#, python-format
msgid "Hi, %(username)s!"

View File

@ -14,4 +14,5 @@ class Config(object):
MAIL_PASSWORD = os.environ.get('MAIL_PASSWORD')
ADMINS = ['your-email@example.com']
LANGUAGES = ['en', 'es']
MS_TRANSLATOR_KEY = os.environ.get('MS_TRANSLATOR_KEY')
POSTS_PER_PAGE = 25

View File

@ -0,0 +1,28 @@
"""add language to posts
Revision ID: 2b017edaa91f
Revises: ae346256b650
Create Date: 2017-10-04 22:48:34.494465
"""
from alembic import op
import sqlalchemy as sa
# revision identifiers, used by Alembic.
revision = '2b017edaa91f'
down_revision = 'ae346256b650'
branch_labels = None
depends_on = None
def upgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.add_column('post', sa.Column('language', sa.String(length=5), nullable=True))
# ### end Alembic commands ###
def downgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.drop_column('post', 'language')
# ### end Alembic commands ###