Flask-Babel: get_locale() seems to be not working - flask

I'm configuring flask-babel to translate an html page from English as base language to Portuguese as translated language. However, no changes at get_locale() reflected in a different language.
These are my current relevant codes:
app.py:
from flask import Flask, render_template
from flask_babel import Babel
from flask_babel import gettext as _
app = Flask(__name__)
app.config['BABEL_DEFAULT_LOCALE'] = 'pt'
babel = Babel(app)
babel.init_app(app)
def get_locale():
return 'en'
#app.route('/')
def index():
return render_template('index.html')
if __name__ == "__main__":
app.run(debug=True)
html:
<!DOCTYPE html>
<html lang="en">
<body>
<h1>{{ _('Word') }}</h1>
</body>
</html>
Switching manually app.config['BABEL_DEFAULT_LOCALE'] = 'pt' seems to show equivalent translated word as written in '.po' file and then compiled, and switching ['BABEL_DEFAULT_LOCALE'] to 'en' and get_locale() to 'pt' seems to show the untranslated word again. In other words, I think my 'messages.mo' file is working as intended. It's as if the get_locale() function is getting ignored.
I'm using flask 2.2.2 and flask-babel 3.0.0, thus, I didn't insert #babel.localeselector as it seems it's not needed (and returns unrecognized decorator when inserted).
Thanks in advance
----- ANSWER -----
Using babel.init_app(app, locale_selector=get_locale) didn't work for the first few times, until I wrote my code in the following order: babel initialization, then get_locale() function, then init_app.
from flask import Flask, render_template
from flask_babel import Babel
from flask_babel import gettext as _
app = Flask(__name__)
app.config['BABEL_DEFAULT_LOCALE'] = 'en'
babel = Babel(app)
def get_locale():
return 'en'
babel.init_app(app, locale_selector=get_locale)
#app.route('/')
def index():
return render_template('index.html')
if __name__ == "__main__":
app.run(debug=True)

Did you check documentation?
You have to set locale_selector to be able use own function:
...
def get_locale():
return 'en'
babel = Babel(app)
babel.init_app(app, locale_selector=get_locale)
...

Related

how to add app object in flask's main file

I want to add app object once in main.py which can be used everywhere, but route does not work in this way. What is the issue here?
main.py
from flask import Flask
app = Flask(__name__)
if __name__ == "__main__":
app.run(debug=True)
routes.py
from main import app
#app.route("/", methods = ["GET"])
def home():
return "hi"
However, if declare app = Flask(name) in routes.py and import app in main.py it is working all fine. Working scenario.
main.py
from routes import app
if __name__ == "__main__":
app.run(debug=True)
routes.py
from flask import Flask, jsonify, request
app = Flask(__name__)
#app.route("/", methods = ["GET"])
def home():
return "hi"
my objective is to define app in main.py and import it in other files, but getting issues.
main.py is not even aware that routes.py exists. Import your routes.py file after initializing your app.
# main.py
from flask import Flask
app = Flask(__name__)
import routes # needed
if __name__ == "__main__":
app.run(debug=True)
# routes.py
from __main__ import app
#app.route("/")
def home():
return "hi"

Why do the routes "/login" and "/register" not work?

My Flask application is not recognizing/using the two defined routes in auth.py, how come?
File structure
Error Msg:
Not Found: The requested URL was not found on the server. If you entered the URL manually please check your spelling and try again.
Routes
http://127.0.0.1:5000/home (WORKS)
http://127.0.0.1:5000/profile (WORKS)
http://127.0.0.1:5000/login (DOES NOT WORK)
http://127.0.0.1:5000/register (DOES NOT WORK)
app.py
from flask import Flask, render_template
app = Flask(__name__)
#app.route("/home")
def home():
return render_template("index.html")
#app.route("/profile")
def profile():
return render_template("profile.html")
auth.py
from flask import current_app as app, render_template
#app.route("/login")
def login():
return render_template("login.html")
#app.route("/register")
def register():
return render_template("register.html")
You can't register routes to current_app, instead you have to use a class called Blueprint which is built exactly for this purpose (splitting application into multiple files).
app.py
from flask import Flask, render_template
from auth import auth_bp
app = Flask(__name__)
# Register the blueprint
app.register_blueprint(auth_bp)
#app.route("/home")
def home():
return render_template("index.html")
#app.route("/profile")
def profile():
return render_template("profile.html")
auth.py
from flask import Blueprint, render_template
# Initialize the blueprint
auth_bp = Blueprint('auth', __name__)
#auth_bp.route("/login")
def login():
return render_template("login.html")
#auth_bp.route("/register")
def register():
return render_template("register.html")
See https://flask.palletsprojects.com/en/2.0.x/blueprints/ for more information.
It seems like you have at least two files in which you have these routes. In your app.py file you have /home and /profile, they both work. They work because you initialised the Flask application over there.
Flask offers Blueprints to split up your application. You could create a blueprint called auth for example.
There is a specific tutorial on this subject as well.
I suggest moving the initialisation of the app variable to the __init__.py file and creating a create_app() method that returns app. In this method you can register your blueprints as well.
This method would look like:
def create_app():
app = Flask(__name__)
from . import app as application, auth
app.register_blueprint(auth.bp)
app.register_blueprint(application.bp)
return app
Your auth.py file, for example, would look like:
from flask import Blueprint, render_template
bp = Blueprint('auth', __name__)
#bp.route("/login")
def login():
return render_template("login.html")
#bp.route("/register")
def register():
return render_template("register.html")

Simple Flask example with pytest and application factory does not work

I am new to flask and I have set up a simple flask example and two tests using pytest(see here). When I let run only one test it works, but if I run both tests it does not work.
Anyone knows why? I think I am missing here some basics of how flask works.
code structure:
app/__init__.py
from flask import Flask
def create_app():
app = Flask(__name__)
with app.app_context():
from app import views
return app
app/views.py
from flask import current_app as app
#app.route('/')
def index():
return 'Index Page'
#app.route('/hello')
def hello():
return 'Hello World!'
tests/conftest.py
import pytest
from app import create_app
#pytest.fixture
def client():
app = create_app()
yield app.test_client()
tests/test_app.py
from app import create_app
def test_index(client):
response = client.get("/")
assert response.data == b"Index Page"
def test_hello(client):
response = client.get("/hello")
assert response.data == b"Hello World!"
The problem is with your registration of the routes in app/views.py when you register them with current_app as app. I'm not sure how you would apply the application factory pattern without using blueprints as the pattern description in the documentation implies they are mandatory for the pattern:
If you are already using packages and blueprints for your application [...]
So I adjusted your code to use a blueprint instead:
app/main/__init__.py:
from flask import Blueprint
bp = Blueprint('main', __name__)
from app.main import views
app/views.py -> app/main/views.py:
from app.main import bp
#bp.route('/')
def index():
return 'Index Page'
#bp.route('/hello')
def hello():
return 'Hello World!'
app/__init__.py:
from flask import Flask
def create_app():
app = Flask(__name__)
# register routes with app instead of current_app:
from app.main import bp as main_bp
app.register_blueprint(main_bp)
return app
Then your tests work as intended:
$ python -m pytest tests
============================== test session starts ==============================
platform darwin -- Python 3.6.5, pytest-6.1.0, py-1.9.0, pluggy-0.13.1
rootdir: /Users/oschlueter/github/simple-flask-example-with-pytest
collected 2 items
tests/test_app.py .. [100%]
=============================== 2 passed in 0.02s ===============================

Can I link to an HTML template above the parent directory in flask?

I'm currently working on Project1 for CS50W - the book club project. I'd like to link to it from my Project0 website. I got the project0 website all jinja'd out, and it's doing pretty good. Is it possible for me to put all the book club stuff in another folder inside the templates folder and still use my Template.html file for the jinja expanding? If not, I understand.
Template.html is in here:
..\01_WebProgrammingWithJSandPython\Quarantime\templates
Can I reference it from here?
..\01_WebProgrammingWithJSandPython\Quarantime\templates\BookClub
Here's from the app.py file:
from flask import Flask, render_template, request
from flask_session import Session
app = Flask(__name__)
#app.route("/")
def index():
return render_template("index.html")
#app.route("/bookclub")
def bookclub():
return render_template("/BookClub/bookclub.html")
And here's from bookclub.html:
{% extends '../Template.html' %}

flask-nav not working with flask-bootstrap sample application

I'm trying to recreate this sample app that is supplied with flask-bootstrap, but have run into an issue rendering the navbar. I get the error:
inja2.exceptions.UndefinedError: 'flask_nav.Nav object' has no attribute 'fronend_top'
The example app is here:
https://github.com/mbr/flask-bootstrap/tree/master/sample_app
And the flask-nav example is here:
http://pythonhosted.org/flask-nav/getting-started.html#rendering-the-navbar
As far as I can tell I'm doing what seems to be correct, but I guess the nav isn't being passed to the web page context? Not sure.
Here is my server.py
from flask import Blueprint, render_template, flash, redirect, url_for
from flask_bootstrap import __version__ as FLASK_BOOTSTRAP_VERSION
from flask_bootstrap import Bootstrap
from flask_nav.elements import Navbar, View, Subgroup, Link, Text, Separator
from markupsafe import escape
from flask_nav import Nav
from forms import SignupForm
from flask import Flask
#from nav import nav
frontend = Blueprint('frontend', __name__)
# We're adding a navbar as well through flask-navbar. In our example, the
# navbar has an usual amount of Link-Elements, more commonly you will have a
# lot more View instances.
nav = Nav()
nav.register_element('frontend_top', Navbar(
View('Flask-Bootstrap', '.index'),
View('Home', '.index'),
View('Forms Example', '.example_form'),
View('Debug-Info', 'debug.debug_root'), ))
# Our index-page just shows a quick explanation. Check out the template
# "templates/index.html" documentation for more details.
#frontend.route('/')
def index():
return render_template('index.html', nav=nav)
app = Flask(__name__)
app.register_blueprint(frontend)
bootstrap = Bootstrap(app)
nav.init_app(app)
app.run(debug=True)
And here is the line that is throwing the error in my base.html
{% block navbar %}
{{nav.fronend_top.render()}}
{% endblock %}
Thanks for any help!
I was able to use this:
https://github.com/mbr/flask-nav/blob/master/example/init.py
and this:
http://pythonhosted.org/flask-nav/getting-started.html#rendering-the-navbar
to create a simplified version which worked. I started with the create_app method from the init example, which worked, then removed the method in the example below. Maybe it had to do with it being a blueprint? so it didn't have the nav object?
from flask import Blueprint, render_template, flash, redirect, url_for
from flask_bootstrap import __version__ as FLASK_BOOTSTRAP_VERSION
from flask_bootstrap import Bootstrap
from flask_nav.elements import Navbar, View, Subgroup, Link, Text, Separator
from markupsafe import escape
from flask_nav import Nav
from forms import SignupForm
from flask import Flask
#from nav import nav
app = Flask(__name__)
nav = Nav()
topbar = Navbar('',
View('Home', 'index'),
)
nav.register_element('top', topbar)
# not good style, but like to keep our examples short
#app.route('/')
def index():
return render_template('index.html')
#app.route('/products/<product>/')
def products(product):
return render_template('index.html', msg='Buy our {}'.format(product))
#app.route('/about-us/')
def about():
return render_template('index.html')
# Shows a long signup form, demonstrating form rendering.
#app.route('/example-form/', methods=('GET', 'POST'))
def example_form():
form = SignupForm()
if form.validate_on_submit():
flash('Hello, {}. You have successfully signed up'
.format(escape(form.name.data)))
# In a real application, you may wish to avoid this tedious redirect.
return redirect(url_for('.index'))
return render_template('signup.html', form=form)
nav.init_app(app)
bootstrap = Bootstrap(app)
app.run(debug=True)
Are you trying this with flask-boostrap4? If so, i found that it's Navbar Renderer is broken and causes the same error you found. Using flask-boostrap v3 along with BS 3 seems to fix it.