module; #include #include export module routemon:locale; import std; import :util; export namespace blocale = boost::locale; export namespace routemon { using lformat = blocale::format; using blocale::gettext; using blocale::translate; } // namespace routemon namespace routemon::locale { export template concept locale_input_range = std::ranges::input_range && std:: same_as>; // Helps select a locale based on the Accept-Language header in an // HTTP request. export class selector { std::locale default_; icu::LocaleMatcher matcher_; std::shared_ptr lgen_; auto make_matcher( locale_input_range auto supported_locales, std::locale default_locale) { auto builder = icu::LocaleMatcher::Builder{}; for (auto const& supported_locale : supported_locales) { auto const& supported_locale_info = std::use_facet(supported_locale); auto supported_icu_locale = icu::Locale{supported_locale_info.name().c_str()}; if (supported_icu_locale.isBogus()) throw std::runtime_error{ "supported locale gives rise to bogus ICU locale" }; builder.addSupportedLocale(supported_icu_locale); } auto const& default_locale_info = std::use_facet(default_locale); auto default_icu_locale = icu::Locale{default_locale_info.name().c_str()}; if (default_icu_locale.isBogus()) throw std::runtime_error{"default locale gives rise to bogus ICU locale"}; builder.setDefaultLocale(&default_icu_locale); auto ec = UErrorCode::U_ZERO_ERROR; auto matcher = builder.build(ec); if (U_FAILURE(ec)) throw std::runtime_error{"failed to build icu::LocaleMatcher"}; return matcher; } // Trimming optional whitespace as defined in RFC 9110, ยง 12.4.2. static auto ltrim_ows(std::string_view s) -> std::string_view; static auto rtrim_ows(std::string_view s) -> std::string_view; static auto trim_ows(std::string_view s) -> std::string_view; auto from_icu_locale(icu::Locale const& l) const -> std::locale; public: // Note: lgen must live at least as long as the selector constructed here! // It is unfortunately not possible to copy/move a blocale::generator. explicit selector( locale_input_range auto locales, std::locale default_, std::shared_ptr lgen) : default_{default_}, matcher_{make_matcher(locales, default_)}, lgen_{lgen} { } auto select(std::string_view accept_language) const -> std::locale; }; auto to_bcp47_lang_tag(std::locale locale) -> std::optional; export auto make_generator() -> std::shared_ptr; } // namespace routemon::locale