Repository: zulip/zulip

Issue:
Spectator language picker always shows realm default language as current language.
The `default_language` parameter used for the logged-out view is always the realm's default language, not the language you picked in the UI. Having done a big of investigation, I believe the problem is that while we read from the browser's cookies inside home.py:
```
    if user_profile is None:                                                                             
        request_language = request.COOKIES.get(settings.LANGUAGE_COOKIE_NAME, default_language)          
```

The `page_params` for spectators come from a separate request to `GET /api/v1/register`, and thus don't inspect the cookies at all. I'm not sure I see an clean way to fix this, but probably easiest would be for `events_register_backend` to read the cookie inside the spectator code path, and pass it through as `request_language` to `do_events_register` and then `fetch_initial_state_data`, which can in turn initialize `settings_user` with `default_language=request_language or realm.default_language`, or something along those lines.

@amanagr FYI.


Discussion:

Resolving patch:
diff --git a/zerver/lib/events.py b/zerver/lib/events.py
--- a/zerver/lib/events.py
+++ b/zerver/lib/events.py
@@ -111,6 +111,7 @@ def fetch_initial_state_data(
     slim_presence: bool = False,
     include_subscribers: bool = True,
     include_streams: bool = True,
+    spectator_requested_language: Optional[str] = None,
 ) -> Dict[str, Any]:
     """When `event_types` is None, fetches the core data powering the
     web app's `page_params` and `/api/v1/register` (for mobile/terminal
@@ -372,6 +373,7 @@ def fetch_initial_state_data(
     if user_profile is not None:
         settings_user = user_profile
     else:
+        assert spectator_requested_language is not None
         # When UserProfile=None, we want to serve the values for various
         # settings as the defaults.  Instead of copying the default values
         # from models.py here, we access these default values from a
@@ -392,6 +394,7 @@ def fetch_initial_state_data(
             avatar_source=UserProfile.AVATAR_FROM_GRAVATAR,
             # ID=0 is not used in real Zulip databases, ensuring this is unique.
             id=0,
+            default_language=spectator_requested_language,
         )
     if want("realm_user"):
         state["raw_users"] = get_raw_user_data(
@@ -1332,6 +1335,7 @@ def do_events_register(
     client_capabilities: Dict[str, bool] = {},
     narrow: Collection[Sequence[str]] = [],
     fetch_event_types: Optional[Collection[str]] = None,
+    spectator_requested_language: Optional[str] = None,
 ) -> Dict[str, Any]:
     # Technically we don't need to check this here because
     # build_narrow_filter will check it, but it's nicer from an error
@@ -1380,6 +1384,7 @@ def do_events_register(
             include_subscribers=False,
             # Force include_streams=False for security reasons.
             include_streams=False,
+            spectator_requested_language=spectator_requested_language,
         )
 
         post_process_state(user_profile, ret, notification_settings_null=False)
diff --git a/zerver/views/events_register.py b/zerver/views/events_register.py
--- a/zerver/views/events_register.py
+++ b/zerver/views/events_register.py
@@ -1,5 +1,6 @@
 from typing import Dict, Optional, Sequence, Union
 
+from django.conf import settings
 from django.contrib.auth.models import AnonymousUser
 from django.http import HttpRequest, HttpResponse
 from django.utils.translation import gettext as _
@@ -75,6 +76,7 @@ def events_register_backend(
 ) -> HttpResponse:
     if maybe_user_profile.is_authenticated:
         user_profile = maybe_user_profile
+        spectator_requested_language = None
         assert isinstance(user_profile, UserProfile)
         realm = user_profile.realm
 
@@ -86,6 +88,10 @@ def events_register_backend(
     else:
         user_profile = None
         realm = get_valid_realm_from_request(request)
+        # Language set by spectator to be passed down to clients as user_settings.
+        spectator_requested_language = request.COOKIES.get(
+            settings.LANGUAGE_COOKIE_NAME, realm.default_language
+        )
 
         if not realm.allow_web_public_streams_access():
             raise MissingAuthenticationError()
@@ -112,5 +118,6 @@ def events_register_backend(
         include_subscribers=include_subscribers,
         client_capabilities=client_capabilities,
         fetch_event_types=fetch_event_types,
+        spectator_requested_language=spectator_requested_language,
     )
     return json_success(request, data=ret)


Test patch: