Skip to content

Resolve "Email templates are not translated to zh_CN"

related to MR on JiHu

What does this MR do and why?

This MR is to solve the problem that the mail sent is not localized according to user preference_language when single recipient.

As for "multiple recipients", "emails with cc/bcc and to is blank" are sent using the default locale :en.

Usages of mail in gitlab

In gitlab, the usage of mail is classified into three types according to the format of to:

  1. :to is a string type, a single email address
  2. :to is an array type
  3. :to is blank with :bcc
:to is a string type, a single email address :to is an array type :to is blank with :bcc
locale recipient's preferred language ::I18n.default_locale ::I18n.default_locale
use example image-20220825123819705 image-20220825123901369 image-20220825123935314
test case https://gitlab.com/gitlab-jh/jh-team/gitlab/-/blob/upstream-1456-email-templates-translation/spec/mailers/notify_spec.rb#L132 https://gitlab.com/gitlab-jh/jh-team/gitlab/-/blob/upstream-1456-email-templates-translation/spec/mailers/repository_check_mailer_spec.rb#L17 https://gitlab.com/gitlab-jh/jh-team/gitlab/-/blob/upstream-1456-email-templates-translation/ee/spec/mailers/license_mailer_spec.rb#L12

Problem cause and solution

Problem cause: An around_action render_with_default_locale in ApplicationMailer used default locale instead of recipient language preference.

  def render_with_default_locale(&block)
    Gitlab::I18n.with_default_locale(&block)
  end

Solution: Define mail_with_locale in ApplicationMailer to set the locale according to the recipient's language preference.Also replace mail with mail_with_locale

  def mail_with_locale(headers = {}, &block)
    locale = recipient_locale headers

    Gitlab::I18n.with_locale(locale) do
      mail(headers, &block)
    end
  end

  def recipient_locale(headers = {})
    locale = I18n.locale
    locale = preferred_language_by_email headers[:to] if headers[:to].is_a?(String)
    locale = preferred_language_by_email headers[:to][0] if headers[:to].is_a?(Array) && headers[:to].length == 1
    locale
  end

  def preferred_language_by_email(email)
    email_obj = Email.find_by_email email
    email_obj ? User.find(email_obj.user_id)&.preferred_language || I18n.locale : I18n.locale
  end

Why

There are some reasons do this:

Our original idea was to override mail in ApplicationMailer:

  • Why override mail: There are about 50 direct calls to mail (excluding spec) in gitlab. It would be very complex and difficult to maintain to set the locale on its caller without overriding mail
  • Why override under ApplicationMailer: The callers of the mail method are all from the ApplicationMailer class and its subclasses. Overriding the mail method under ApplicationMailer can solve all problems at once

But it is inappropriate for mail to be rewritten as the base api. So we choose to define mail_with_locale to achieve a similar effect. Even this adds modification: replace mail with mail_with_locale.

How to set up and validate locally

  1. Login to your GDK
  2. Go to any project
  3. Click Issues > any issue
  4. Add an assignee
  5. Open /rails/letter_opener
  6. See the mail about adding an assignee.

MR acceptance checklist

This checklist encourages us to confirm any changes have been analyzed to reduce risks in quality, performance, reliability, security, and maintainability.

cc @prajnamas

Edited by qt

Merge request reports

Loading