numerique-gouv / impress

MIT License
13 stars 8 forks source link

Receive email notification in my language #323

Open virgile-dev opened 1 month ago

virgile-dev commented 1 month ago

Bug Report

Problematic behavior Even though my interface is in french I'm receiving notification emails in english. Right the emails are sent in the language setting the sender using on the app. It should be the opposite.

rvveber commented 1 month ago

I observed the same. User A sends invite to user B -> user B get's email in language of user A We need to store/set the language for the user B in the backend.

With my PR from #333 we will have the same language in the backend that we have in the frontend, because of sharing the language cookie impress_language.

We just need to read that cookie on the backend when the user B makes any request to it, and if it changed, update the language attribute on the user enttity for user B.

Then we always have up to date preferred language for the user B. And when user B is supposed to receive an invite/mail, we can translate based on his stored language, no matter who invited him.

rvveber commented 1 month ago

@lindenb1 and i would like to work on this issue next.

To do this, we would like to remove the current usage of the Content-Language Headers in both frontend and backend.

Instead we would update language via the users API endpoint on language selection in the frontend.

Then we would adapt the code that sends invitation emails, to associate the email-address with the receiving user, and use their language for translation of the email.

sampaccoud commented 1 month ago

associate the email-address with the receiving user,

@rvveber in the backend the email is sent to a user if we have one, so you will have access to user.language. If we have no user an invitation is sent to an email address but in this case we have no real way to determine a language... We could use the default language of the instance (settings.LANGUAGE_CODE) or the language of the requesting user like now? In the case of a governmental instance like us, the instance default language is paradoxically our best bet!

rvveber commented 1 month ago

in the backend the email is sent to a user if we have one, so you will have access to user.language

Oh great! Even better

If we have no user an invitation is sent to an email address

I didn't see that we could add any email address! Totally agree then to use the standard language as fallback

sampaccoud commented 1 month ago

You said:

With my PR from #333 we will have the same language in the backend that we have in the frontend, because of sharing the language cookie impress_language.

We just need to read that cookie on the backend when the user B makes any request to it, and if it changed, update the language attribute on the user enttity for user B.

But then you proposed:

Instead we would update language via the users API endpoint on language selection in the frontend.

Am I correct if I say this is in contradiction? If we update the field value on the user each time the cookie changes, we don't want to offer modifying it via the frontend because it will be confusing?

I would expect the value to be set the first time I login, and then being editable in my settings via the frontend. This means that we can set it in the authentication backend and not via a middleware and the cookie?

sampaccoud commented 1 month ago

I didn't see that we could add any email address!

@virgile-dev may not be obvious enough?

rvveber commented 1 month ago

You said:

With my PR from #333 we will have the same language in the backend that we have in the frontend, because of sharing the language cookie impress_language. We just need to read that cookie on the backend when the user B makes any request to it, and if it changed, update the language attribute on the user enttity for user B.

But then you proposed:

Instead we would update language via the users API endpoint on language selection in the frontend.

Am I correct if I say this is in contradiction? If we update the field value on the user each time the cookie changes, we don't want to offer modifying it via the frontend because it will be confusing?

I would expect the value to be set the first time I login, and then being editable in my settings via the frontend. This means that we can set it in the authentication backend and not via a middleware and the cookie?

The cookie determines the backend django language for the request as per LocaleMiddleware. (It also determines the frontend i18n language) But it is not persistet on the user. I believe, the language attribute on the user is not used for translation: https://docs.djangoproject.com/en/5.1/topics/i18n/translation/#how-django-discovers-language-preference And it make sense, because most of the time you want to display something, you have LocaleMiddleware between the user and the backend, but not in this case, where the user is not making the request.

My original idea was to take that backend language which is (determined by cookie as of #333) for the user and persist it on his user entity. Because it would be a minimal solution.

But maybe doing it on each request is unnecessary stress, if it only changes on language switch(set) anyways.

Since there is also an existing user endpoint to update language, i revised the most minimal solution might be to instead update user.language on language switching via Header.

Both would change to the same lang

rvveber commented 1 month ago

After external discussion with @sampaccoud we could agree on the process.

Currently the frontend detects its language in this order:

  1. cookie
  2. browser-lang

And stores the detected language in a cookie. (Which then results in translation)

I will add a detection strategy after the cookie, that will get the users language attribute:

  1. cookie
  2. user.language
  3. browser-lang

This way, when accessed from a new browser that has no cookie, or the cookie expired, we still get the users choosen language for the new cookie.

On language switch, i will update user.language asynchronously via API - then everything should be kept in sync, while still switching and loading instantly.

And of course finally, i will adapt to send the email in the users.language with fallback to djangos default language (settings.LANGUAGE_CODE).


Additional considerations: @sampaccoud mentioned, that it would be better to have an account settings page, where to change user settings such as language.