Repository: torchbox/wagtail-footnotes (language: python)

Issue:
Enable translation of footnotes
Adds `TranslatableMixin` to the `Footnote` model to allow it to be translatable.


Discussion / hints:

Fix patch:
diff --git a/.gitignore b/.gitignore
index 7cf364b..54e7e50 100644
--- a/.gitignore
+++ b/.gitignore
@@ -52,7 +52,6 @@ coverage.xml
 cover/
 
 # Translations
-*.mo
 *.pot
 
 # Django stuff:
diff --git a/README.md b/README.md
index fa6c536..37c57ba 100644
--- a/README.md
+++ b/README.md
@@ -124,6 +124,36 @@ WAGTAILADMIN_RICH_TEXT_EDITORS = {
   - Default: `["bold", "italic", "link"]`
   - Use this to update a list of Rich Text features allowed in the footnote text.
 
+## 🌍 Internationalisation
+
+Wagtail Footnotes can be translated. Note that in a multi-lingual setup, the URL setup for footnotes
+needs to be in a `i18n_patterns()` call with `prefix_default_language=False`:
+
+```python
+# urls.py
+
+urlpatterns += i18n_patterns(
+    path("footnotes/", include(footnotes_urls)),
+    # ...
+    path("", include(wagtail_urls)),
+    prefix_default_language=False,
+)
+```
+
+or outside `i18n_patterns()`:
+
+```python
+# urls.py
+
+urlpattherns += [
+    path("footnotes/", include(footnotes_urls)),
+]
+urlpatterns += i18n_patterns(
+    # ...
+    path("", include(wagtail_urls)),
+)
+```
+
 ## 💡 Common issues
 
 - I click on the `Fn` button in the editor and it stops working
diff --git a/wagtail_footnotes/locale/en/LC_MESSAGES/django.mo b/wagtail_footnotes/locale/en/LC_MESSAGES/django.mo
new file mode 100644
index 0000000..71cbdf3
Binary files /dev/null and b/wagtail_footnotes/locale/en/LC_MESSAGES/django.mo differ
diff --git a/wagtail_footnotes/locale/en/LC_MESSAGES/django.po b/wagtail_footnotes/locale/en/LC_MESSAGES/django.po
new file mode 100644
index 0000000..301de16
--- /dev/null
+++ b/wagtail_footnotes/locale/en/LC_MESSAGES/django.po
@@ -0,0 +1,55 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) 2024 Torchbox
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2024-05-17 09:04-0500\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"Language: \n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=(n != 1);\n"
+#: templates/wagtail_footnotes/admin/footnotes_modal.html:14
+msgid "Choose a footnote"
+msgstr ""
+
+#: templates/wagtail_footnotes/admin/footnotes_modal.html:26
+msgid "Footnotes"
+msgstr ""
+
+#: templates/wagtail_footnotes/admin/footnotes_modal.html:28
+msgid ""
+"To add a new footnote, close this window and scroll to the \"Footnotes\" "
+"section at bottom of the page."
+msgstr ""
+
+#: templates/wagtail_footnotes/admin/footnotes_modal.html:36
+msgid "Text"
+msgstr ""
+
+#: templates/wagtail_footnotes/admin/footnotes_modal.html:37
+msgid "ID"
+msgstr ""
+
+#: templates/wagtail_footnotes/admin/footnotes_modal.html:45
+msgid ""
+"Footnotes will appear with arbitrary numbers here in the editor. On the "
+"published page, and in previews, their numbering will be numerical and "
+"ordered."
+msgstr ""
+
+#: templates/wagtail_footnotes/includes/footnotes.html:6
+msgid "Foonotes"
+msgstr ""
+
+#: templates/wagtail_footnotes/includes/footnotes.html:12
+msgid "Back to content"
+msgstr ""
diff --git a/wagtail_footnotes/locale/ro/LC_MESSAGES/django.mo b/wagtail_footnotes/locale/ro/LC_MESSAGES/django.mo
new file mode 100644
index 0000000..37d3d47
Binary files /dev/null and b/wagtail_footnotes/locale/ro/LC_MESSAGES/django.mo differ
diff --git a/wagtail_footnotes/locale/ro/LC_MESSAGES/django.po b/wagtail_footnotes/locale/ro/LC_MESSAGES/django.po
new file mode 100644
index 0000000..98ddcee
--- /dev/null
+++ b/wagtail_footnotes/locale/ro/LC_MESSAGES/django.po
@@ -0,0 +1,63 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: \n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2024-05-17 09:06-0500\n"
+"PO-Revision-Date: 2024-05-17 15:23+0100\n"
+"Last-Translator: \n"
+"Language-Team: \n"
+"Language: ro\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=3; plural=(n==1 ? 0 : n==0 || (n!=1 && n%100>=1 && "
+"n%100<=19) ? 1 : 2);\n"
+"X-Generator: Poedit 3.4.4\n"
+
+#: templates/wagtail_footnotes/admin/footnotes_modal.html:14
+msgid "Choose a footnote"
+msgstr "Alegeți o notă de subsol"
+
+#: templates/wagtail_footnotes/admin/footnotes_modal.html:26
+msgid "Footnotes"
+msgstr "Note de subsol"
+
+#: templates/wagtail_footnotes/admin/footnotes_modal.html:28
+msgid ""
+"To add a new footnote, close this window and scroll to the \"Footnotes\" "
+"section at bottom of the page."
+msgstr ""
+"Pentru a adăuga o notă nouă de subsol, închideți această fereastră și "
+"derulați la secțiunea „Note de subsol”."
+
+#: templates/wagtail_footnotes/admin/footnotes_modal.html:36
+msgid "Text"
+msgstr "Text"
+
+#: templates/wagtail_footnotes/admin/footnotes_modal.html:37
+msgid "ID"
+msgstr "ID"
+
+#: templates/wagtail_footnotes/admin/footnotes_modal.html:45
+msgid ""
+"Footnotes will appear with arbitrary numbers here in the editor. On the "
+"published page, and in previews, their numbering will be numerical and "
+"ordered."
+msgstr ""
+"Notele de subsol vor apărea ca un set de numere și cifre aleatorii în "
+"editorul de text. Pe pagina publicată și în previzualizări, numerotarea va "
+"fi numerică și ordonată."
+
+#: templates/wagtail_footnotes/includes/footnotes.html:6
+msgid "Foonotes"
+msgstr "Note de subsol"
+
+#: templates/wagtail_footnotes/includes/footnotes.html:12
+msgid "Back to content"
+msgstr "Înapoi la conținut"
diff --git a/wagtail_footnotes/migrations/0003_add_bootstrap_translatable_mixin.py b/wagtail_footnotes/migrations/0003_add_bootstrap_translatable_mixin.py
new file mode 100755
index 0000000..002dfcb
--- /dev/null
+++ b/wagtail_footnotes/migrations/0003_add_bootstrap_translatable_mixin.py
@@ -0,0 +1,39 @@
+# Generated by Django 4.2.9 on 2024-01-11 12:53
+
+import django.db.models.deletion
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+    dependencies = [
+        ("wagtailcore", "0078_referenceindex"),
+        ("wagtail_footnotes", "0002_alter_footnote_unique_together"),
+    ]
+
+    operations = [
+        migrations.AlterUniqueTogether(
+            name="footnote",
+            unique_together={("page", "uuid")},
+        ),
+        migrations.AddField(
+            model_name="footnote",
+            name="locale",
+            field=models.ForeignKey(
+                editable=False,
+                null=True,
+                on_delete=django.db.models.deletion.PROTECT,
+                related_name="+",
+                to="wagtailcore.locale",
+            ),
+        ),
+        migrations.AddField(
+            model_name="footnote",
+            name="translation_key",
+            field=models.UUIDField(editable=False, null=True),
+        ),
+        migrations.AlterUniqueTogether(
+            name="footnote",
+            unique_together={("translation_key", "locale"), ("page", "uuid")},
+        ),
+    ]
diff --git a/wagtail_footnotes/migrations/0004_boostrap_translatable_mixin_data_migration.py b/wagtail_footnotes/migrations/0004_boostrap_translatable_mixin_data_migration.py
new file mode 100755
index 0000000..8e86620
--- /dev/null
+++ b/wagtail_footnotes/migrations/0004_boostrap_translatable_mixin_data_migration.py
@@ -0,0 +1,14 @@
+# Generated by Django 4.2.9 on 2024-01-11 12:56
+
+from django.db import migrations
+from wagtail.models import BootstrapTranslatableModel
+
+
+class Migration(migrations.Migration):
+    dependencies = [
+        ("wagtail_footnotes", "0003_add_bootstrap_translatable_mixin"),
+    ]
+
+    operations = [
+        BootstrapTranslatableModel("wagtail_footnotes.Footnote"),
+    ]
diff --git a/wagtail_footnotes/migrations/0005_alter_footnote_locale_alter_footnote_translation_key.py b/wagtail_footnotes/migrations/0005_alter_footnote_locale_alter_footnote_translation_key.py
new file mode 100755
index 0000000..62efe8f
--- /dev/null
+++ b/wagtail_footnotes/migrations/0005_alter_footnote_locale_alter_footnote_translation_key.py
@@ -0,0 +1,32 @@
+# Generated by Django 4.2.9 on 2024-01-11 12:58
+
+import uuid
+
+import django.db.models.deletion
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+    dependencies = [
+        ("wagtailcore", "0078_referenceindex"),
+        ("wagtail_footnotes", "0004_boostrap_translatable_mixin_data_migration"),
+    ]
+
+    operations = [
+        migrations.AlterField(
+            model_name="footnote",
+            name="locale",
+            field=models.ForeignKey(
+                editable=False,
+                on_delete=django.db.models.deletion.PROTECT,
+                related_name="+",
+                to="wagtailcore.locale",
+            ),
+        ),
+        migrations.AlterField(
+            model_name="footnote",
+            name="translation_key",
+            field=models.UUIDField(default=uuid.uuid4, editable=False),
+        ),
+    ]
diff --git a/wagtail_footnotes/models.py b/wagtail_footnotes/models.py
index 4665d3d..5f1ce3e 100644
--- a/wagtail_footnotes/models.py
+++ b/wagtail_footnotes/models.py
@@ -3,12 +3,13 @@
 from modelcluster.fields import ParentalKey
 from wagtail.admin.panels import FieldPanel
 from wagtail.fields import RichTextField
+from wagtail.models import TranslatableMixin
 
 from wagtail_footnotes.fields import CustomUUIDField
 from wagtail_footnotes.widgets import ReadonlyUUIDInput
 
 
-class Footnote(models.Model):
+class Footnote(TranslatableMixin, models.Model):
     """
     Footnote has a UUID field which is set using JavaScript on object creation
     so that it is available immediately for hardcoding a reference to the
@@ -29,8 +30,8 @@ class Footnote(models.Model):
 
     panels = [FieldPanel("text"), FieldPanel("uuid", widget=ReadonlyUUIDInput)]
 
-    class Meta:
-        unique_together = ("page", "uuid")
+    class Meta(TranslatableMixin.Meta):
+        unique_together = [("page", "uuid"), ("translation_key", "locale")]
 
     def __str__(self):
         return str(self.uuid)
diff --git a/wagtail_footnotes/static/footnotes/js/footnotes.js b/wagtail_footnotes/static/footnotes/js/footnotes.js
index ae1ff2d..54257ea 100644
--- a/wagtail_footnotes/static/footnotes/js/footnotes.js
+++ b/wagtail_footnotes/static/footnotes/js/footnotes.js
@@ -50,8 +50,8 @@ class FootnoteSource extends React.Component {
           "#id_footnotes-FORMS .w-panel"
         );
         Array.prototype.forEach.call(live_footnotes, function (value) {
-          var text = $(".public-DraftEditor-content", value).text();
-          var uuid = $('input[id*="-uuid"]', value)[0].value;
+          const text = $(".public-DraftEditor-content", value).text();
+          const uuid = $('input[id*="-uuid"]', value)[0].value;
           var row = $(
             "<tr data-uuid=" +
             uuid +
@@ -112,7 +112,6 @@ class FootnoteSource extends React.Component {
   }
 
   render() {
-    console.log("FootnoteSource", this.props);
     return null;
   }
 }
diff --git a/wagtail_footnotes/templates/wagtail_footnotes/admin/footnotes_modal.html b/wagtail_footnotes/templates/wagtail_footnotes/admin/footnotes_modal.html
index 0f1c0d6..82034a5 100644
--- a/wagtail_footnotes/templates/wagtail_footnotes/admin/footnotes_modal.html
+++ b/wagtail_footnotes/templates/wagtail_footnotes/admin/footnotes_modal.html
@@ -1,3 +1,4 @@
+{% load i18n %}
 {% comment %}
     This template is used in Wagtail CMS
 {% endcomment %}
@@ -6,40 +7,45 @@
         <div class="modal-content">
             <button type="button" class="button close button--icon text-replace" data-dismiss="modal"><svg class="icon icon-cross" aria-hidden="true"><use href="#icon-cross"></use></svg>Close</button>
             <div class="modal-body">
-
                 <header class="w-header w-header--merged">
                     <div class="row">
                         <div class="left">
                             <div class="col">
-                                <h1 class="w-header__title">Choose a footnote</h1>
+                                <h1 class="header-title w-header__title">{% translate "Choose a footnote" %}</h1>
                             </div>
 
-                            </div>
-                            <div class="right">
+                            <div class="right"></div>
                         </div>
                     </div>
                 </header>
 
                 <div class="w-tabs" data-tabs="" data-tabs-disable-url="">
-                    <div class="w-tabs__wrapper w-overflow-hidden">
-                        <div role="tablist" class="w-tabs__list w-w-full"><!-- intentionally empty to get some top padding --></div>
-                    </div>
+                    <div class="w-tabs__wrapper"></div>
                     <div class="tab-content">
                         <div class="w-tabs__panel">
-                            <h2>Footnotes</h2>
-                            <p>To add a new footnote, close this window and scroll to the "FOOTNOTES" section at bottom of the page.</p>
+                            <h2>{% translate "Footnotes" %}</h2>
+                            <p>
+                                {% blocktranslate trimmed %}
+                                    To add a new footnote, close this window and scroll to the "Footnotes" section at bottom of the page.
+                                {% endblocktranslate %}
+                            </p>
+
                             <table id="footnotes-listing" class="listing">
                                 <thead>
                                     <tr>
-                                        <th>Text</th>
-                                        <th>ID</th>
+                                        <th>{% translate "Text" %}</th>
+                                        <th>{% translate "ID" %}</th>
                                     </tr>
                                 </thead>
                                 <tbody>
-
                                 </tbody>
                             </table>
-                            <p>Footnotes will appear with arbitrary numbers here in the editor. In the published page, and in previews, their numbering will be numerical and ordered.</p>
+
+                            <p>
+                                {% blocktranslate trimmed %}
+                                    Footnotes will appear with arbitrary numbers here in the editor. On the published page, and in previews, their numbering will be numerical and ordered.
+                                {% endblocktranslate %}
+                            </p>
                         </div>
                     </div>
                 </div>
diff --git a/wagtail_footnotes/templates/wagtail_footnotes/includes/footnotes.html b/wagtail_footnotes/templates/wagtail_footnotes/includes/footnotes.html
index 275dd24..92e57fe 100644
--- a/wagtail_footnotes/templates/wagtail_footnotes/includes/footnotes.html
+++ b/wagtail_footnotes/templates/wagtail_footnotes/includes/footnotes.html
@@ -1,15 +1,15 @@
-{% load wagtailcore_tags %}
+{% load wagtailcore_tags i18n %}
 
 {% if page.footnotes_list %}
     <div class="footnotes" id="footnotes">
         <h2 id="footnote-label">
-            Footnotes
+            {% translate "Foonotes" %}
         </h2>
         <ol>
             {% for footnote in page.footnotes_list %}
                 <li id="footnote-{{ forloop.counter }}">
                     [{{ forloop.counter }}] {{ footnote.text|richtext }}
-                    <a href="#footnote-source-{{ forloop.counter }}" aria-label="Back to content">↩</a>
+                    <a href="#footnote-source-{{ forloop.counter }}" aria-label="{% translate "Back to content" %}">↩</a>
                 </li>
             {% endfor %}
         </ol>


Test patch:
diff --git a/tests/settings.py b/tests/settings.py
index c832642..e166029 100644
--- a/tests/settings.py
+++ b/tests/settings.py
@@ -39,6 +39,8 @@
     "wagtail.search",
     "wagtail.admin",
     "wagtail_modeladmin",
+    "wagtail.contrib.simple_translation",
+    "wagtail.contrib.redirects",
     "wagtail.sites",
     "wagtail",
     "taggit",
@@ -53,6 +55,7 @@
 MIDDLEWARE = [
     "django.middleware.security.SecurityMiddleware",
     "django.contrib.sessions.middleware.SessionMiddleware",
+    "django.middleware.locale.LocaleMiddleware",
     "django.middleware.common.CommonMiddleware",
     "django.middleware.csrf.CsrfViewMiddleware",
     "django.contrib.auth.middleware.AuthenticationMiddleware",
@@ -110,6 +113,11 @@
 
 USE_TZ = True
 
+USE_I18N = True
+WAGTAIL_I18N_ENABLED = True
+LANGUAGE_CODE = "en"
+
+
 # Static files (CSS, JavaScript, Images)
 # https://docs.djangoproject.com/en/stable/howto/static-files/
 
diff --git a/tests/templates/base.html b/tests/templates/base.html
index f0a8cf7..570d5f7 100644
--- a/tests/templates/base.html
+++ b/tests/templates/base.html
@@ -1,6 +1,9 @@
-{% load wagtailuserbar %}
+{% load wagtailuserbar i18n %}
+
+{% get_current_language as LANGUAGE_CODE %}
+
 <!DOCTYPE html>
-<html lang="en">
+<html lang="{{ LANGUAGE_CODE }}">
 
 <head>
     <meta charset="UTF-8">
diff --git a/tests/test/test_translation.py b/tests/test/test_translation.py
new file mode 100644
index 0000000..c08bef6
--- /dev/null
+++ b/tests/test/test_translation.py
@@ -0,0 +1,155 @@
+import json
+
+from bs4 import BeautifulSoup as bs4
+from django.test import override_settings
+from django.urls import reverse
+from django.utils import translation
+from wagtail.models import Locale, Page
+from wagtail.test.utils import TestCase, WagtailTestUtils
+
+from wagtail_footnotes.models import Footnote
+
+from ..models import TestPageStreamField
+
+
+@override_settings(
+    LANGUAGES=[
+        ("en", "English"),
+        ("fr", "French"),
+        ("de", "German"),
+    ],
+    WAGTAIL_CONTENT_LANGUAGES=[
+        ("en", "English"),
+        ("fr", "French"),
+        ("de", "German"),
+    ],
+)
+class TestSubmitPageTranslationView(WagtailTestUtils, TestCase):
+    @classmethod
+    def setUpTestData(cls):
+        cls.en_locale = Locale.objects.first()
+        cls.fr_locale = Locale.objects.create(language_code="fr")
+        cls.de_locale = Locale.objects.create(language_code="de")
+
+        cls.en_homepage = Page.objects.get(title="Welcome to your new Wagtail site!")
+        cls.fr_homepage = cls.en_homepage.copy_for_translation(cls.fr_locale)
+        cls.fr_homepage.save_revision().publish()
+        cls.de_homepage = cls.en_homepage.copy_for_translation(cls.de_locale)
+        cls.de_homepage.save_revision().publish()
+
+        cls.uuid = "f291a4b7-5ac5-4030-b341-b1993efb2ad2"
+        cls.en_test_page = TestPageStreamField(
+            title="Test Page With Footnote",
+            slug="test-page-with-footnote",
+            body=json.dumps(
+                [
+                    {
+                        "type": "paragraph",
+                        "value": f'<p>This is a paragraph with a footnote. <footnote id="{cls.uuid}">1</footnote></p>',
+                    },
+                ]
+            ),
+        )
+        cls.en_homepage.add_child(instance=cls.en_test_page)
+        cls.en_test_page.save_revision().publish()
+        cls.en_footnote = Footnote.objects.create(
+            page=cls.en_test_page,
+            uuid=cls.uuid,
+            text="This is a footnote",
+        )
+        cls.url = reverse(
+            "simple_translation:submit_page_translation", args=(cls.en_test_page.id,)
+        )
+
+    def setUp(self):
+        super().setUp()
+        self.login()
+
+    def test_translating_page_translates_footnote(self):
+        de = self.de_locale.id
+        fr = self.fr_locale.id
+        data = {"locales": [de, fr], "include_subtree": True}
+        self.client.post(self.url, data, follow=True)
+
+        de_footnote = self.en_footnote.get_translation(de)
+        self.assertEqual(de_footnote.text, self.en_footnote.text)
+        self.assertEqual(de_footnote.uuid, self.en_footnote.uuid)
+        de_test_page = self.en_test_page.get_translation(de)
+        self.assertCountEqual(de_test_page.footnotes.all(), [de_footnote])
+
+        fr_footnote = self.en_footnote.get_translation(fr)
+        self.assertEqual(fr_footnote.text, self.en_footnote.text)
+        self.assertEqual(fr_footnote.uuid, self.en_footnote.uuid)
+        fr_test_page = self.en_test_page.get_translation(fr)
+        self.assertCountEqual(fr_test_page.footnotes.all(), [fr_footnote])
+
+        # Can also change the text:
+        fr_footnote.text = "This is a French translated footnote"
+        fr_footnote.save(update_fields=["text"])
+        fr_footnote.refresh_from_db()
+        en_footnote = self.en_footnote
+        en_footnote.refresh_from_db()
+        self.assertEqual(fr_footnote.text, "This is a French translated footnote")
+        self.assertNotEqual(fr_footnote.text, en_footnote.text)
+
+    def test_translated_page_shows_translated_footnote(self):
+        fr = self.fr_locale.id
+        data = {"locales": [fr], "include_subtree": True}
+        response = self.client.post(self.url, data, follow=True)
+
+        fr_test_page = self.en_test_page.get_translation(fr)
+
+        self.assertRedirects(
+            response, reverse("wagtailadmin_pages:edit", args=[fr_test_page.pk])
+        )
+
+        self.assertIn(
+            "The page 'Test Page With Footnote' was successfully created in French",
+            [msg.message for msg in response.context["messages"]],
+        )
+
+        fr_footnote = self.en_footnote.get_translation(fr)
+        self.assertEqual(fr_footnote.text, self.en_footnote.text)
+        self.assertEqual(fr_footnote.uuid, self.en_footnote.uuid)
+        self.assertCountEqual(fr_test_page.footnotes.all(), [fr_footnote])
+
+        fr_test_page.title = ("[FR] Test Page With Footnote",)
+        fr_test_page.body = json.dumps(
+            [
+                {
+                    "type": "paragraph",
+                    "value": f'<p>This is a French paragraph with a footnote. <footnote id="{self.uuid}">1</footnote></p>',
+                },
+            ]
+        )
+        fr_test_page.save_revision().publish()
+        fr_test_page.refresh_from_db()
+
+        # Can also change the text:
+        fr_footnote.text = "This is a French translated footnote"
+        fr_footnote.save()
+
+        translation.activate("fr")
+
+        response = self.client.get(fr_test_page.get_full_url())
+        self.assertEqual(response.status_code, 200)
+
+        soup = bs4(response.content, "html.parser")
+
+        # Test that required html tags are present with correct
+        # attrs that enable the footnotes to respond to clicks
+        source_anchor = soup.find("a", {"id": "footnote-source-1"})
+        self.assertTrue(source_anchor)
+
+        source_anchor_string = str(source_anchor)
+        self.assertIn("<sup>[1]</sup>", source_anchor_string)
+        self.assertIn('href="#footnote-1"', source_anchor_string)
+        self.assertIn('id="footnote-source-1"', source_anchor_string)
+
+        footnotes = soup.find("div", {"class": "footnotes"})
+        self.assertTrue(footnotes)
+
+        footnotes_string = str(footnotes)
+        self.assertIn('id="footnote-1"', footnotes_string)
+        self.assertIn('href="#footnote-source-1"', footnotes_string)
+        self.assertIn("[1] This is a French translated footnote", footnotes_string)
diff --git a/tests/urls.py b/tests/urls.py
index 2417fa8..57bd950 100644
--- a/tests/urls.py
+++ b/tests/urls.py
@@ -1,3 +1,4 @@
+from django.conf.urls.i18n import i18n_patterns
 from django.contrib import admin
 from django.urls import include, path
 from wagtail import urls as wagtail_urls
@@ -11,6 +12,10 @@
     path("django-admin/", admin.site.urls),
     path("admin/", include(wagtailadmin_urls)),
     path("documents/", include(wagtaildocs_urls)),
+]
+
+urlpatterns += i18n_patterns(
     path("footnotes/", include(footnotes_urls)),
     path("", include(wagtail_urls)),
-]
+    prefix_default_language=False,
+)