Skip to content

Commit

Permalink
Chapter 14: Ajax (v0.14)
Browse files Browse the repository at this point in the history
  • Loading branch information
miguelgrinberg committed Jun 7, 2018
1 parent c2f24e8 commit 388177a
Show file tree
Hide file tree
Showing 9 changed files with 119 additions and 16 deletions.
1 change: 1 addition & 0 deletions app/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)
19 changes: 17 additions & 2 deletions app/routes.py
Original file line number Diff line number Diff line change
@@ -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 guess_language import guess_language
from app import app, db
from app.forms import LoginForm, RegistrationForm, EditProfileForm, 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
Expand All @@ -24,7 +27,11 @@ def before_request():
def index():
form = PostForm()
if form.validate_on_submit():
post = Post(body=form.post.data, author=current_user)
language = guess_language(form.post.data)
if language == 'UNKNOWN' or len(language) > 5:
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!'))
Expand Down Expand Up @@ -189,3 +196,11 @@ def unfollow(username):
db.session.commit()
flash(_('You are not following %(username)s.', username=username))
return redirect(url_for('user', username=username))


@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'])})
Binary file added app/static/loading.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
12 changes: 11 additions & 1 deletion app/templates/_post.html
Original file line number Diff line number Diff line change
Expand Up @@ -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>
14 changes: 14 additions & 0 deletions app/templates/base.html
Original file line number Diff line number Diff line change
Expand Up @@ -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 %}
18 changes: 18 additions & 0 deletions app/translate.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
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']}
r = requests.get('https://api.microsofttranslator.com/v2/Ajax.svc'
'/Translate?text={}&from={}&to={}'.format(
text, source_language, dest_language),
headers=auth)
if r.status_code != 200:
return _('Error: the translation service failed.')
return json.loads(r.content.decode('utf-8-sig'))
42 changes: 29 additions & 13 deletions app/translations/es/LC_MESSAGES/messages.po
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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"
Expand All @@ -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"
Expand All @@ -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!"
Expand Down
1 change: 1 addition & 0 deletions config.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,5 @@ class Config(object):
MAIL_PASSWORD = os.environ.get('MAIL_PASSWORD')
ADMINS = ['[email protected]']
LANGUAGES = ['en', 'es']
MS_TRANSLATOR_KEY = os.environ.get('MS_TRANSLATOR_KEY')
POSTS_PER_PAGE = 25
28 changes: 28 additions & 0 deletions migrations/versions/2b017edaa91f_add_language_to_posts.py
Original file line number Diff line number Diff line change
@@ -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 ###

0 comments on commit 388177a

Please sign in to comment.