summaryrefslogtreecommitdiffstats
path: root/server/src/locale.cppm
diff options
context:
space:
mode:
Diffstat (limited to 'server/src/locale.cppm')
-rw-r--r--server/src/locale.cppm65
1 files changed, 26 insertions, 39 deletions
diff --git a/server/src/locale.cppm b/server/src/locale.cppm
index 263de1d..00a3d36 100644
--- a/server/src/locale.cppm
+++ b/server/src/locale.cppm
@@ -26,65 +26,52 @@ concept locale_input_range =
26 && std:: 26 && std::
27 same_as<std::locale const&, std::ranges::range_const_reference_t<T>>; 27 same_as<std::locale const&, std::ranges::range_const_reference_t<T>>;
28 28
29class bcp47_tag : public std::locale::facet
30{
31 std::string tag_;
32
33public:
34 static std::locale::id id;
35
36 explicit bcp47_tag(std::locale locale);
37 ~bcp47_tag() override = default;
38
39 auto tag() const -> std::string_view;
40};
41
29// Helps select a locale based on the Accept-Language header in an 42// Helps select a locale based on the Accept-Language header in an
30// HTTP request. 43// HTTP request.
31export class selector 44export class selector
32{ 45{
46 std::vector<std::locale> supported_;
33 std::locale default_; 47 std::locale default_;
34 icu::LocaleMatcher matcher_; 48 icu::LocaleMatcher matcher_;
35 std::shared_ptr<blocale::generator const> lgen_;
36 49
37 auto make_matcher( 50 static auto make_matcher(std::vector<std::locale> const& supported_locales)
38 locale_input_range auto supported_locales, std::locale default_locale) 51 -> icu::LocaleMatcher;
39 {
40 auto builder = icu::LocaleMatcher::Builder{};
41 for (auto const& supported_locale : supported_locales)
42 {
43 auto const& supported_locale_info =
44 std::use_facet<blocale::info>(supported_locale);
45 auto supported_icu_locale =
46 icu::Locale{supported_locale_info.name().c_str()};
47 if (supported_icu_locale.isBogus())
48 throw std::runtime_error{
49 "supported locale gives rise to bogus ICU locale"
50 };
51 builder.addSupportedLocale(supported_icu_locale);
52 }
53 auto const& default_locale_info =
54 std::use_facet<blocale::info>(default_locale);
55 auto default_icu_locale = icu::Locale{default_locale_info.name().c_str()};
56 if (default_icu_locale.isBogus())
57 throw std::runtime_error{"default locale gives rise to bogus ICU locale"};
58 builder.setDefaultLocale(&default_icu_locale);
59 auto ec = UErrorCode::U_ZERO_ERROR;
60 auto matcher = builder.build(ec);
61 if (U_FAILURE(ec))
62 throw std::runtime_error{"failed to build icu::LocaleMatcher"};
63 return matcher;
64 }
65 52
66 // Trimming optional whitespace as defined in RFC 9110, § 12.4.2. 53 // Trimming optional whitespace as defined in RFC 9110, § 12.4.2.
67 static auto ltrim_ows(std::string_view s) -> std::string_view; 54 static auto ltrim_ows(std::string_view s) -> std::string_view;
68 static auto rtrim_ows(std::string_view s) -> std::string_view; 55 static auto rtrim_ows(std::string_view s) -> std::string_view;
69 static auto trim_ows(std::string_view s) -> std::string_view; 56 static auto trim_ows(std::string_view s) -> std::string_view;
70 57
71 auto from_icu_locale(icu::Locale const& l) const -> std::locale;
72
73public: 58public:
74 // Note: lgen must live at least as long as the selector constructed here! 59 explicit selector(locale_input_range auto supported, std::locale default_)
75 // It is unfortunately not possible to copy/move a blocale::generator. 60 : supported_{
76 explicit selector( 61 std::from_range,
77 locale_input_range auto locales, std::locale default_, 62 supported
78 std::shared_ptr<blocale::generator const> lgen) 63 | std::views::transform(
79 : default_{default_}, matcher_{make_matcher(locales, default_)}, lgen_{lgen} 64 [](std::locale const& locale) -> std::locale
65 { return std::locale{locale, new bcp47_tag{locale}}; })
66 },
67 default_{std::locale{default_, new bcp47_tag{default_}}},
68 matcher_{make_matcher(supported_)}
80 { 69 {
81 } 70 }
82 71
83 auto select(std::string_view accept_language) const -> std::locale; 72 auto select(std::string_view accept_language) const -> std::locale;
84}; 73};
85 74
86auto to_bcp47_lang_tag(std::locale locale) -> std::optional<std::string>;
87
88export auto make_generator() -> std::shared_ptr<blocale::generator const>; 75export auto make_generator() -> std::shared_ptr<blocale::generator const>;
89 76
90} // namespace routemon::locale 77} // namespace routemon::locale