问题:Open edX Cypress版本注册用户的英文问题

##现象
Cypress注册时候,用户性别和学历为英文。
http://x.edustack.org/register

##分析

edx-platform/lms/djangoapps/student_account/views.py中的

@require_http_methods(['GET'])
@ensure_csrf_cookie
def login_and_registration_form(request, initial_mode="login"):
    """Render the combined login/registration form, defaulting to login
    This relies on the JS to asynchronously load the actual form from
    the user_api.
    Keyword Args:
        initial_mode (string): Either "login" or "register".
    """
    # Determine the URL to redirect to following login/registration/third_party_auth
    redirect_to = get_next_url_for_login_page(request)

    # If we're already logged in, redirect to the dashboard
    if request.user.is_authenticated():
        return redirect(redirect_to)

    # Retrieve the form descriptions from the user API
    form_descriptions = _get_form_descriptions(request)

    # If this is a microsite, revert to the old login/registration pages.
    # We need to do this for now to support existing themes.
    # Microsites can use the new logistration page by setting
    # 'ENABLE_COMBINED_LOGIN_REGISTRATION' in their microsites configuration file.
    if microsite.is_request_in_microsite() and not microsite.get_value('ENABLE_COMBINED_LOGIN_REGISTRATION', False):
        if initial_mode == "login":
            return old_login_view(request)
        elif initial_mode == "register":
            return old_register_view(request)

    # Allow external auth to intercept and handle the request
    ext_auth_response = _external_auth_intercept(request, initial_mode)
    if ext_auth_response is not None:
        return ext_auth_response

    # Our ?next= URL may itself contain a parameter 'tpa_hint=x' that we need to check.
    # If present, we display a login page focused on third-party auth with that provider.
    third_party_auth_hint = None
    if '?' in redirect_to:
        try:
            next_args = urlparse.parse_qs(urlparse.urlparse(redirect_to).query)
            provider_id = next_args['tpa_hint'][0]
            if third_party_auth.provider.Registry.get(provider_id=provider_id):
                third_party_auth_hint = provider_id
                initial_mode = "hinted_login"
        except (KeyError, ValueError, IndexError):
            pass

    # Otherwise, render the combined login/registration page
    context = {
        'data': {
            'login_redirect_url': redirect_to,
            'initial_mode': initial_mode,
            'third_party_auth': _third_party_auth_context(request, redirect_to),
            'third_party_auth_hint': third_party_auth_hint or '',
            'platform_name': settings.PLATFORM_NAME,

            # Include form descriptions retrieved from the user API.
            # We could have the JS client make these requests directly,
            # but we include them in the initial page load to avoid
            # the additional round-trip to the server.
            'login_form_desc': json.loads(form_descriptions['login']),
            'registration_form_desc': json.loads(form_descriptions['registration']),
            'password_reset_form_desc': json.loads(form_descriptions['password_reset']),
        },
        'login_redirect_url': redirect_to,  # This gets added to the query string of the "Sign In" button in header
        'responsive': True,
        'allow_iframing': True,
        'disable_courseware_js': True,
    }

    return render_to_response('student_account/login_and_register.html', context)

渲染用户注册界面return render_to_response(‘student_account/login_and_register.html’, context)
context{}中 ‘registration_form_desc’: json.loads(form_descriptions[‘registration’]),
form_descriptions = _get_form_descriptions(request)

def _get_form_descriptions(request):
    """Retrieve form descriptions from the user API.
    Arguments:
        request (HttpRequest): The original request, used to retrieve session info.
    Returns:
        dict: Keys are 'login', 'registration', and 'password_reset';
            values are the JSON-serialized form descriptions.
    """
    return {
        'login': _local_server_get('/user_api/v1/account/login_session/', request.session),
        'registration': _local_server_get('/user_api/v1/account/registration/', request.session),
        'password_reset': _local_server_get('/user_api/v1/account/password_reset/', request.session)
    }

‘registration’: _local_server_get(’/user_api/v1/account/registration/’, request.session),

查看lms/urls.py

Note: these are older versions of the User API that will eventually be

# subsumed by api/user listed below.
url(r'^user_api/', include('openedx.core.djangoapps.user_api.legacy_urls')),

对应到
edx-platform/openedx/core/djangoapps/user_api/legacy_urls.py

if settings.FEATURES.get('ENABLE_COMBINED_LOGIN_REGISTRATION'):
    urlpatterns += patterns(
        '',
        url(r'^v1/account/login_session/$', user_api_views.LoginSessionView.as_view(),
            name="user_api_login_session"),
        url(r'^v1/account/registration/$', user_api_views.RegistrationView.as_view(),
            name="user_api_registration"),
        url(r'^v1/account/password_reset/$', user_api_views.PasswordResetView.as_view(),
            name="user_api_password_reset"),
    )

观察edx-platform/openedx/core/djangoapps/user_api/views.py
class RegistrationView(APIView):

def _add_gender_field(self, form_desc, required=True):
    """Add a gender field to a form description.
    Arguments:
        form_desc: A form description
    Keyword Arguments:
        required (bool): Whether this field is required; defaults to True
    """
    # Translators: This label appears above a dropdown menu on the registration
    # form used to select the user's gender.
    gender_label = _(u"Gender")

    form_desc.add_field(
        "gender",
        label=gender_label,
        field_type="select",
        options=UserProfile.GENDER_CHOICES,
        include_default_option=True,
        required=required
    )

注意到options=UserProfile.GENDER_CHOICES,
而from .models import UserPreference, UserProfile

观察 edx-platform/openedx/core/djangoapps/user_api/models.py

# Currently, the "student" app is responsible for
# accounts, profiles, enrollments, and the student dashboard.
# We are trying to move some of this functionality into separate apps,
# but currently the rest of the system assumes that "student" defines
# certain models.  For now we will leave the models in "student" and
# create an alias in "user_api".
from student.models import UserProfile, Registration, PendingEmailChange  # pylint: disable=unused-import
class UserPreference(models.Model):
    """A user's preference, stored as generic text to be processed by client"""
    KEY_REGEX = r"[-_a-zA-Z0-9]+"
    user = models.ForeignKey(User, db_index=True, related_name="preferences")
    key = models.CharField(max_length=255, db_index=True, validators=[RegexValidator(KEY_REGEX)])
    value = models.TextField()

观察到from student.models 调用了edx-platform/common/djangoapps/student/models.py

GENDER_CHOICES = (
    ('m', ugettext_noop('Male')),
    ('f', ugettext_noop('Female')),
    # Translators: 'Other' refers to the student's gender
    ('o', ugettext_noop('Other'))
)
gender = models.CharField(
    blank=True, null=True, max_length=6, db_index=True, choices=GENDER_CHOICES
)

模板 student_account/login_and_register.html 调用了 edx-platform/lms/templates/student_account/register.underscore

得先检查你的系统是否开启了ENABLE_COMBINED_LOGIN_REGISTRATION
DatoChan 20:23:05
如果开启了,才走分析中lms的那个view
DatoChan 20:23:22
而且 传递的参数 initial_mode 是 register
DatoChan 20:25:02
如果没开启,就直接渲染/lms/template/register.html


恩,开启就走开启的流程,是在backbone里面
edx-platform/lms/templates/student_account/login_and_register.html

数据的获取代码:
<%block name=“js_extra”>
<%static:require_module module_name=“js/student_account/logistration_factory” class_name=“LogistrationFactory”>
var options = ${ json.dumps(data, cls=EscapedEdxJSONEncoder) };
LogistrationFactory(options);
</%static:require_module>
</%block>
从这里开始渲染的数据,backbone也是在这里加载的。




由此可以定位出来,注册的表单对应的tpl是:form_field.underscore
DatoChan 20:36:46
<%= el.name %>
加上翻译指令:
<%= ${_(el.name)} %>
然后在:
/conf/locale/zh_CN/LC_MESSAGES/underscore.po
中增加相关翻译就可以了

DatoChan 20:37:51
应该是这个名。
DatoChan 20:37:57
我以前的项目代码中有这个文件。
DatoChan 20:38:15
可能新版本取消不叫这个名也说不定。
DatoChan 20:38:44
这个界面渲染用的是backbone的模板。其实就是 underscore的模板……
DatoChan 20:39:02
要翻译应该是在underscore.po中翻译。


DatoChan 20:42:50
从register.html中可以看出来,翻译肯定不是靠 models.py 中的 ugettext_noop 进行翻译的
DatoChan 20:43:12
一定是需要在模板,或者underscore,或者forms.py中进行翻译。
DatoChan 20:54:22
恩,有个地方我写错了
DatoChan 20:54:54
<%= el.name %>
加上翻译指令:
<%= gettext(el.name) %>
然后在:
/conf/locale/zh_CN/LC_MESSAGES/underscore.po
中增加相关翻译就可以了DatoChan 20:54:22
DatoChan 20:55:04
要用 gettext。不能用 _()


DatoChan 21:59:52
这个问题出在 backbone封装控件时,没有对值进行翻译。
MT 21:59:57
循环取出所有select类型的表单,但是value那里却是原值

额,整理排版一下就好了~

有心人自然就能看懂了。

Powered by eduStack & ifLab