Flask-Babel在js中的本地化字符串

7 投票
2 回答
5531 浏览
提问于 2025-04-17 21:57

我刚接触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 个回答

0

在用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.jsonstatic/view-fr.json等),然后通过ajax调用获取。

不过,有些事情需要考虑。如果你真的想让JSON更小,可能需要通过控制babel提取选项,把翻译域分成Python和JavaScript。另外,把所有翻译字符串放在JavaScript里也有安全方面的考虑。也许你不想把某些只有管理员能看到的短语暴露给其他用户。但这样的话,就需要为不同的访问级别设置更多的翻译域。此外,可能还需要去掉一些头部信息,以防泄露翻译者的邮箱等信息。当然,这样会让构建过程变得复杂一些,但随着时间的推移,JavaScript翻译的需求越多,自动化的好处就越明显。

2

我终于找到了解决办法,虽然我不确定这是否是最佳选择。我的想法是把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()

希望这对你有帮助!

撰写回答