Activation email in multiple languages?

Running Open edX in multiple languages is sometimes frustrating.

I just noticed something that was working under Ironwood but now seems to be broken under Juniper.

We support both French and English on our site. The main language is French. But user can register in English.

I just noticed that the activation email was sent in French even if the user registered in English.

When I don’t activate the account and try to login again, I am told I will receive a new activation email. And then the activation email I receive is in English as expected.

Does that look like a bug? Or might I say a feature?

I am tempted to create a new account of the Spanish version of edx.org to see if I will receive the activation email in Spanish or in English…

Anybody encountered a similar issue when running a multi language site with Juniper?

Of course, clicking on the Registrarse button on https://www.edx.org/es redirects me to https://courses.edx.org/register which seems to be in English only… So, no point testing it through the Spanish version. I guess I will have to look at the code and see if I find something.

Now that Juniper has been released, where should I create a new bug report about activation emails and the user preference not being followed for the original activation email?

This is a problem for Open edX instances supporting multiple languages like us at EDUlib. Whatever LANGUAGE_CODE is set to in /edx/etc/lms.yml, this is the language that will be used to send the activation email. Since LANGUAGE_CODE: fr in our case, users registering in English on our site would receive an activation message in French. This is different than the behaviour in previous releases of Open edX.

It seems language=preferences_api.get_user_preference(user, LANGUAGE_KEY) is not set properly in compose_activation_email in common/djangoapps/student/views/management.py at the time of the original activation email. It is set correctly when you try to authenticate again before activating your account. The second activation email is then sent in the preferred language of the user.

I would have loved to demonstrate it on the Spanish website of edx.org/es, but the Registrate button redirects to an English only registration page at courses.edx.org which would lead me to believe I would receive a message in English anyway. (edited)

It would be really nice if other Open edX instances running multiple languages can try to reproduce this bug. You just have to set LANGUAGE_CODE to a language and use another one to create a new account.

Oh, and compose_activation_email isn’t present in common/djangoapps/student/views/management.py under Ironwood… so this is new code in Juniper

compose_and_send_activation_email is used in Ironwood and I might have to backport this code to Juniper in our fork.

i18n works great when dealing with one language at a time. Dealing with 2 languages simultaneously is a different ballgame.

Open edX instances only using one language would never encounter this bug.

Here is what I did as a proof of concept of the bug.

In /edx/etc/lms.yml, I have
LANGUAGE_CODE: en

I’ve modified /edx/app/edxapp/edx-platform/common/djangoapps/student/views/management.py so that I force the language to French and output some traces in /edx/var/logs/lms/edx.log during the initial account creation and when I try to login a second time so that the activation email is sent again.

In compose_activation_email:
msg = AccountActivation().personalize(
recipient=Recipient(user.username, dest_addr),
#####language=preferences_api.get_user_preference(user, LANGUAGE_KEY),
language=“fr”,
user_context=message_context,
)

thisuserpreflang = preferences_api.get_user_preference(user, LANGUAGE_KEY)
log.info("TRACE PIERRE: USER NAME is %s", user.username)
log.info("TRACE PIERRE: LANGUAGE_KEY is %s", LANGUAGE_KEY)
log.info("TRACE PIERRE: LANGUAGE PREF is %s", thisuserpreflang)

Since my instance supports both English and French, I tried registering an account in French. Here is what I found in the logs.

Jul 29 09:12:51 ip-10-0-0-71 [service_variant=lms][audit][env:sandbox] INFO [ip-10-0-0-71 386] [user 170169] [models.py:2450] - Login success - user.id: 170169
Jul 29 09:12:51 ip-10-0-0-71 [service_variant=lms][edx.student][env:sandbox] INFO [ip-10-0-0-71 386] [user 170169] [management.py:198] - TRACE PIERRE: USER NAME is umtest203_v3
Jul 29 09:12:51 ip-10-0-0-71 [service_variant=lms][edx.student][env:sandbox] INFO [ip-10-0-0-71 386] [user 170169] [management.py:199] - TRACE PIERRE: LANGUAGE_KEY is pref-lang
Jul 29 09:12:51 ip-10-0-0-71 [service_variant=lms][edx.student][env:sandbox] INFO [ip-10-0-0-71 386] [user 170169] [management.py:200] - TRACE PIERRE: LANGUAGE PREF is None
Jul 29 09:12:51 ip-10-0-0-71 [service_variant=lms][celery.worker.strategy][env:sandbox] INFO [ip-10-0-0-71 490] [user None] [strategy.py:60] - Received task: student.tasks.send_activation_email[646bbb08-cb82-460f-9a15-0406dc1d4525]
Jul 29 09:12:52 ip-10-0-0-71 [service_variant=lms][celery.worker.job][env:sandbox] INFO [ip-10-0-0-71 490] [user None] [job.py:402] - Task student.tasks.send_activation_email[646bbb08-cb82-460f-9a15-0406dc1d4525] succeeded in 0.18702953699994396s: None
Jul 29 09:12:53 ip-10-0-0-71 [service_variant=lms][audit][env:sandbox] INFO [ip-10-0-0-71 386] [user 170169] [register.py:249] - Login success on new account creation - umtest203_v3
Jul 29 09:14:12 ip-10-0-0-71 [service_variant=lms][audit][env:sandbox] INFO [ip-10-0-0-71 386] [user 170169] [models.py:2460] - Logout - user.id: 170169
Jul 29 09:14:42 ip-10-0-0-71 [service_variant=lms][audit][env:sandbox] WARNING [ip-10-0-0-71 407] [user None] [login.py:173] - Login failed - Account not active for user.id: 170169, resending activation
Jul 29 09:14:42 ip-10-0-0-71 [service_variant=lms][edx.student][env:sandbox] INFO [ip-10-0-0-71 407] [user None] [management.py:198] - TRACE PIERRE: USER NAME is umtest203_v3
Jul 29 09:14:42 ip-10-0-0-71 [service_variant=lms][edx.student][env:sandbox] INFO [ip-10-0-0-71 407] [user None] [management.py:199] - TRACE PIERRE: LANGUAGE_KEY is pref-lang
Jul 29 09:14:42 ip-10-0-0-71 [service_variant=lms][edx.student][env:sandbox] INFO [ip-10-0-0-71 407] [user None] [management.py:200] - TRACE PIERRE: LANGUAGE PREF is fr
Jul 29 09:14:42 ip-10-0-0-71 [service_variant=lms][celery.worker.strategy][env:sandbox] INFO [ip-10-0-0-71 490] [user None] [strategy.py:60] - Received task: student.tasks.send_activation_email[a0e6260e-976b-4289-9fe1-a45dd08d81a3]
Jul 29 09:14:42 ip-10-0-0-71 [service_variant=lms][edx.student][env:sandbox] ERROR [ip-10-0-0-71 407] [user None] [login.py:449] - {‘success’: False, ‘value’: Markup(‘Pour vous connecter, vous devez activer votre compte.

Nous venons d’envoyer un lien d’activation à umtest203@edulib.org. Si vous ne recevez pas un courriel, vérifiez vos dossiers de courrier indésirable ou contacter le Support EDUlib .’)}
Traceback (most recent call last):
File “/edx/app/edxapp/edx-platform/openedx/core/djangoapps/user_authn/views/login.py”, line 425, in login_user
_handle_failed_authentication(user, possibly_authenticated_user)
File “/edx/app/edxapp/edx-platform/openedx/core/djangoapps/user_authn/views/login.py”, line 223, in _handle_failed_authentication
_log_and_raise_inactive_user_auth_error(user)
File “/edx/app/edxapp/edx-platform/openedx/core/djangoapps/user_authn/views/login.py”, line 183, in _log_and_raise_inactive_user_auth_error
raise AuthFailedError(_generate_not_activated_message(unauthenticated_user))
openedx.core.djangoapps.user_authn.exceptions.AuthFailedError
Jul 29 09:14:42 ip-10-0-0-71 [service_variant=lms][celery.worker.job][env:sandbox] INFO [ip-10-0-0-71 490] [user None] [job.py:402] - Task student.tasks.send_activation_email[a0e6260e-976b-4289-9fe1-a45dd08d81a3] succeeded in 0.04874986100003298s: None

Notice that if I didn’t force language to be set to fr when making the call to AccountActivation, LANGUAGE PREF was None and the original activation email would have been sent in English because LANGUAGE_CODE: en in /edx/etc/lms.yml.

Notice the second time, when I try to login a second time before activating the account, where LANGUAGE PREF is now fr.

I am now convinced there is a bug somewhere that doesn’t take into account the language used by the user when filling the form when creating an account or that doesn’t set it properly in user_preferences before AccountActivation is called.

Open edX instances only supporting one language will never face this bug since all users are created with the same default language. Therefore, all activation emails will be sent in the same language based on LANGUAGE_CODE.

Unfortunately, Open edX instances supporting multiple languages through Django Admin dark_lang and a language selector will face this issue when user try to register in a language that is not the site’s default language. They will then receive an activation email that is not in the language they used to register.

THIS IS A BUG. And a MAJOR one for us since we do support multiple languages because we have courses in multiple languages.

Should I open a Community Report Incident?
How long would it take to be prioritized?

P.S. I’ve also noticed that all the account activation code has been redone between Ironwood and Juniper. Some tests might not have run in order to test this test case. Everything was working fine under Ironwood.

Digging a little bit further, I found this in create_account_with_params in openedx/core/djangoapps/user_authn/views/register.py

if skip_email:
    registration.activate()
else:
    compose_and_send_activation_email(user, profile, registration)

# Perform operations that are non-critical parts of account creation
create_or_set_user_attribute_created_on_site(user, request.site)

preferences_api.set_user_preference(user, LANGUAGE_KEY, get_language())

So, does it prove that the language preferences is definitely set after the original compose_and_send_activation_email is called?

@sambapete I believe creating a CRI ticket in Jira like before a release is still the correct way to report issues like this. Or since you have already identified the issue in the code, maybe send a PR to fix the issue in master, that will likely shorten the path to getting it backported to the juniper release?