Repository: wagtail/wagtail

Issue:
Confirmation message on creating user says "User {0} created"
![Screenshot 2023-01-09 at 14 11 37](https://user-images.githubusercontent.com/85097/211372297-5fe2d0e5-8d47-40c9-95c6-9baf34319e54.png)

### Steps to Reproduce

* log in to admin
* settings -> Users -> Add a user

-   I have confirmed that this issue can be reproduced as described on a fresh Wagtail project: yes

### Technical details

-   Python version: 3.8.0
-   Django version: 4.0.8
-   Wagtail version: main (959a802c76ea760a5893e27783815e580a89d2c4)



Discussion:
I guess this was missed from 5c1c2c8f531d96f4568f6dfa6ce71bc32dd9d16c because it's also missing the `_(...)` wrapper:

https://github.com/wagtail/wagtail/blob/959a802c76ea760a5893e27783815e580a89d2c4/wagtail/users/views/users.py#L149

(Actually there's a secondary error on the confirmation messages in this file - `_` is aliased to `gettext`, so we need to use `gettext_lazy` explicitly).

Looks like this is the only user-facing occurrence of `'{0}'` (although there are two more in `wagtail.test.testapp.views` that are also worth fixing).

Resolving patch:
diff --git a/wagtail/users/views/users.py b/wagtail/users/views/users.py
--- a/wagtail/users/views/users.py
+++ b/wagtail/users/views/users.py
@@ -146,7 +146,7 @@ class Create(CreateView):
     add_url_name = "wagtailusers_users:add"
     index_url_name = "wagtailusers_users:index"
     edit_url_name = "wagtailusers_users:edit"
-    success_message = "User '{0}' created."
+    success_message = gettext_lazy("User '%(object)s' created.")
     page_title = gettext_lazy("Add user")
 
     def run_before_hook(self):
@@ -178,7 +178,7 @@ class Edit(EditView):
     index_url_name = "wagtailusers_users:index"
     edit_url_name = "wagtailusers_users:edit"
     delete_url_name = "wagtailusers_users:delete"
-    success_message = _("User '%(object)s' updated.")
+    success_message = gettext_lazy("User '%(object)s' updated.")
     context_object_name = "user"
     error_message = gettext_lazy("The user could not be saved due to errors.")
 
@@ -250,7 +250,7 @@ class Delete(DeleteView):
     index_url_name = "wagtailusers_users:index"
     page_title = gettext_lazy("Delete user")
     context_object_name = "user"
-    success_message = _("User '%(object)s' deleted.")
+    success_message = gettext_lazy("User '%(object)s' deleted.")
 
     def dispatch(self, request, *args, **kwargs):
         self.object = self.get_object()


Test patch:
diff --git a/wagtail/test/testapp/views.py b/wagtail/test/testapp/views.py
--- a/wagtail/test/testapp/views.py
+++ b/wagtail/test/testapp/views.py
@@ -67,7 +67,7 @@ class TestEditView(EditView):
     edit_url_name = "testapp_generic_edit"
     delete_url_name = "testapp_generic_delete"
     form_class = CustomModelEditForm
-    success_message = "User '{0}' updated."
+    success_message = gettext_lazy("User '%(object)s' updated.")
     page_title = gettext_lazy("test edit view")
 
 
@@ -79,5 +79,5 @@ class TestDeleteView(DeleteView):
     index_url_name = "testapp_generic_index"
     edit_url_name = "testapp_generic_edit"
     delete_url_name = "testapp_generic_delete"
-    success_message = "User '{0}' updated."
+    success_message = gettext_lazy("User '%(object)s' updated.")
     page_title = gettext_lazy("test delete view")
diff --git a/wagtail/users/tests/test_admin_views.py b/wagtail/users/tests/test_admin_views.py
--- a/wagtail/users/tests/test_admin_views.py
+++ b/wagtail/users/tests/test_admin_views.py
@@ -213,8 +213,10 @@ def setUp(self):
     def get(self, params={}):
         return self.client.get(reverse("wagtailusers_users:add"), params)
 
-    def post(self, post_data={}):
-        return self.client.post(reverse("wagtailusers_users:add"), post_data)
+    def post(self, post_data={}, follow=False):
+        return self.client.post(
+            reverse("wagtailusers_users:add"), post_data, follow=follow
+        )
 
     def test_simple(self):
         response = self.get()
@@ -232,7 +234,8 @@ def test_create(self):
                 "last_name": "User",
                 "password1": "password",
                 "password2": "password",
-            }
+            },
+            follow=True,
         )
 
         # Should redirect back to index
@@ -241,6 +244,10 @@ def test_create(self):
         # Check that the user was created
         users = get_user_model().objects.filter(email="test@user.com")
         self.assertEqual(users.count(), 1)
+        if settings.AUTH_USER_MODEL == "emailuser.EmailUser":
+            self.assertContains(response, "User &#x27;test@user.com&#x27; created.")
+        else:
+            self.assertContains(response, "User &#x27;testuser&#x27; created.")
 
     @unittest.skipUnless(
         settings.AUTH_USER_MODEL == "customuser.CustomUser",
@@ -531,9 +538,11 @@ def get(self, params={}):
             reverse("wagtailusers_users:delete", args=(self.test_user.pk,)), params
         )
 
-    def post(self, post_data={}):
+    def post(self, post_data={}, follow=False):
         return self.client.post(
-            reverse("wagtailusers_users:delete", args=(self.test_user.pk,)), post_data
+            reverse("wagtailusers_users:delete", args=(self.test_user.pk,)),
+            post_data,
+            follow=follow,
         )
 
     def test_simple(self):
@@ -542,7 +551,7 @@ def test_simple(self):
         self.assertTemplateUsed(response, "wagtailusers/users/confirm_delete.html")
 
     def test_delete(self):
-        response = self.post()
+        response = self.post(follow=True)
 
         # Should redirect back to index
         self.assertRedirects(response, reverse("wagtailusers_users:index"))
@@ -550,6 +559,12 @@ def test_delete(self):
         # Check that the user was deleted
         users = get_user_model().objects.filter(email="testuser@email.com")
         self.assertEqual(users.count(), 0)
+        if settings.AUTH_USER_MODEL == "emailuser.EmailUser":
+            self.assertContains(
+                response, "User &#x27;testuser@email.com&#x27; deleted."
+            )
+        else:
+            self.assertContains(response, "User &#x27;testuser&#x27; deleted.")
 
     def test_user_cannot_delete_self(self):
         response = self.client.get(
@@ -710,10 +725,11 @@ def get(self, params={}, user_id=None):
             params,
         )
 
-    def post(self, post_data={}, user_id=None):
+    def post(self, post_data={}, user_id=None, follow=False):
         return self.client.post(
             reverse("wagtailusers_users:edit", args=(user_id or self.test_user.pk,)),
             post_data,
+            follow=follow,
         )
 
     def test_simple(self):
@@ -745,7 +761,8 @@ def test_simple_post(self):
                 "password1": "newpassword",
                 "password2": "newpassword",
                 "is_active": "on",
-            }
+            },
+            follow=True,
         )
         # Should redirect back to index
         self.assertRedirects(response, reverse("wagtailusers_users:index"))
@@ -754,6 +771,10 @@ def test_simple_post(self):
         user = get_user_model().objects.get(pk=self.test_user.pk)
         self.assertEqual(user.first_name, "Edited")
         self.assertTrue(user.check_password("newpassword"))
+        if settings.AUTH_USER_MODEL == "emailuser.EmailUser":
+            self.assertContains(response, "User &#x27;test@user.com&#x27; updated.")
+        else:
+            self.assertContains(response, "User &#x27;testuser&#x27; updated.")
 
     def test_password_optional(self):
         """Leaving password fields blank should leave it unchanged"""