make_lazy_gettext使用wForms获取输出.lazy_gettext位于0x07808D68>

时间:2018-05-11 13:01:06

标签: python-3.x tornado

我在使用龙卷风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))

1 个答案:

答案 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