diff --git a/notifications_utils/jinja_templates/email/email_template.jinja2 b/notifications_utils/jinja_templates/email/email_template.jinja2 index d9222e08b..01ead5a27 100644 --- a/notifications_utils/jinja_templates/email/email_template.jinja2 +++ b/notifications_utils/jinja_templates/email/email_template.jinja2 @@ -1,6 +1,6 @@ {% if complete_html %} - +
diff --git a/notifications_utils/template.py b/notifications_utils/template.py index 6f81592a1..bfd133d38 100644 --- a/notifications_utils/template.py +++ b/notifications_utils/template.py @@ -389,6 +389,7 @@ def __init__( allow_html=False, alt_text_en=None, alt_text_fr=None, + lang=None, ): super().__init__(template, values, jinja_path=jinja_path) self.fip_banner_english = fip_banner_english @@ -403,6 +404,11 @@ def __init__( self.alt_text_en = alt_text_en self.alt_text_fr = alt_text_fr self.text_direction_rtl = template.get("text_direction_rtl", False) + # BCP 47 language tag for the rendered attribute. Defaults to + # "en" so existing callers keep their current behaviour, but French / bilingual + # callers should pass "fr" or "und" so screen readers announce the document + # language correctly (WCAG 3.1.1). + self.lang = lang or "en" # set this again to make sure the correct either utils / downstream local jinja is used # however, don't set if we are in a test environment (to preserve the above mock) @@ -447,6 +453,7 @@ def __str__(self): "alt_text_en": self.alt_text_en, "alt_text_fr": self.alt_text_fr, "text_direction_rtl": self.text_direction_rtl, + "lang": self.lang, } ) @@ -493,6 +500,7 @@ def __init__( alt_text_en=None, alt_text_fr=None, user_language="en", + lang=None, ): super().__init__( template, @@ -517,6 +525,7 @@ def __init__( self.alt_text_fr = alt_text_fr self.user_language = user_language self.text_direction_rtl = template.get("text_direction_rtl", False) + self.lang = lang or "en" def __str__(self): return Markup( @@ -544,6 +553,7 @@ def __str__(self): "alt_text_en": self.alt_text_en, "alt_text_fr": self.alt_text_fr, "text_direction_rtl": self.text_direction_rtl, + "lang": self.lang, } ) ) diff --git a/tests/test_template_types.py b/tests/test_template_types.py index fcc0d2f25..3c7a78cb2 100644 --- a/tests/test_template_types.py +++ b/tests/test_template_types.py @@ -88,6 +88,41 @@ def test_fip_banner_french(renderer, show_banner): assert "canada-logo.png" not in str(email) +def test_html_email_lang_defaults_to_english(): + rendered = str(HTMLEmailTemplate({"content": "hello world", "subject": ""})) + assert '' in rendered + + +@pytest.mark.parametrize( + "lang,expected", + [ + ("fr", ''), + ("fr-CA", ''), + ("en-CA", ''), + ("und", ''), + ], +) +def test_html_email_lang_is_threaded_into_html_tag(lang, expected): + rendered = str(HTMLEmailTemplate({"content": "hello world", "subject": ""}, lang=lang)) + assert expected in rendered + + +def test_html_email_lang_falls_back_to_english_when_none(): + rendered = str(HTMLEmailTemplate({"content": "hello world", "subject": ""}, lang=None)) + assert '' in rendered + + +def test_html_email_bilingual_blocks_get_inline_lang_attributes(): + # add_language_divs already wraps [[en]]/[[fr]] blocks with lang attributes; + # for bilingual content the document-level lang should be set by the caller + # (e.g. to "und") so screen readers pick up the lang on the inline divs. + bilingual_content = "[[en]]\nHello\n[[/en]]\n[[fr]]\nBonjour\n[[/fr]]" + rendered = str(HTMLEmailTemplate({"content": bilingual_content, "subject": ""}, lang="und")) + assert '' in rendered + assert '