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>; class bcp47_tag : public std::locale::facet { std::string tag_; public: static std::locale::id id; explicit bcp47_tag(std::locale locale); ~bcp47_tag() override = default; auto tag() const -> std::string_view; }; // Helps select a locale based on the Accept-Language header in an // HTTP request. export class selector { std::vector supported_; std::locale default_; icu::LocaleMatcher matcher_; static auto make_matcher(std::vector const& supported_locales) -> icu::LocaleMatcher; // 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; public: explicit selector(locale_input_range auto supported, std::locale default_) : supported_{ std::from_range, supported | std::views::transform( [](std::locale const& locale) -> std::locale { return std::locale{locale, new bcp47_tag{locale}}; }) }, default_{std::locale{default_, new bcp47_tag{default_}}}, matcher_{make_matcher(supported_)} { } auto select(std::string_view accept_language) const -> std::locale; }; export auto make_generator() -> std::shared_ptr; } // namespace routemon::locale