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 https://www.boost.org/LICENSE_1_0.txt)
4
5#pragma once
6
7#include "iso_15924.hpp"
8#include "iso_3166.hpp"
9#include "iso_639.hpp"
10#include "../hash.hpp"
11#include "../generator.hpp"
12#include "../ranges.hpp"
13#include <vector>
14#include <string_view>
15
16namespace hi::inline v1 {
17
26public:
28 iso_15924 script;
29 iso_3166 region;
30 uint16_t _reserved = 0;
31
32 constexpr language_tag() noexcept {}
33 constexpr language_tag(language_tag const&) noexcept = default;
34 constexpr language_tag(language_tag&&) noexcept = default;
35 constexpr language_tag& operator=(language_tag const&) noexcept = default;
36 constexpr language_tag& operator=(language_tag&&) noexcept = default;
37
38 constexpr language_tag(iso_639 const& language, iso_15924 const& script = {}, iso_3166 const& region = {}) noexcept :
39 language(language), script(script), region(region)
40 {
41 }
42
43 constexpr language_tag(iso_639 const& language, iso_3166 const& region) noexcept : language_tag(language, {}, region) {}
44
57 language_tag(std::string_view str);
58
63 [[nodiscard]] static language_tag parse(std::string_view str);
64
67 [[nodiscard]] bool empty() const noexcept
68 {
69 return language.empty() and script.empty() and region.empty();
70 }
71
74 explicit operator bool() const noexcept
75 {
76 return not empty();
77 }
78
86 [[nodiscard]] generator<language_tag> variants() const noexcept
87 {
88 co_yield *this;
89 if (script and region) {
90 co_yield language_tag{language, region};
91 co_yield language_tag{language, script};
92 }
93 if (script or region) {
94 co_yield language_tag{language};
95 }
96 }
97
106 [[nodiscard]] generator<language_tag> canonical_variants() const noexcept
107 {
108 hilet check = expand();
109 for (hilet& tag : variants()) {
110 if (tag.expand() == check) {
111 co_yield tag;
112 }
113 }
114 }
115
118 [[nodiscard]] std::vector<language_tag> all_variants() const noexcept
119 {
120 auto r = make_vector(variants());
121
122 // And languages variants from expanded variants.
123 for (hilet variant : variants()) {
124 for (hilet expanded_variant : variant.expand().variants()) {
125 if (std::find(r.begin(), r.end(), expanded_variant) == r.end()) {
126 r.push_back(expanded_variant);
127 }
128 }
129 }
130 return r;
131 }
132
137 [[nodiscard]] language_tag expand() const noexcept;
138
141 [[nodiscard]] language_tag shrink() const noexcept
142 {
143 auto last_variant = *this;
144 for (hilet& variant : canonical_variants()) {
145 last_variant = variant;
146 }
147 return last_variant;
148 }
149
154 [[nodiscard]] unicode_bidi_class writing_direction() const noexcept
155 {
156 return expand().script.writing_direction();
157 }
158
159 [[nodiscard]] std::string to_string() const noexcept
160 {
161 auto r = std::string{};
162 r += language.code();
163 if (script) {
164 r += '-';
165 r += script.code4();
166 }
167 if (region) {
168 r += "-";
169 r += region.code2();
170 }
171 return r;
172 }
173
176 [[nodiscard]] constexpr friend bool match(language_tag const& lhs, language_tag const& rhs) noexcept
177 {
178 if (lhs.language != rhs.language) {
179 return false;
180 }
181 if (lhs.script and rhs.script and lhs.script != rhs.script) {
182 return false;
183 }
184 if (lhs.region and rhs.region and lhs.region != rhs.region) {
185 return false;
186 }
187 return true;
188 }
189
190 [[nodiscard]] constexpr friend bool operator==(language_tag const&, language_tag const&) noexcept = default;
191};
192
202
203} // namespace hi::inline v1
204
205template<>
206struct std::hash<hi::language_tag> {
207 [[nodiscard]] size_t operator()(hi::language_tag const& rhs) const noexcept
208 {
209 return hi::hash_mix(
210 std::hash<hi::iso_639>{}(rhs.language),
211 std::hash<hi::iso_15924>{}(rhs.script),
212 std::hash<hi::iso_3166>{}(rhs.region));
213 }
214};
215
216template<typename CharT>
217struct std::formatter<hi::language_tag, CharT> : std::formatter<std::string_view, CharT> {
218 auto format(hi::language_tag const& t, auto& fc)
219 {
220 return std::formatter<std::string_view, CharT>::format(t.to_string(), fc);
221 }
222};
#define hilet
Invariant should be the default for variables.
Definition utility.hpp:23
DOXYGEN BUG.
Definition algorithm.hpp:15
constexpr std::vector< Value > make_vector(Range &&range)
Make a vector from a view.
Definition ranges.hpp:43
std::vector< language_tag > variants(std::vector< language_tag > languages)
Add variants to the list of languages.
unicode_bidi_class
Bidirectional class Unicode Standard Annex #9: https://unicode.org/reports/tr9/.
Definition unicode_bidi_class.hpp:17
The HikoGUI namespace.
Definition ascii.hpp:19
A return value for a generator-function.
Definition generator.hpp:28
ISO-15924 script code.
Definition iso_15924.hpp:19
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:140
Definition language.hpp:17
The IETF BCP 47 language tag.
Definition language_tag.hpp:25
unicode_bidi_class writing_direction() const noexcept
The language direction for this language-tag.
Definition language_tag.hpp:154
bool empty() const noexcept
Check if the language tag is empty.
Definition language_tag.hpp:67
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:106
generator< language_tag > variants() const noexcept
Get variants of the language_tag.
Definition language_tag.hpp:86
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:118
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:176
T find(T... args)
T operator()(T... args)