Skip to content

Commit 82dddc5

Browse files
authored
Merge pull request #9302 from Couchers-org/backend/fix/cache-localized-resource-responses
Backend: Cache localized GetLanguages/GetRegions responses per locale
2 parents ee37bd2 + 36b158b commit 82dddc5

2 files changed

Lines changed: 36 additions & 34 deletions

File tree

app/backend/src/couchers/i18n/context.py

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,6 @@
2121
localize_list,
2222
localize_time,
2323
localize_timezone,
24-
try_localize_language_name_from_iso639,
25-
try_localize_region_name_from_iso3166,
2624
)
2725
from couchers.models.users import User
2826
from couchers.utils import to_timezone
@@ -67,12 +65,6 @@ def __setattr__(self, name: str, value: Any) -> None:
6765
def localized_timezone(self) -> str:
6866
return localize_timezone(self.timezone, self.babel_locale)
6967

70-
def try_localize_language_name_from_iso639(self, code: str, standalone: bool = False) -> str | None:
71-
return try_localize_language_name_from_iso639(code, self.babel_locale, standalone=standalone)
72-
73-
def try_localize_region_name_from_iso3166(self, code: str) -> str | None:
74-
return try_localize_region_name_from_iso3166(code, self.babel_locale)
75-
7668
def localize_string(
7769
self, key: str, *, i18next: I18Next | None = None, substitutions: SubstitutionDict | None = None
7870
) -> str:

app/backend/src/couchers/servicers/resources.py

Lines changed: 36 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,14 @@
1+
import functools
12
import logging
23

4+
import babel
35
from google.protobuf import empty_pb2
46
from sqlalchemy.orm import Session
57

68
from couchers.context import CouchersContext
9+
from couchers.i18n.localize import try_localize_language_name_from_iso639, try_localize_region_name_from_iso3166
710
from couchers.proto import resources_pb2, resources_pb2_grpc
8-
from couchers.resources import (
9-
get_badge_dict,
10-
get_icon,
11-
get_language_dict,
12-
get_region_dict,
13-
get_terms_of_service,
14-
)
11+
from couchers.resources import get_badge_dict, get_icon, get_language_dict, get_region_dict, get_terms_of_service
1512

1613
logger = logging.getLogger(__name__)
1714

@@ -23,6 +20,36 @@
2320
]
2421

2522

23+
# These responses are static per locale, and localizing ~300 names costs tens of ms of CPU (mostly
24+
# babel.Locale.parse), so cache the built protos. Sharing one message across requests is safe as
25+
# long as nothing mutates responses after return (the tracing interceptor deepcopies before
26+
# sanitizing).
27+
@functools.lru_cache
28+
def _get_regions_res(locale: babel.Locale) -> resources_pb2.GetRegionsRes:
29+
return resources_pb2.GetRegionsRes(
30+
regions=[
31+
resources_pb2.Region(
32+
alpha3=alpha3,
33+
name=try_localize_region_name_from_iso3166(alpha3, locale) or english_name,
34+
)
35+
for alpha3, english_name in sorted(get_region_dict().items())
36+
]
37+
)
38+
39+
40+
@functools.lru_cache
41+
def _get_languages_res(locale: babel.Locale) -> resources_pb2.GetLanguagesRes:
42+
return resources_pb2.GetLanguagesRes(
43+
languages=[
44+
resources_pb2.Language(
45+
code=code,
46+
name=try_localize_language_name_from_iso639(code, locale, standalone=True) or english_name,
47+
)
48+
for code, english_name in sorted(get_language_dict().items())
49+
]
50+
)
51+
52+
2653
class Resources(resources_pb2_grpc.ResourcesServicer):
2754
def GetTermsOfService(
2855
self, request: empty_pb2.Empty, context: CouchersContext, session: Session
@@ -46,29 +73,12 @@ def GetCommunityGuidelines(
4673
def GetRegions(
4774
self, request: empty_pb2.Empty, context: CouchersContext, session: Session
4875
) -> resources_pb2.GetRegionsRes:
49-
return resources_pb2.GetRegionsRes(
50-
regions=[
51-
resources_pb2.Region(
52-
alpha3=alpha3,
53-
name=context.localization.try_localize_region_name_from_iso3166(alpha3) or english_name,
54-
)
55-
for alpha3, english_name in sorted(get_region_dict().items())
56-
]
57-
)
76+
return _get_regions_res(context.localization.babel_locale)
5877

5978
def GetLanguages(
6079
self, request: empty_pb2.Empty, context: CouchersContext, session: Session
6180
) -> resources_pb2.GetLanguagesRes:
62-
return resources_pb2.GetLanguagesRes(
63-
languages=[
64-
resources_pb2.Language(
65-
code=code,
66-
name=context.localization.try_localize_language_name_from_iso639(code, standalone=True)
67-
or english_name,
68-
)
69-
for code, english_name in sorted(get_language_dict().items())
70-
]
71-
)
81+
return _get_languages_res(context.localization.babel_locale)
7282

7383
def GetBadges(
7484
self, request: empty_pb2.Empty, context: CouchersContext, session: Session

0 commit comments

Comments
 (0)