Repository: zulip/zulip
Pull request #34218: Construct new channel notification message as a whole string rather than gluing strings together
Author: login: ritwik-69
Labels: name: bug
name: area: internationalization
name: size: XL
name: integration review
description: Added by maintainers when a PR may be ready for integration.
Created: 2025-03-29T08:56:35Z | Merged: 2025-04-15T23:28:38Z

<!-- Describe your pull request here.-->
This PR solves the issue which is described in this [comment](https://github.com/zulip/zulip/issues/30212#issuecomment-2246375514) as the original issue was already solved by updating the translation.

Note: "Channel created" event messages aren't sent for public_protected_history channels available only in Zephyr realms. This is an existing behaviour and this PR doesn't change that.

as the Previous PR #31009 for this issue was near completion I only had to fix conflicts.

[CZO discussion](https://chat.zulip.org/#narrow/stream/9-issues/topic/.F0.9F.93.82.C2.A0.20Inconsistent.20localization.20in.20new.20channel.20notif.20.2330212)

Fixes: #30212


<!-- If the PR makes UI changes, always include one or more still screenshots to demonstrate your changes. If it seems helpful, add a screen capture of the new functionality as well.

Tooling tips: https://zulip.readthedocs.io/en/latest/tutorials/screenshot-and-gif-software.html
-->

**Screenshots and screen captures:**

<table border="1">
    <tr>
        <th>Before/main branch</th>
        <th>After/issue#30212 branch</th>
    </tr>
    <tr>
        <td><img src="https://github.com/user-attachments/assets/7fdc72c7-2ce6-41b3-a3d5-45a355f46f38" alt="Before Image 1" ></td>
        <td><img src="https://github.com/user-attachments/assets/81015d06-9a22-4d80-846c-2cd725cf3337" alt="Before Image 1" ></td>
</table>


<details>
<summary>Self-review checklist</summary>

<!-- Prior to submitting a PR, follow our step-by-step guide to review your own code:
https://zulip.readthedocs.io/en/latest/contributing/code-reviewing.html#how-to-review-code -->

<!-- Once you create the PR, check off all the steps below that you have completed.
If any of these steps are not relevant or you have not completed, leave them unchecked.-->

- [x] [Self-reviewed](https://zulip.readthedocs.io/en/latest/contributing/code-reviewing.html#how-to-review-code) the changes for clarity and maintainability
      (variable names, code reuse, readability, etc.).

Communicate decisions, questions, and potential concerns.

- [x] Explains differences from previous plans (e.g., issue description).
- [x] Highlights technical choices and bugs encountered.
- [x] Calls out remaining decisions and concerns.
- [x] Automated tests verify logic where appropriate.

Individual commits are ready for review (see [commit discipline](https://zulip.readthedocs.io/en/latest/contributing/commit-discipline.html)).

- [x] Each commit is a coherent idea.
- [x] Commit message(s) explain reasoning and motivation for changes.

Completed manual review and testing of the following:

- [x] Visual appearance of the changes.
- [x] Responsiveness and internationalization.
- [x] Strings and tooltips.
- [x] End-to-end functionality of buttons, interactions and flows.
- [x] Corner cases, error conditions, and easily imagined bugs.
</details>



Diff:
diff --git a/zerver/actions/streams.py b/zerver/actions/streams.py
index 7fb83285c9170..5c9fc434b6b70 100644
--- a/zerver/actions/streams.py
+++ b/zerver/actions/streams.py
@@ -39,7 +39,7 @@
     can_access_stream_metadata_user_ids,
     check_basic_stream_access,
     get_anonymous_group_membership_dict_for_streams,
-    get_stream_permission_policy_name,
+    get_stream_permission_policy_key,
     get_stream_post_policy_value_based_on_group_setting,
     get_user_ids_with_metadata_access_via_permission_groups,
     get_users_dict_with_metadata_access_to_streams_via_permission_groups,
@@ -1339,16 +1339,18 @@ def do_change_stream_permission(
     )
     send_event_on_commit(stream.realm, event, notify_stream_update_ids)
 
-    old_policy_name = get_stream_permission_policy_name(
+    old_policy_key = get_stream_permission_policy_key(
         invite_only=old_invite_only_value,
         history_public_to_subscribers=old_history_public_to_subscribers_value,
         is_web_public=old_is_web_public_value,
     )
-    new_policy_name = get_stream_permission_policy_name(
+    old_policy_name = Stream.PERMISSION_POLICIES[old_policy_key]["policy_name"]
+    new_policy_key = get_stream_permission_policy_key(
         invite_only=stream.invite_only,
         history_public_to_subscribers=stream.history_public_to_subscribers,
         is_web_public=stream.is_web_public,
     )
+    new_policy_name = Stream.PERMISSION_POLICIES[new_policy_key]["policy_name"]
     send_change_stream_permission_notification(
         stream,
         old_policy_name=old_policy_name,
diff --git a/zerver/lib/streams.py b/zerver/lib/streams.py
index 95889cd131e6f..eccbb9e38eef0 100644
--- a/zerver/lib/streams.py
+++ b/zerver/lib/streams.py
@@ -90,24 +90,24 @@ class StreamDict(TypedDict, total=False):
     can_subscribe_group: UserGroup | None
 
 
-def get_stream_permission_policy_name(
+def get_stream_permission_policy_key(
     *,
     invite_only: bool | None = None,
     history_public_to_subscribers: bool | None = None,
     is_web_public: bool | None = None,
 ) -> str:
-    policy_name = None
-    for permission_dict in Stream.PERMISSION_POLICIES.values():
+    policy_key = None
+    for permission_key, permission_dict in Stream.PERMISSION_POLICIES.items():
         if (
             permission_dict["invite_only"] == invite_only
             and permission_dict["history_public_to_subscribers"] == history_public_to_subscribers
             and permission_dict["is_web_public"] == is_web_public
         ):
-            policy_name = permission_dict["policy_name"]
+            policy_key = permission_key
             break
 
-    assert policy_name is not None
-    return policy_name
+    assert policy_key is not None
+    return policy_key
 
 
 def get_default_value_for_history_public_to_subscribers(
diff --git a/zerver/tests/test_subs.py b/zerver/tests/test_subs.py
index 16612d1d0614d..c02c1321d9d64 100644
--- a/zerver/tests/test_subs.py
+++ b/zerver/tests/test_subs.py
@@ -894,6 +894,54 @@ def test_acting_user_is_creator(self) -> None:
         created_stream = new_streams[0]
         self.assertEqual(created_stream.creator_id, hamlet.id)
 
+    def test_channel_create_message_exists_for_all_policy_types(self) -> None:
+        """
+        Create a channel for each policy type to ensure they all have a "new channel" message.
+        """
+        # this is to check if the appropriate channel name is present in the "new channel" message
+        policy_key_map: dict[str, str] = {
+            "web_public": "**Web-public**",
+            "public": "**Public**",
+            "private_shared_history": "**Private, shared history**",
+            "private_protected_history": "**Private, protected history**",
+        }
+        for policy_key, policy_dict in Stream.PERMISSION_POLICIES.items():
+            channel_creator = self.example_user("desdemona")
+            subdomain = "zulip"
+
+            if policy_key == "public_protected_history":
+                # This is a special channel policy only available in Zephyr realms.
+                channel_creator = self.mit_user("starnine")
+                subdomain = "zephyr"
+
+            self.login_user(channel_creator)
+            new_channel_name = f"New {policy_key} channel"
+            result = self.api_post(
+                channel_creator,
+                "/json/users/me/subscriptions",
+                {
+                    "subscriptions": orjson.dumps([{"name": new_channel_name}]).decode(),
+                    "is_web_public": orjson.dumps(policy_dict["is_web_public"]).decode(),
+                    "invite_only": orjson.dumps(policy_dict["invite_only"]).decode(),
+                    "history_public_to_subscribers": orjson.dumps(
+                        policy_dict["history_public_to_subscribers"]
+                    ).decode(),
+                },
+                subdomain=subdomain,
+            )
+            self.assert_json_success(result)
+            new_channel = get_stream(new_channel_name, channel_creator.realm)
+            channel_events_messages = get_topic_messages(
+                channel_creator, new_channel, "channel events"
+            )
+            if policy_key == "public_protected_history":
+                # These do not get channel creation notification.
+                self.assert_length(channel_events_messages, 0)
+                continue
+
+            self.assert_length(channel_events_messages, 1)
+            self.assertIn(policy_key_map[policy_key], channel_events_messages[0].content)
+
 
 class RecipientTest(ZulipTestCase):
     def test_recipient(self) -> None:
diff --git a/zerver/views/streams.py b/zerver/views/streams.py
index c8d8fcca563c2..6c6b003e46afb 100644
--- a/zerver/views/streams.py
+++ b/zerver/views/streams.py
@@ -72,7 +72,7 @@
     filter_stream_authorization_for_adding_subscribers,
     get_anonymous_group_membership_dict_for_streams,
     get_stream_permission_default_group,
-    get_stream_permission_policy_name,
+    get_stream_permission_policy_key,
     list_to_streams,
     stream_to_dict,
     user_has_content_access,
@@ -879,20 +879,41 @@ def send_messages_for_new_subscribers(
                     stream_description = "*" + _("No description.") + "*"
                 else:
                     stream_description = stream.description
+
+                policy_key = get_stream_permission_policy_key(
+                    invite_only=stream.invite_only,
+                    history_public_to_subscribers=stream.history_public_to_subscribers,
+                    is_web_public=stream.is_web_public,
+                )
+                new_channel_message = None
+
+                # Policy `public_protected_history` is missing here as those channels don't get
+                # channel creation notification.
+                if policy_key == "web_public":
+                    new_channel_message = _(
+                        "**Web-public** channel created by {user_name}. **Description:**"
+                    )
+                elif policy_key == "public":
+                    new_channel_message = _(
+                        "**Public** channel created by {user_name}. **Description:**"
+                    )
+                elif policy_key == "private_shared_history":
+                    new_channel_message = _(
+                        "**Private, shared history** channel created by {user_name}. **Description:**"
+                    )
+                elif policy_key == "private_protected_history":
+                    new_channel_message = _(
+                        "**Private, protected history** channel created by {user_name}. **Description:**"
+                    )
+
+                assert new_channel_message is not None
                 notifications.append(
                     internal_prep_stream_message(
                         sender=sender,
                         stream=stream,
                         topic_name=str(Realm.STREAM_EVENTS_NOTIFICATION_TOPIC_NAME),
-                        content=_(
-                            "**{policy}** channel created by {user_name}. **Description:**"
-                        ).format(
+                        content=new_channel_message.format(
                             user_name=silent_mention_syntax_for_user(user_profile),
-                            policy=get_stream_permission_policy_name(
-                                invite_only=stream.invite_only,
-                                history_public_to_subscribers=stream.history_public_to_subscribers,
-                                is_web_public=stream.is_web_public,
-                            ),
                         )
                         + f"\n```` quote\n{stream_description}\n````",
                     ),


Reviews:
user: login: prakhar1144
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-04-04T06:45:41Z
user: login: ritwik-69
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-04-04T07:02:10Z
user: login: ritwik-69
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-04-04T07:14:05Z
user: login: prakhar1144
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-04-08T05:04:24Z
user: login: prakhar1144
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-04-08T11:55:28Z
user: login: prakhar1144
body: Thanks @ritwik-69 for iterating. LGTM!
state: APPROVED
author_association: MEMBER
submitted_at: 2025-04-09T04:20:15Z
user: login: timabbott
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-04-15T01:02:15Z

Review comments:
diff_hunk: @@ -885,6 +885,32 @@ def send_messages_for_new_subscribers(
                     history_public_to_subscribers=stream.history_public_to_subscribers,
                     is_web_public=stream.is_web_public,
                 )
+                new_channel_message = None
+
+                # Policy `public_protected_history` is missing here as those channels don't get
+                # channel creation notification.
+                if policy_key == "web_public":
+                    new_channel_message = _(
+                        "**Web-public** channel created by {user_name}. **Description:**\n"
+                        "{channel_description_in_quotes}"
+                    )
+                elif policy_key == "public":
+                    new_channel_message = _(
+                        "**Public** channel created by {user_name}. **Description:**\n"
+                        "{channel_description_in_quotes}"
+                    )
+                elif policy_key == "private_shared_history":
+                    new_channel_message = _(
+                        "**Private, shared history** channel created by {user_name}. **Description:**\n"
+                        "{channel_description_in_quotes}"
+                    )
+                elif policy_key == "private_protected_history":
+                    new_channel_message = _(
+                        "**Private, protected history** channel created by {user_name}. **Description:**\n"
+                        "{channel_description_in_quotes}"
+                    )
+
+                assert new_channel_message is not None
path: zerver/views/streams.py
user: login: prakhar1144
body: I don't think the code you have written is getting used at all.

`new_channel_message` is never getting used & `channel_description_in_quotes` is never set, right ?
created_at: 2025-04-04T06:45:35Z
author_association: MEMBER
diff_hunk: @@ -885,6 +885,32 @@ def send_messages_for_new_subscribers(
                     history_public_to_subscribers=stream.history_public_to_subscribers,
                     is_web_public=stream.is_web_public,
                 )
+                new_channel_message = None
+
+                # Policy `public_protected_history` is missing here as those channels don't get
+                # channel creation notification.
+                if policy_key == "web_public":
+                    new_channel_message = _(
+                        "**Web-public** channel created by {user_name}. **Description:**\n"
+                        "{channel_description_in_quotes}"
+                    )
+                elif policy_key == "public":
+                    new_channel_message = _(
+                        "**Public** channel created by {user_name}. **Description:**\n"
+                        "{channel_description_in_quotes}"
+                    )
+                elif policy_key == "private_shared_history":
+                    new_channel_message = _(
+                        "**Private, shared history** channel created by {user_name}. **Description:**\n"
+                        "{channel_description_in_quotes}"
+                    )
+                elif policy_key == "private_protected_history":
+                    new_channel_message = _(
+                        "**Private, protected history** channel created by {user_name}. **Description:**\n"
+                        "{channel_description_in_quotes}"
+                    )
+
+                assert new_channel_message is not None
path: zerver/views/streams.py
user: login: ritwik-69
body: ig i missed it, it should be used in `content` just below that.
created_at: 2025-04-04T07:02:10Z
author_association: COLLABORATOR
diff_hunk: @@ -885,6 +885,32 @@ def send_messages_for_new_subscribers(
                     history_public_to_subscribers=stream.history_public_to_subscribers,
                     is_web_public=stream.is_web_public,
                 )
+                new_channel_message = None
+
+                # Policy `public_protected_history` is missing here as those channels don't get
+                # channel creation notification.
+                if policy_key == "web_public":
+                    new_channel_message = _(
+                        "**Web-public** channel created by {user_name}. **Description:**\n"
+                        "{channel_description_in_quotes}"
+                    )
+                elif policy_key == "public":
+                    new_channel_message = _(
+                        "**Public** channel created by {user_name}. **Description:**\n"
+                        "{channel_description_in_quotes}"
+                    )
+                elif policy_key == "private_shared_history":
+                    new_channel_message = _(
+                        "**Private, shared history** channel created by {user_name}. **Description:**\n"
+                        "{channel_description_in_quotes}"
+                    )
+                elif policy_key == "private_protected_history":
+                    new_channel_message = _(
+                        "**Private, protected history** channel created by {user_name}. **Description:**\n"
+                        "{channel_description_in_quotes}"
+                    )
+
+                assert new_channel_message is not None
path: zerver/views/streams.py
user: login: ritwik-69
body: @prakhar1144 I made the changes!
created_at: 2025-04-04T07:14:05Z
author_association: COLLABORATOR
diff_hunk: @@ -894,6 +894,44 @@ def test_acting_user_is_creator(self) -> None:
         created_stream = new_streams[0]
         self.assertEqual(created_stream.creator_id, hamlet.id)
 
+    def test_channel_create_message_exists_for_all_policy_types(self) -> None:
+        """
+        Create a channel for each policy type to ensure they all have a "new channel" message.
+        """
+        for policy_key, policy_dict in Stream.PERMISSION_POLICIES.items():
+            channel_creator = self.example_user("desdemona")
+            subdomain = "zulip"
+
+            if policy_key == "public_protected_history":
+                # This is a special channel policy only available in Zephyr realms.
+                channel_creator = self.mit_user("starnine")
+                subdomain = "zephyr"
+
+            self.login_user(channel_creator)
+            new_channel_name = f"New {policy_key} channel"
+            res = self.api_post(
+                channel_creator,
+                "/json/users/me/subscriptions",
+                {
+                    "subscriptions": orjson.dumps([{"name": new_channel_name}]).decode(),
+                    "is_web_public": orjson.dumps(policy_dict["is_web_public"]).decode(),
+                    "invite_only": orjson.dumps(policy_dict["invite_only"]).decode(),
+                    "history_public_to_subscribers": orjson.dumps(
+                        policy_dict["history_public_to_subscribers"]
+                    ).decode(),
+                },
+                subdomain=subdomain,
+            )
+            self.assert_json_success(res)
+
+            if policy_key == "public_protected_history":
+                # These do not get channel creation notification.
path: zerver/tests/test_subs.py
user: login: prakhar1144
body: I think, the right check would be to verify `self.assert_length(new_channel_events, 0)` in this case.
created_at: 2025-04-08T04:38:19Z
author_association: MEMBER
diff_hunk: @@ -894,6 +894,44 @@ def test_acting_user_is_creator(self) -> None:
         created_stream = new_streams[0]
         self.assertEqual(created_stream.creator_id, hamlet.id)
 
+    def test_channel_create_message_exists_for_all_policy_types(self) -> None:
+        """
+        Create a channel for each policy type to ensure they all have a "new channel" message.
+        """
+        for policy_key, policy_dict in Stream.PERMISSION_POLICIES.items():
+            channel_creator = self.example_user("desdemona")
+            subdomain = "zulip"
+
+            if policy_key == "public_protected_history":
+                # This is a special channel policy only available in Zephyr realms.
+                channel_creator = self.mit_user("starnine")
+                subdomain = "zephyr"
+
+            self.login_user(channel_creator)
+            new_channel_name = f"New {policy_key} channel"
+            res = self.api_post(
+                channel_creator,
+                "/json/users/me/subscriptions",
+                {
+                    "subscriptions": orjson.dumps([{"name": new_channel_name}]).decode(),
+                    "is_web_public": orjson.dumps(policy_dict["is_web_public"]).decode(),
+                    "invite_only": orjson.dumps(policy_dict["invite_only"]).decode(),
+                    "history_public_to_subscribers": orjson.dumps(
+                        policy_dict["history_public_to_subscribers"]
+                    ).decode(),
+                },
+                subdomain=subdomain,
+            )
+            self.assert_json_success(res)
+
+            if policy_key == "public_protected_history":
+                # These do not get channel creation notification.
+                continue
+
+            new_channel = get_stream(new_channel_name, channel_creator.realm)
+            new_channel_events = get_topic_messages(channel_creator, new_channel, "channel events")
+            self.assert_length(new_channel_events, 1)
path: zerver/tests/test_subs.py
user: login: prakhar1144
body: It'd be great to verify the content in addition to the count of messages.
created_at: 2025-04-08T04:38:57Z
author_association: MEMBER
diff_hunk: @@ -894,6 +894,65 @@ def test_acting_user_is_creator(self) -> None:
         created_stream = new_streams[0]
         self.assertEqual(created_stream.creator_id, hamlet.id)
 
+    def test_channel_create_message_exists_for_all_policy_types(self) -> None:
+        """
+        Create a channel for each policy type to ensure they all have a "new channel" message.
+        """
+        for policy_key, policy_dict in Stream.PERMISSION_POLICIES.items():
+            channel_creator = self.example_user("desdemona")
+            subdomain = "zulip"
+
+            if policy_key == "public_protected_history":
+                # This is a special channel policy only available in Zephyr realms.
+                channel_creator = self.mit_user("starnine")
+                subdomain = "zephyr"
+
+            self.login_user(channel_creator)
+            new_channel_name = f"New {policy_key} channel"
+            res = self.api_post(
path: zerver/tests/test_subs.py
user: login: prakhar1144
body: `result` instead of `res`
created_at: 2025-04-08T11:31:28Z
author_association: MEMBER
diff_hunk: @@ -894,6 +894,65 @@ def test_acting_user_is_creator(self) -> None:
         created_stream = new_streams[0]
         self.assertEqual(created_stream.creator_id, hamlet.id)
 
+    def test_channel_create_message_exists_for_all_policy_types(self) -> None:
+        """
+        Create a channel for each policy type to ensure they all have a "new channel" message.
+        """
+        for policy_key, policy_dict in Stream.PERMISSION_POLICIES.items():
+            channel_creator = self.example_user("desdemona")
+            subdomain = "zulip"
+
+            if policy_key == "public_protected_history":
+                # This is a special channel policy only available in Zephyr realms.
+                channel_creator = self.mit_user("starnine")
+                subdomain = "zephyr"
+
+            self.login_user(channel_creator)
+            new_channel_name = f"New {policy_key} channel"
+            res = self.api_post(
+                channel_creator,
+                "/json/users/me/subscriptions",
+                {
+                    "subscriptions": orjson.dumps([{"name": new_channel_name}]).decode(),
+                    "is_web_public": orjson.dumps(policy_dict["is_web_public"]).decode(),
+                    "invite_only": orjson.dumps(policy_dict["invite_only"]).decode(),
+                    "history_public_to_subscribers": orjson.dumps(
+                        policy_dict["history_public_to_subscribers"]
+                    ).decode(),
+                },
+                subdomain=subdomain,
+            )
+            self.assert_json_success(res)
+            new_channel = get_stream(new_channel_name, channel_creator.realm)
+            new_channel_events = get_topic_messages(channel_creator, new_channel, "channel events")
path: zerver/tests/test_subs.py
user: login: prakhar1144
body: `channel_events_messages` -- `new_channel_events` sounds like referring to [events](https://zulip.readthedocs.io/en/latest/subsystems/events-system.html)
created_at: 2025-04-08T11:47:22Z
author_association: MEMBER
diff_hunk: @@ -894,6 +894,65 @@ def test_acting_user_is_creator(self) -> None:
         created_stream = new_streams[0]
         self.assertEqual(created_stream.creator_id, hamlet.id)
 
+    def test_channel_create_message_exists_for_all_policy_types(self) -> None:
+        """
+        Create a channel for each policy type to ensure they all have a "new channel" message.
+        """
+        for policy_key, policy_dict in Stream.PERMISSION_POLICIES.items():
+            channel_creator = self.example_user("desdemona")
+            subdomain = "zulip"
+
+            if policy_key == "public_protected_history":
+                # This is a special channel policy only available in Zephyr realms.
+                channel_creator = self.mit_user("starnine")
+                subdomain = "zephyr"
+
+            self.login_user(channel_creator)
+            new_channel_name = f"New {policy_key} channel"
+            res = self.api_post(
+                channel_creator,
+                "/json/users/me/subscriptions",
+                {
+                    "subscriptions": orjson.dumps([{"name": new_channel_name}]).decode(),
+                    "is_web_public": orjson.dumps(policy_dict["is_web_public"]).decode(),
+                    "invite_only": orjson.dumps(policy_dict["invite_only"]).decode(),
+                    "history_public_to_subscribers": orjson.dumps(
+                        policy_dict["history_public_to_subscribers"]
+                    ).decode(),
+                },
+                subdomain=subdomain,
+            )
+            self.assert_json_success(res)
+            new_channel = get_stream(new_channel_name, channel_creator.realm)
+            new_channel_events = get_topic_messages(channel_creator, new_channel, "channel events")
+            new_channel_message = (
+                f"channel created by @_**{channel_creator.full_name}|{channel_creator.id}**. **Description:**\n"
+                "```` quote\n*No description.*\n````"
+            )
+            if policy_key == "web_public":
+                self.assert_length(new_channel_events, 1)
+                self.assertEqual(
+                    new_channel_events[0].content, "**Web-public** " + new_channel_message
+                )
+            elif policy_key == "public":
+                self.assert_length(new_channel_events, 1)
+                self.assertEqual(new_channel_events[0].content, "**Public** " + new_channel_message)
+            elif policy_key == "private_shared_history":
+                self.assert_length(new_channel_events, 1)
+                self.assertEqual(
+                    new_channel_events[0].content,
+                    "**Private, shared history** " + new_channel_message,
+                )
+            elif policy_key == "private_protected_history":
+                self.assert_length(new_channel_events, 1)
+                self.assertEqual(
+                    new_channel_events[0].content,
+                    "**Private, protected history** " + new_channel_message,
+                )
+            elif policy_key == "public_protected_history":
+                # These do not get channel creation notification.
+                self.assert_length(new_channel_events, 0)
path: zerver/tests/test_subs.py
user: login: prakhar1144
body: I think a cleaner approach would be along the line of:
```
if policy_key == "public_protected_history":
  self.assert_length(new_channel_events, 0)
  continue

self.assert_length(new_channel_events, 1)
self.assertIn(map_name[policy_key], new_channel_events[0].content)
```

where `map_name` should be defined early on as:
```
map_name = {"web_public": "**Web-public**", "public": "**Public**", and so on...}
```

Make sure to give `map_name` / `new_channel_events` etc a better name; The above code snippet is to give an idea.
created_at: 2025-04-08T11:54:50Z
author_association: MEMBER
diff_hunk: @@ -885,18 +885,41 @@ def send_messages_for_new_subscribers(
                     history_public_to_subscribers=stream.history_public_to_subscribers,
                     is_web_public=stream.is_web_public,
                 )
+                new_channel_message = None
+
+                # Policy `public_protected_history` is missing here as those channels don't get
+                # channel creation notification.
+                if policy_key == "web_public":
+                    new_channel_message = _(
+                        "**Web-public** channel created by {user_name}. **Description:**\n"
+                        "{channel_description_in_quotes}"
+                    )
path: zerver/views/streams.py
user: login: timabbott
body: It seems like `"{channel_description_in_quotes}"` could be a separate translated string, to avoid duplicate work by translators? 
created_at: 2025-04-15T01:02:15Z
author_association: MEMBER

PR comments:
user: login: zulipbot
created_at: 2025-03-29T08:56:42Z
body: Hello @zulip/server-i18n members, this pull request was labeled with the "area: internationalization" label, so you may want to check it out!

<!-- areaLabelAddition -->

author_association: MEMBER
user: login: alya
created_at: 2025-04-02T17:14:54Z
body: @prakhar1144 Are you up for reviewing this one?
author_association: CONTRIBUTOR
user: login: alya
created_at: 2025-04-02T17:15:33Z
body: Actually, first, @ritwik-69 please add before/after screenshots. They should confirm that there are no changes in English (if that's what's expected).
author_association: CONTRIBUTOR
user: login: ritwik-69
created_at: 2025-04-02T17:42:10Z
body: @alya I have updated my PR It shows that there is no change in english after applying the changes.
author_association: COLLABORATOR
user: login: alya
created_at: 2025-04-02T19:23:07Z
body: OK, now I'm confused by your PR title. Are these changes for Welcome Bot or Notification Bot?
author_association: CONTRIBUTOR
user: login: ritwik-69
created_at: 2025-04-03T04:06:45Z
body: Apologies for the confusion It is the notification Bot and I have updated the title.
author_association: COLLABORATOR
user: login: alya
created_at: 2025-04-04T05:20:44Z
body: OK. @prakhar1144 are you up for reviewing this one?
author_association: CONTRIBUTOR
user: login: ritwik-69
created_at: 2025-04-08T08:39:16Z
body: @prakhar1144 I have made the suggested changes do let me know if the way i wrote the tests are satisfactory.

author_association: COLLABORATOR
user: login: ritwik-69
created_at: 2025-04-08T13:54:56Z
body: @prakhar1144 I made the suggested changes also added a comment clarifying the use of map.
author_association: COLLABORATOR
user: login: ritwik-69
created_at: 2025-04-15T14:29:34Z
body: @timabbott I made the requested changes. Do check them out.
author_association: COLLABORATOR
user: login: timabbott
created_at: 2025-04-15T23:28:51Z
body: Merged, thanks @ritwik-69 and @tnmkr and @prakhar1144!
author_association: MEMBER