mirror of
				https://github.com/zulip/zulip.git
				synced 2025-11-04 05:53:43 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			213 lines
		
	
	
		
			7.4 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			213 lines
		
	
	
		
			7.4 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
from http.cookies import SimpleCookie
 | 
						||
from typing import TYPE_CHECKING, Any
 | 
						||
from unittest import mock
 | 
						||
 | 
						||
import orjson
 | 
						||
from django.conf import settings
 | 
						||
from django.core import mail
 | 
						||
from django.utils import translation
 | 
						||
from typing_extensions import override
 | 
						||
 | 
						||
from zerver.lib.email_notifications import enqueue_welcome_emails
 | 
						||
from zerver.lib.i18n import get_browser_language_code
 | 
						||
from zerver.lib.test_classes import ZulipTestCase
 | 
						||
from zerver.lib.test_helpers import HostRequestMock
 | 
						||
from zerver.management.commands import makemessages
 | 
						||
from zerver.models.streams import get_realm_stream
 | 
						||
 | 
						||
if TYPE_CHECKING:
 | 
						||
    from django.test.client import _MonkeyPatchedWSGIResponse as TestHttpResponse
 | 
						||
 | 
						||
 | 
						||
class EmailTranslationTestCase(ZulipTestCase):
 | 
						||
    def test_email_translation(self) -> None:
 | 
						||
        def check_translation(phrase: str, request_type: str, *args: Any, **kwargs: Any) -> None:
 | 
						||
            with self.captureOnCommitCallbacks(execute=True):
 | 
						||
                if request_type == "post":
 | 
						||
                    self.client_post(*args, **kwargs)
 | 
						||
                elif request_type == "patch":
 | 
						||
                    self.client_patch(*args, **kwargs)
 | 
						||
 | 
						||
            email_message = mail.outbox[0]
 | 
						||
            self.assertIn(phrase, email_message.body)
 | 
						||
 | 
						||
            for i in range(len(mail.outbox)):
 | 
						||
                mail.outbox.pop()
 | 
						||
 | 
						||
        hamlet = self.example_user("hamlet")
 | 
						||
        hamlet.default_language = "de"
 | 
						||
        hamlet.save()
 | 
						||
        realm = hamlet.realm
 | 
						||
        realm.default_language = "de"
 | 
						||
        realm.save()
 | 
						||
        stream = get_realm_stream("Denmark", realm.id)
 | 
						||
        invite_expires_in_minutes = 2 * 24 * 60
 | 
						||
        self.login_user(hamlet)
 | 
						||
 | 
						||
        check_translation(
 | 
						||
            "Wir haben eine Anfrage erhalten",
 | 
						||
            "patch",
 | 
						||
            "/json/settings",
 | 
						||
            {"email": "hamlets-new@zulip.com"},
 | 
						||
        )
 | 
						||
        check_translation(
 | 
						||
            "Excelente!",
 | 
						||
            "post",
 | 
						||
            "/accounts/home/",
 | 
						||
            {"email": "new-email@zulip.com"},
 | 
						||
            HTTP_ACCEPT_LANGUAGE="pt",
 | 
						||
        )
 | 
						||
        check_translation("Danke für", "post", "/accounts/find/", {"emails": hamlet.delivery_email})
 | 
						||
        check_translation(
 | 
						||
            "Hallo",
 | 
						||
            "post",
 | 
						||
            "/json/invites",
 | 
						||
            {
 | 
						||
                "invitee_emails": "new-email@zulip.com",
 | 
						||
                "stream_ids": orjson.dumps([stream.id]).decode(),
 | 
						||
                "invite_expires_in_minutes": invite_expires_in_minutes,
 | 
						||
            },
 | 
						||
        )
 | 
						||
 | 
						||
        with self.settings(DEVELOPMENT_LOG_EMAILS=True):
 | 
						||
            enqueue_welcome_emails(hamlet)
 | 
						||
        check_translation("Hier findest du einige Tipps", "")
 | 
						||
 | 
						||
 | 
						||
class TranslationTestCase(ZulipTestCase):
 | 
						||
    """
 | 
						||
    Translations strings should change with locale. URLs should be locale
 | 
						||
    aware.
 | 
						||
    """
 | 
						||
 | 
						||
    @override
 | 
						||
    def tearDown(self) -> None:
 | 
						||
        translation.activate(settings.LANGUAGE_CODE)
 | 
						||
        super().tearDown()
 | 
						||
 | 
						||
    # e.g. self.client_post(url) if method is "post"
 | 
						||
    def fetch(
 | 
						||
        self, method: str, url: str, expected_status: int, **kwargs: Any
 | 
						||
    ) -> "TestHttpResponse":
 | 
						||
        response = getattr(self, f"client_{method}")(url, **kwargs)
 | 
						||
        self.assertEqual(
 | 
						||
            response.status_code,
 | 
						||
            expected_status,
 | 
						||
            msg=f"Expected {expected_status}, received {response.status_code} for {method} to {url}",
 | 
						||
        )
 | 
						||
        return response
 | 
						||
 | 
						||
    def test_accept_language_header(self) -> None:
 | 
						||
        languages = [
 | 
						||
            ("en", "Sign up"),
 | 
						||
            ("de", "Registrieren"),
 | 
						||
            ("sr", "Региструјте се"),
 | 
						||
            ("zh-hans", "注册"),
 | 
						||
        ]
 | 
						||
 | 
						||
        for lang, word in languages:
 | 
						||
            response = self.fetch("get", "/integrations/", 200, HTTP_ACCEPT_LANGUAGE=lang)
 | 
						||
            self.assert_in_response(word, response)
 | 
						||
 | 
						||
    def test_cookie(self) -> None:
 | 
						||
        languages = [
 | 
						||
            ("en", "Sign up"),
 | 
						||
            ("de", "Registrieren"),
 | 
						||
            ("sr", "Региструјте се"),
 | 
						||
            ("zh-hans", "注册"),
 | 
						||
        ]
 | 
						||
 | 
						||
        for lang, word in languages:
 | 
						||
            # Applying str function to LANGUAGE_COOKIE_NAME to convert Unicode
 | 
						||
            # into an ascii otherwise SimpleCookie will raise an exception
 | 
						||
            self.client.cookies = SimpleCookie({str(settings.LANGUAGE_COOKIE_NAME): lang})
 | 
						||
 | 
						||
            response = self.fetch("get", "/integrations/", 200)
 | 
						||
            self.assert_in_response(word, response)
 | 
						||
 | 
						||
    def test_i18n_urls(self) -> None:
 | 
						||
        languages = [
 | 
						||
            ("en", "Sign up"),
 | 
						||
            ("de", "Registrieren"),
 | 
						||
            ("sr", "Региструјте се"),
 | 
						||
            ("zh-hans", "注册"),
 | 
						||
        ]
 | 
						||
 | 
						||
        for lang, word in languages:
 | 
						||
            response = self.fetch("get", f"/{lang}/integrations/", 200)
 | 
						||
            self.assert_in_response(word, response)
 | 
						||
 | 
						||
    def test_get_browser_language_code(self) -> None:
 | 
						||
        req = HostRequestMock()
 | 
						||
        self.assertIsNone(get_browser_language_code(req))
 | 
						||
 | 
						||
        req = HostRequestMock()
 | 
						||
        req.META["HTTP_ACCEPT_LANGUAGE"] = "de"
 | 
						||
        self.assertEqual(get_browser_language_code(req), "de")
 | 
						||
 | 
						||
        req = HostRequestMock()
 | 
						||
        req.META["HTTP_ACCEPT_LANGUAGE"] = "en-GB,en;q=0.8"
 | 
						||
        self.assertEqual(get_browser_language_code(req), "en-gb")
 | 
						||
 | 
						||
        # Case when unsupported language has higher weight.
 | 
						||
        req = HostRequestMock()
 | 
						||
        req.META["HTTP_ACCEPT_LANGUAGE"] = "en-IND;q=0.9,de;q=0.8"
 | 
						||
        self.assertEqual(get_browser_language_code(req), "de")
 | 
						||
 | 
						||
        # Browser locale is set to unsupported language.
 | 
						||
        req = HostRequestMock()
 | 
						||
        req.META["HTTP_ACCEPT_LANGUAGE"] = "en-IND"
 | 
						||
        self.assertIsNone(get_browser_language_code(req))
 | 
						||
 | 
						||
        req = HostRequestMock()
 | 
						||
        req.META["HTTP_ACCEPT_LANGUAGE"] = "*"
 | 
						||
        self.assertIsNone(get_browser_language_code(req))
 | 
						||
 | 
						||
 | 
						||
class JsonTranslationTestCase(ZulipTestCase):
 | 
						||
    @override
 | 
						||
    def tearDown(self) -> None:
 | 
						||
        translation.activate(settings.LANGUAGE_CODE)
 | 
						||
        super().tearDown()
 | 
						||
 | 
						||
    @mock.patch("zerver.lib.request._")
 | 
						||
    def test_json_error(self, mock_gettext: Any) -> None:
 | 
						||
        dummy_value = "this arg is bad: '{var_name}' (translated to German)"
 | 
						||
        mock_gettext.return_value = dummy_value
 | 
						||
 | 
						||
        self.login("hamlet")
 | 
						||
        result = self.client_post("/json/invites", HTTP_ACCEPT_LANGUAGE="de")
 | 
						||
 | 
						||
        expected_error = "this arg is bad: 'invitee_emails' (translated to German)"
 | 
						||
        self.assert_json_error_contains(result, expected_error, status_code=400)
 | 
						||
 | 
						||
    @mock.patch("zerver.views.auth._")
 | 
						||
    def test_jsonable_error(self, mock_gettext: Any) -> None:
 | 
						||
        dummy_value = "Some other language"
 | 
						||
        mock_gettext.return_value = dummy_value
 | 
						||
 | 
						||
        self.login("hamlet")
 | 
						||
        result = self.client_post("/de/accounts/login/jwt/")
 | 
						||
 | 
						||
        self.assert_json_error_contains(result, dummy_value, status_code=400)
 | 
						||
 | 
						||
 | 
						||
class FrontendRegexTestCase(ZulipTestCase):
 | 
						||
    def test_regexes(self) -> None:
 | 
						||
        command = makemessages.Command()
 | 
						||
 | 
						||
        data = [
 | 
						||
            (
 | 
						||
                "{{#tr}}english text with {variable}{{/tr}}{{/tr}}",
 | 
						||
                "english text with {variable}",
 | 
						||
            ),
 | 
						||
            ('{{t "english text" }}, "extra"}}', "english text"),
 | 
						||
            ("{{t 'english text' }}, 'extra'}}", "english text"),
 | 
						||
            ("{{> template var=(t 'english text') }}, 'extra'}}", "english text"),
 | 
						||
        ]
 | 
						||
 | 
						||
        for input_text, expected in data:
 | 
						||
            result = command.extract_strings(input_text)
 | 
						||
            self.assert_length(result, 1)
 | 
						||
            self.assertEqual(result[0], expected)
 |