Flask-Babel在js中的本地化字符串
我刚接触Python和Flask(使用Jinja2作为模板引擎),不太确定自己是不是在正确的方向上。我正在使用Flask-Babel这个扩展来给我的网页应用添加国际化支持。我想从我的JavaScript代码中获取本地化的字符串,比如:
var helloWorld = gettext('Hello, world');
console.log(helloWorld); //should log a localized hello world message
为此,我配置了babel(babel.cfg):
[python: **/**.py]
[jinja2: **/**.html]
extensions=jinja2.ext.autoescape,jinja2.ext.with_
[javascript: **/**.js]
encoding = utf-8
它的初始化代码是(为了简单省略了一些导入):
#main Flask app
app = Flask(__name__)
#localization
babel = Babel(app)
LANGUAGES = {
'ca': 'Catalan',
'en': 'English',
'de': 'Deutsch',
'es': 'Español',
'fi': 'Finnish',
'it': 'Italian'
}
@babel.localeselector
def get_locale():
return request.accept_languages.best_match(LANGUAGES.keys())
#some more stuff...
Babel在生成POT/PO语言文件时能识别到这个字符串,但我似乎无法从JavaScript代码中访问这些本地化的字符串,因为gettext函数没有定义。看起来Jinja2忽略了这一部分。
有没有什么提示?
2 个回答
在用JavaScript提供翻译的时候,有点脆弱。而且,我通常不使用Jinja来生成JavaScript,因为它用的括号和其他地方一样,容易搞得一团糟(动态数据和静态JavaScript混在一起总是可能的)。
一个轻量级的替代方法是用数据属性来做同样的JSON处理:
<div id="view-i18n" data-i18n='{{ view_i18n|tojson }}'> ... </div>
(注意:使用单引号!)
不过,这种方法适合翻译数量有限的情况。
也许,最稳妥的办法是让JavaScript中的翻译和Flask应用中的翻译保持一致。
借助一个叫做pojson
的工具,可以把po文件转换成json(可以参考这个例子:https://github.com/ZeWaren/flask-i18n-example),这可以作为构建过程的一部分(比如,在生成mo
文件之后)。翻译可以通过在pojson
的输出前加上var some_unique_name =
,轻松地添加到一个独特的全局变量中,方便访问。或者把文件放在static
目录下的特定语言文件夹里(例如static/view-es.json
,static/view-fr.json
等),然后通过ajax调用获取。
不过,有些事情需要考虑。如果你真的想让JSON更小,可能需要通过控制babel提取选项,把翻译域分成Python和JavaScript。另外,把所有翻译字符串放在JavaScript里也有安全方面的考虑。也许你不想把某些只有管理员能看到的短语暴露给其他用户。但这样的话,就需要为不同的访问级别设置更多的翻译域。此外,可能还需要去掉一些头部信息,以防泄露翻译者的邮箱等信息。当然,这样会让构建过程变得复杂一些,但随着时间的推移,JavaScript翻译的需求越多,自动化的好处就越明显。
我终于找到了解决办法,虽然我不确定这是否是最佳选择。我的想法是把javascript代码放在一个html模板里,这样在渲染之前,Jinja2会先处理它,并应用一个自定义的Jinja2过滤器来解决一些小问题。我尝试把js文件单独放,但没成功。
看起来可以这样使用gettext函数:
var helloWorld = {{gettext('Hello, world')}};
但是这样的话,就不会插入引号,因此js解释器会报错:
var helloWorld = Hello, world;
所以我最终使用了一个自定义过滤器。一个可用的例子如下。
hello_world.html:
<script type="text/javascript">
var x = {{gettext('Hello, world')|generate_string|safe}};
console.log(x); //logs the localized hello world message
</script>
app.py:
#Jinja2 filters
from jinja2 import evalcontextfilter, Markup
#Mind the hack! Babel does not work well within js code
@app.template_filter()
@evalcontextfilter
def generate_string(eval_ctx, localized_value):
if localized_value is None:
return ""
else:
return Markup("\"" + localized_value + "\"").unescape()
希望这对你有帮助!