3

I'm migrated my code from webapp2 to Flask. (I deploy my code in Google App Engine)

However, I can no longer use this string: "Error: Max %1$d characters"

Initialization

flask_app = Flask(__name__)
babel = Babel(flask_app, default_domain='strings')

Html template

<div class="...">{{ _('error_long_value') | replace('%1$d', '200') }}</div>

I know that this is not the best use, but I need to keep %1$d as placeholder. (It was working with webapp2)

Log:

...
File ".../libs/flask/templating.py", line 135, in render_template
context, ctx.app)
File ".../libs/flask/templating.py", line 117, in _render
rv = template.render(context)
File ".../libs/jinja2/environment.py", line 1008, in render
return self.environment.handle_exception(exc_info, True)
File ".../libs/jinja2/environment.py", line 780, in handle_exception
reraise(exc_type, exc_value, tb)
File ".../app/templates/filename.html", line 567, in top-level template code
<div class="invalid-feedback">{{ _('error_long_value') | replace('%1$d', '200') }}</div>
ValueError: unsupported format character '$' (0x24) at index 29

I've already tried to use the "| e" or "| safe" after " _('error_long_value')" in the HTML template, removing the replace().

desertnaut
  • 57,590
  • 26
  • 140
  • 166
Blodhgard
  • 9,130
  • 3
  • 24
  • 36
  • 1
    Regarding your last paragrapy, Jinja doesn't know/care about HTML comments. Only Jinja comments would affect its behavior (ie stop the code from running). – ThiefMaster Dec 30 '18 at 12:46
  • So does the error happen when you remove the "| replace('%1$d', '200')" ? if yes then it is happenign in Babel. What is the Bable version ? – Tomasz Swider Dec 30 '18 at 16:36
  • The error always happens when I use a translation with a dollar inside. Eg:
    {{ _('error_long_value') }}
    Where error_long_value is "Error: Max %1$d characters"
    – Blodhgard Dec 30 '18 at 19:04

2 Answers2

1

This is a two-fold problem coming from the fact that flask (and jinja more specifically), when interpreting text from templates and applying filters and/or context processors, it uses the string % something operation liberally.

This operation interprets the %1$d text like a formatting string, an invalid one that is causing the error. So what you need to do is replace both of the operations you're doing in the template, since the ones provided by flask (and its extensions, usually) are likely to cause errors because of the aforementioned modulus operation.

First, you can create a context processor using the babel gettext directly:

from flask_babel import gettext
#...
@app.context_processor
def my_gettext():
  return {'my_gettext': gettext}

Now a filter for the text replacement:

@app.template_filter()
def my_replace(text, old, new):
  return text.replace(old, new)

With this, in your template you'd use:

<div class="...">{{ my_gettext('error_long_value') | my_replace('%1$d', '200') }}</div>
Luis Orduz
  • 2,887
  • 1
  • 13
  • 19
0

It is hard to tell from your questions what is happening exactly, But it looks like you have error message "Error: Max %1$d characters" in Babel config under 'error_long_value' variable and you want do display "Error: Max 200 characters" in the outputted html. And for some reason something on the way does not like the "$" character. You could just change the placeholder to something that does not contain the "$". That will fix at least one problem. As for why it was working in webapp2, it might be different version of Babel or python or who knows what. Other thing you could check is to what exact function is called with _('error_long_value') is it babel gettext() ? where the variable name is assigned?

Tomasz Swider
  • 2,314
  • 18
  • 22