Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: miguelgrinberg/microblog
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: v0.13
Choose a base ref
...
head repository: miguelgrinberg/microblog
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: v0.14
Choose a head ref
  • 1 commit
  • 9 files changed
  • 1 contributor

Commits on Jul 30, 2024

  1. Verified

    This commit was signed with the committer’s verified signature.
    miguelgrinberg Miguel Grinberg
    Copy the full SHA
    b00c690 View commit details
1 change: 1 addition & 0 deletions app/models.py
Original file line number Diff line number Diff line change
@@ -119,6 +119,7 @@ class Post(db.Model):
index=True, default=lambda: datetime.now(timezone.utc))
user_id: so.Mapped[int] = so.mapped_column(sa.ForeignKey(User.id),
index=True)
language: so.Mapped[Optional[str]] = so.mapped_column(sa.String(5))

author: so.Mapped[User] = so.relationship(back_populates='posts')

18 changes: 17 additions & 1 deletion app/routes.py
Original file line number Diff line number Diff line change
@@ -4,11 +4,13 @@
from flask_login import login_user, logout_user, current_user, login_required
from flask_babel import _, get_locale
import sqlalchemy as sa
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
@@ -25,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!'))
@@ -206,3 +213,12 @@ 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():
data = request.get_json()
return {'text': translate(data['text'],
data['source_language'],
data['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
@@ -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>
17 changes: 17 additions & 0 deletions app/templates/base.html
Original file line number Diff line number Diff line change
@@ -64,5 +64,22 @@
</script>
{{ moment.include_moment() }}
{{ moment.lang(g.locale) }}
<script>
async function translate(sourceElem, destElem, sourceLang, destLang) {
document.getElementById(destElem).innerHTML =
'<img src="{{ url_for('static', filename='loading.gif') }}">';
const response = await fetch('/translate', {
method: 'POST',
headers: {'Content-Type': 'application/json; charset=utf-8'},
body: JSON.stringify({
text: document.getElementById(sourceElem).innerText,
source_language: sourceLang,
dest_language: destLang
})
})
const data = await response.json();
document.getElementById(destElem).innerText = data.text;
}
</script>
</body>
</html>
21 changes: 21 additions & 0 deletions app/translate.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
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': 'westus'
}
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']
42 changes: 29 additions & 13 deletions app/translations/es/LC_MESSAGES/messages.po
Original file line number Diff line number Diff line change
@@ -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!"
1 change: 1 addition & 0 deletions config.py
Original file line number Diff line number Diff line change
@@ -13,4 +13,5 @@ class Config:
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
32 changes: 32 additions & 0 deletions migrations/versions/2b017edaa91f_add_language_to_posts.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
"""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! ###
with op.batch_alter_table('post', schema=None) as batch_op:
batch_op.add_column(sa.Column('language', sa.String(length=5), nullable=True))

# ### end Alembic commands ###


def downgrade():
# ### commands auto generated by Alembic - please adjust! ###
with op.batch_alter_table('post', schema=None) as batch_op:
batch_op.drop_column('language')

# ### end Alembic commands ###