HikoGUI
A low latency retained GUI
Loading...
Searching...
No Matches
language_tag.hpp
1// Copyright Take Vos 2022.
2// Distributed under the Boost Software License, Version 1.0.
3// (See accompanying file LICENSE_1_0.txt or copy at
4// https://www.boost.org/LICENSE_1_0.txt)
5
6#pragma once
7
8#include "iso_15924.hpp"
9#include "iso_3166.hpp"
10#include "iso_639.hpp"
11#include "../hash.hpp"
12#include "../generator.hpp"
13#include "../ranges.hpp"
14#include <vector>
15#include <string_view>
16
17namespace hi::inline v1 {
18
27public:
29 iso_15924 script;
30 iso_3166 region;
31 uint16_t _reserved = 0;
32
33 constexpr language_tag() noexcept {}
34 constexpr language_tag(language_tag const&) noexcept = default;
35 constexpr language_tag(language_tag&&) noexcept = default;
36 constexpr language_tag& operator=(language_tag const&) noexcept = default;
37 constexpr language_tag& operator=(language_tag&&) noexcept = default;
38
39 constexpr language_tag(iso_639 const& language, iso_15924 const& script = {}, iso_3166 const& region = {}) noexcept :
40 language(language), script(script), region(region)
41 {
42 }
43
44 constexpr language_tag(iso_639 const& language, iso_3166 const& region) noexcept : language_tag(language, {}, region) {}
45
58 language_tag(std::string_view str);
59
64 [[nodiscard]] static language_tag parse(std::string_view str);
65
68 [[nodiscard]] bool empty() const noexcept
69 {
70 return language.empty() and script.empty() and region.empty();
71 }
72
75 explicit operator bool() const noexcept
76 {
77 return not empty();
78 }
79
87 [[nodiscard]] generator<language_tag> variants() const noexcept
88 {
89 co_yield *this;
90 if (script and region) {
91 co_yield language_tag{language, region};
92 co_yield language_tag{language, script};
93 }
94 if (script or region) {
95 co_yield language_tag{language};
96 }
97 }
98
107 [[nodiscard]] generator<language_tag> canonical_variants() const noexcept
108 {
109 auto check = expand();
110 for (hilet& tag : variants()) {
111 if (tag.expand() == check) {
112 co_yield tag;
113 }
114 }
115 }
116
119 [[nodiscard]] std::vector<language_tag> all_variants() const noexcept
120 {
121 auto r = make_vector(variants());
122
123 // And languages variants from expanded variants.
124 for (hilet variant : variants()) {
125 for (hilet expanded_variant : variant.expand().variants()) {
126 if (std::find(r.begin(), r.end(), expanded_variant) == r.end()) {
127 r.push_back(expanded_variant);
128 }
129 }
130 }
131 return r;
132 }
133
138 [[nodiscard]] language_tag expand() const noexcept;
139
142 [[nodiscard]] language_tag shrink() const noexcept
143 {
144 auto last_variant = *this;
145 for (hilet& variant : canonical_variants()) {
146 last_variant = variant;
147 }
148 return last_variant;
149 }
150
151 [[nodiscard]] std::string to_string() const noexcept
152 {
153 auto r = std::string{};
154 r += language.code();
155 if (script) {
156 r += '-';
157 r += script.code4();
158 }
159 if (region) {
160 r += "-";
161 r += region.code2();
162 }
163 return r;
164 }
165
168 [[nodiscard]] constexpr friend bool match(language_tag const& lhs, language_tag const& rhs) noexcept
169 {
170 if (lhs.language != rhs.language) {
171 return false;
172 }
173 if (lhs.script and rhs.script and lhs.script != rhs.script) {
174 return false;
175 }
176 if (lhs.region and rhs.region and lhs.region != rhs.region) {
177 return false;
178 }
179 return true;
180 }
181
182 [[nodiscard]] constexpr friend bool operator==(language_tag const&, language_tag const&) noexcept = default;
183};
184
193[[nodiscard]] std::vector<language_tag> variants(std::vector<language_tag> languages);
194
195} // namespace hi::inline v1
196
197template<>
198struct std::hash<hi::language_tag> {
199 [[nodiscard]] size_t operator()(hi::language_tag const& rhs) const noexcept
200 {
201 return hi::hash_mix(
202 std::hash<hi::iso_639>{}(rhs.language),
203 std::hash<hi::iso_15924>{}(rhs.script),
204 std::hash<hi::iso_3166>{}(rhs.region));
205 }
206};
207
208template<typename CharT>
209struct std::formatter<hi::language_tag, CharT> : std::formatter<std::string_view, CharT> {
210 auto format(hi::language_tag const& t, auto& fc)
211 {
212 return std::formatter<std::string_view, CharT>::format(t.to_string(), fc);
213 }
214};
#define hilet
Invariant should be the default for variables.
Definition required.hpp:23
A return value for a generator-function.
Definition generator.hpp:27
ISO-15924 script code.
Definition iso_15924.hpp:18
std::string_view code4() const noexcept
Get the iso-15924 4-letter code.
ISO-3166 country code.
Definition iso_3166.hpp:16
ISO-639 language code.
Definition iso_639.hpp:25
constexpr std::string code() const noexcept
Get the 2 or 3 letter ISO-639 code.
Definition iso_639.hpp:92
Definition language.hpp:18
The IETF BCP 47 language tag.
Definition language_tag.hpp:26
bool empty() const noexcept
Check if the language tag is empty.
Definition language_tag.hpp:68
language_tag(std::string_view str)
Parse a language tag.
language_tag expand() const noexcept
Expand the language tag to include script and language.
generator< language_tag > canonical_variants() const noexcept
Get variants of the language_tag.
Definition language_tag.hpp:107
generator< language_tag > variants() const noexcept
Get variants of the language_tag.
Definition language_tag.hpp:87
std::vector< language_tag > all_variants() const noexcept
Creates variants of a language tag, including those by expanding the normal variants.
Definition language_tag.hpp:119
static language_tag parse(std::string_view str)
Parse the language, script and region raw from the string.
constexpr friend bool match(language_tag const &lhs, language_tag const &rhs) noexcept
Check if two language_tags match for their non-empty fields.
Definition language_tag.hpp:168
T find(T... args)
T operator()(T... args)