wtforms / flask-wtf

Simple integration of Flask and WTForms, including CSRF, file upload and Recaptcha integration.
https://flask-wtf.readthedocs.io
BSD 3-Clause "New" or "Revised" License
1.46k stars 310 forks source link

flask-wtf i18n does not work without flask-babel #582

Open azmeuk opened 11 months ago

azmeuk commented 11 months ago

wtforms has no hard dependency to babel/flask-babel, and translations work out of the box when properly configured, e.g. Form(flask.request.form, meta={"locales": ["fr"]})

However translations for a simple flask-wtf form with the same configuration won't work, unless flask-babel is installed and initialized.

This behavior feels unexpected, and adds an unnecessary dependency against flask-babel for non-English applications.

This can be fixed by manually setting WTF_I18N_ENABLED to False. Maybe WTF_I18N_ENABLED should default to True only if flask-babel is installed and False otherwise?

vanilla wtforms

assertions pass

import flask
import wtforms

class Form(wtforms.Form):
    email = wtforms.EmailField(validators=[wtforms.validators.Email()])

app = flask.Flask(__name__)

@app.route("/", methods=["GET", "POST"])
def index():
    form = Form(flask.request.form, meta={"locales": ["fr"]})
    form.validate()
    return form.errors

res = app.test_client().post("/", data={"email": "invalid-email"})
assert "Invalid email address." not in res.json["email"]
assert "Adresse électronique non valide." in res.json["email"]

flask-wtf without flask-babel

assertions fail

import flask
import wtforms
import flask_wtf

class Form(flask_wtf.FlaskForm):
    email = wtforms.EmailField(validators=[wtforms.validators.Email()])

app = flask.Flask(__name__)
app.config["WTF_CSRF_ENABLED"] = False

@app.route("/", methods=["GET", "POST"])
def index():
    form = Form(flask.request.form, meta={"locales": ["fr"]})
    form.validate()
    return form.errors

res = app.test_client().post("/", data={"email": "invalid-email"})
assert "Invalid email address." not in res.json["email"]
assert "Adresse électronique non valide." in res.json["email"]

flask-wtf with flask-babel

assertions pass

import flask
import wtforms
import flask_wtf
import flask_babel

class Form(flask_wtf.FlaskForm):
    email = wtforms.EmailField(validators=[wtforms.validators.Email()])

app = flask.Flask(__name__)
app.config["WTF_CSRF_ENABLED"] = False

babel = flask_babel.Babel()
babel.init_app(app, locale_selector=lambda: "fr")

@app.route("/", methods=["GET", "POST"])
def index():
    form = Form(flask.request.form, meta={"locales": ["fr"]})
    form.validate()
    return form.errors

res = app.test_client().post("/", data={"email": "invalid-email"})
assert "Invalid email address." not in res.json["email"]
assert "Adresse électronique non valide." in res.json["email"]