我在使用龙卷风4.5.1的python 3.5上有应用程序,我遇到了wForms中给出的自定义错误的问题,我做了一个研究和wForms说必须使用lazy_gettex才能翻译自定义错误到wForm Class。
我发现模块 speaklater 有 make_lazy_gettext ,但是使用它我遇到了另一个麻烦,而不是前端的错误消息我得到类似的东西< strong> .lazy_gettext at 0x07808D68&gt;
我的代码处理程序:hanlders.py 在处理程序内部我可以使用self._进行gettext翻译,现在可以使用
class ChangePassword(ProfileHandler):
def initialize(self, *args, **kwargs):
super(ChangePassword, self).initialize(*args, **kwargs)
self.form = profile_f.ChangePasswordForm(meta=self.meta_locale)
@authenticated(domain='c')
@coroutine
def get(self):
"""::access::
<div class="___sort">Profile</div>
<div>
<font class="__get__">GET</font>
<i class="icon-arrow-right14"></i>
<font class="desc">Change password</font>
</div>
::
::auto_access::1::
"""
response = yield self.model.item(_id=self.current_user)
profile = response.get('user', {})
response = yield self.quiz_m.get_all_quizzes(self.current_user)
quizzes = response.get('quizzes', {})
render_vars = {
'form': self.form,
'profile': profile,
'quizzes': quizzes,
}
self.render('pages/profile/profile_edit_password.html', **render_vars)
@authenticated(domain='c')
@coroutine
def post(self):
"""::access::
<div class="___sort">Profile</div>
<div>
<font class="__post__">POST</font>
<i class="icon-arrow-right14"></i>
<font class="desc">Change password</font>
</div>
::
::auto_access::1::
"""
self.form.process(self.request.arguments)
if self.form.validate():
form_data = self.form.prepared_data
update_response = yield self.model.update_password(
self.current_user, new_password=form_data['new_password'], old_password=form_data['old_password']) # noqa
if update_response['success']:
# start send email
user = yield self.model.mongo_find_one('users', ObjectId(self.current_user))
render_vars = {
'user': user,
'new_password': form_data['new_password'],
}
yield emails_template.send_template(self, 'profile_password', render_vars, user['email'])
# end send email
self.redirect('/profile/')
return
else:
self.form.set_foreign_errors({'old_password': update_response['errors']})
response = yield self.model.item(_id=self.current_user)
profile = response.get('user', {})
response = yield self.quiz_m.get_all_quizzes(self.current_user)
quizzes = response.get('quizzes', {})
render_vars = {
'form': self.form,
'profile': profile,
'quizzes': quizzes,
}
self.render('pages/profile/profile_edit_password.html', **render_vars)
我的代码如下:forms.py
from copy import copy
from forms import BaseForm, vl, fl, CustomStringField
from forms import EmailValidator
from speaklater import make_lazy_gettext as _
class ChangePasswordForm(BaseForm):
old_password = fl.PasswordField(validators=[vl.DataRequired(), vl.length(max=32, min=6)])
new_password = fl.PasswordField(validators=[vl.DataRequired(), vl.length(max=32, min=6)])
new_repassword = fl.PasswordField(validators=[vl.DataRequired(), vl.length(max=32, min=6)])
def validate_new_repassword(self, field):
if self.data.get('new_password') != field.data:
raise vl.ValidationError(_('Incorrect retyped password'))
从上面的代码我的自定义错误消息是_('不正确的重新输入密码')和前端输出我得到 .lazy_gettext在0x07808D68&gt;
为什么会发生这种情况的任何建议?
应用程序中使用的简单gettext的函数
def load_gettext_translations(dir_dom):
# Todo: think about workaround
"""
Like standard tornado.locale.load_gettext_translations but loads more locales from different locations
:param dir_dom: {'directory': '', 'domain': '', 'prefix': ''}
"""
import gettext
# global _translations
# global _supported_locales
# global _use_gettext
# _translations = {}
for trans in dir_dom:
for lang in os.listdir(trans['directory']):
if lang.startswith('.'):
continue # skip .svn, etc
if os.path.isfile(os.path.join(trans['directory'], lang)):
continue
try:
os.stat(os.path.join(trans['directory'], lang, "LC_MESSAGES", trans['domain'] + ".mo"))
tornado.locale._translations['%s%s' % (trans.get('prefix', ''), lang)] = gettext.translation(
trans['domain'], trans['directory'],
languages=[lang])
except Exception as e:
gen_log.error("Cannot load translation for '%s': %s", lang, str(e))
continue
tornado.locale._supported_locales = frozenset(list(tornado.locale._translations.keys()) + [tornado.locale._default_locale])
tornado.locale._use_gettext = True
gen_log.debug("Supported locales: %s", sorted(tornado.locale._supported_locales))
答案 0 :(得分:2)
你错了。顾名思义,speaklater
docs make_lazy_gettext
制作了一个懒惰的gettext对象。它不返回字符串对象,而是返回一个函数。所以,当你做的时候:
msg = _('Message')
msg is in fact a function, not a lazy string
正确使用将是这样的:
from speaklater import make_lazy_gettext
def translate(message):
"""Function responsible for translating message"""
return message # return message for the sake of example
_ = make_lazy_gettext(lambda: translate)
msg = _('Hello')
print(msg)
# outputs Hello
translate
函数负责翻译。我使用了一个简单的函数来演示speaklater的用法。但在实际应用程序中,它必须能够根据客户端的语言翻译给定的字符串。
翻译的工作原理:
您似乎认为使用_
或gettext
会自动将某些消息翻译为任何语言。
没有。这不是翻译的工作方式。
您必须手动为要翻译的所有邮件提供翻译。
在上面示例中的translate()
函数中,您可以通过创建以下字典来实现邮件的翻译:
# spanish
{
'es_ES': {'Incorrect retyped password': 'Contraseña reescrita incorrecta'}
# do this for other languages you want to support
}
在translate()
函数中编写相应的代码,该函数将根据语言(语言环境)查找此字典中的翻译并返回已翻译的消息。
如果您想为许多语言提供支持,编写词典可能会令人厌烦,而且不切实际。为此,您可以查看tornado-babel
库,以便于您使用。龙卷风也支持locale。但这比使用tornado-babel
要多一点。
示例Tornado应用
我应该指出的一点是,您无法使用全局_
对象,因为Tornado是单线程的。您需要在处理程序中创建_
对象,以便每个用户的语言环境保持不同。
from tornado import web, locale
from speaklater import make_lazy_gettext
class MyHandler(web.RequestHandler):
def get(self):
# tornado handlers have a `self.locale` attribute
# which returns the current user's locale
_ = make_lazy_gettext(lambda: self.locale.translate)
hello = _('hello')
# do something else
if __name__ == '__main__':
# load the translation files
locale.load_gettext_translations('/path/to/locale/', 'domain')
# ...
您还需要修改__init__
的{{1}}功能,以接受gettext对象ChangePasswordForm
。