HikoGUI
A low latency retained GUI
Loading...
Searching...
No Matches
txt.hpp
1// Copyright Take Vos 2020-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 "translation.hpp"
8#include "../utility/utility.hpp"
9#include "../unicode/unicode.hpp"
10#include "../settings/settings.hpp"
11#include "../macros.hpp"
12#include <memory>
13#include <string>
14#include <string_view>
15#include <tuple>
16#include <algorithm>
17#include <utility>
18
19hi_export_module(hikogui.l10n.txt);
20
21hi_export namespace hi { inline namespace v1 {
22
23namespace detail {
24
26 virtual ~txt_arguments_base() = default;
27
28 [[nodiscard]] virtual std::unique_ptr<txt_arguments_base> make_unique_copy() const noexcept = 0;
29 [[nodiscard]] virtual std::string format(std::locale const &loc, std::string_view fmt) const noexcept = 0;
30 [[nodiscard]] virtual bool equal_to(txt_arguments_base const& rhs) const noexcept = 0;
31};
32
33template<typename... Types>
35 template<typename... Args>
36 constexpr txt_arguments(Args&&...args) : _args(std::forward<Args>(args)...)
37 {
38 }
39
40 [[nodiscard]] std::unique_ptr<txt_arguments_base> make_unique_copy() const noexcept override
41 {
42 return std::apply(
43 [](auto const&...args) {
44 return std::make_unique<txt_arguments>(args...);
45 },
46 _args);
47 }
48
49 [[nodiscard]] std::string format(std::locale const &loc, std::string_view fmt) const noexcept override
50 {
51 return std::apply(
52 [&](auto const&...args) {
53 return std::vformat(loc, fmt, std::make_format_args(args...));
54 },
55 _args);
56 }
57
58 [[nodiscard]] bool equal_to(txt_arguments_base const& rhs) const noexcept override
59 {
60 if (auto *rhs_ = dynamic_cast<txt_arguments const *>(std::addressof(rhs))) {
61 return _args == rhs_->_args;
62 } else {
63 return false;
64 }
65 }
66
67 std::tuple<Types...> _args;
68};
69
70template<typename... Args>
71constexpr std::unique_ptr<txt_arguments_base> make_unique_txt_arguments(Args&&...args) noexcept
72{
73 using txt_arguments_type = txt_arguments<std::decay_t<Args>...>;
74 return std::make_unique<txt_arguments_type>(std::forward<Args>(args)...);
75}
76
77} // namespace detail
78
79[[nodiscard]] constexpr long long get_first_integer_argument() noexcept
80{
81 return 0;
82}
83
84template<typename First, typename... Rest>
85[[nodiscard]] constexpr long long get_first_integer_argument(First const& first, Rest const&...rest) noexcept
86{
87 if constexpr (std::is_integral_v<First>) {
88 return narrow_cast<long long>(first);
89 } else {
90 return get_first_integer_argument(rest...);
91 }
92}
93
100hi_export class txt {
101public:
102 ~txt() = default;
103
104 constexpr txt() noexcept : _first_integer_argument(), _msg_id(), _args(detail::make_unique_txt_arguments()) {}
105
106 txt(txt const& other) noexcept :
107 _first_integer_argument(other._first_integer_argument), _msg_id(other._msg_id), _args(other._args->make_unique_copy())
108 {
109 }
110
111 txt(txt&& other) noexcept
112 {
113 std::swap(_first_integer_argument, other._first_integer_argument);
114 std::swap(_msg_id, other._msg_id);
115 std::swap(_args, other._args);
116 }
117
118 txt& operator=(txt const& other) noexcept
119 {
120 if (std::addressof(other) != this) {
121 _first_integer_argument = other._first_integer_argument;
122 _msg_id = other._msg_id;
123 _args = other._args->make_unique_copy();
124 }
125 return *this;
126 }
127
128 txt& operator=(txt&& other) noexcept
129 {
130 if (std::addressof(other) != this) {
131 std::swap(_first_integer_argument, other._first_integer_argument);
132 std::swap(_msg_id, other._msg_id);
133 std::swap(_args, other._args);
134 }
135 return *this;
136 }
137
150 template<typename... Args>
151 txt(std::string msg_id, Args&&...args) noexcept :
152 _first_integer_argument(get_first_integer_argument(args...)),
153 _msg_id(std::move(msg_id)),
154 _args(detail::make_unique_txt_arguments(std::forward<Args>(args)...))
155 {
156 }
157
158 [[nodiscard]] constexpr bool empty() const noexcept
159 {
160 return _msg_id.empty();
161 }
162
165 [[nodiscard]] constexpr explicit operator bool() const noexcept
166 {
167 return not empty();
168 }
169
170 [[nodiscard]] constexpr friend bool operator==(txt const& lhs, txt const& rhs) noexcept
171 {
172 hi_axiom_not_null(lhs._args);
173 hi_axiom_not_null(rhs._args);
174 return lhs._msg_id == rhs._msg_id and lhs._args->equal_to(*rhs._args);
175 }
176
184 [[nodiscard]] gstring translate(
185 std::locale const& loc = os_settings::locale(),
186 std::vector<language_tag> const& languages = os_settings::language_tags()) const noexcept
187 {
188 hi_axiom_not_null(_args);
189 auto const[fmt, language_tag] = ::hi::get_translation(_msg_id, _first_integer_argument, languages);
190 auto const msg = _args->format(loc, fmt);
191 return apply_markup(msg, language_tag);
192 }
193
200 [[nodiscard]] gstring translate(std::vector<language_tag> const& languages) const noexcept
201 {
202 return translate(os_settings::locale(), languages);
203 }
204
205 [[nodiscard]] gstring original() const noexcept
206 {
207 hi_axiom_not_null(_args);
208 auto const msg = _args->format(std::locale::classic(), _msg_id);
209 return apply_markup(msg, language_tag{"en-US"});
210 }
211
212 explicit operator std::string() const noexcept
213 {
214 return to_string(this->translate());
215 }
216
217private:
218 long long _first_integer_argument = 0;
219 std::string _msg_id = {};
221};
222
223}} // namespace hi::v1
224
225// XXX #617 MSVC bug does not handle partial specialization in modules.
226hi_export template<>
227struct std::formatter<hi::txt, char> : std::formatter<std::string, char> {
228 auto format(hi::txt const& t, auto& fc) const
229 {
230 return std::formatter<std::string, char>::format(std::string{t}, fc);
231 }
232};
@ other
The gui_event does not have associated data.
The HikoGUI namespace.
Definition array_generic.hpp:20
hi_export constexpr It apply_markup(It first, ItEnd last, language_tag default_language=language_tag{"en-US"}, phrasing default_phrasing=phrasing::regular) noexcept
Inplace-apply markup to a string of graphemes.
Definition markup.hpp:59
DOXYGEN BUG.
Definition algorithm_misc.hpp:20
The IETF BCP 47 language tag.
Definition language_tag_intf.hpp:30
Definition txt.hpp:34
A localizable message.
Definition txt.hpp:100
gstring translate(std::vector< language_tag > const &languages) const noexcept
Translate and format the message.
Definition txt.hpp:200
gstring translate(std::locale const &loc=os_settings::locale(), std::vector< language_tag > const &languages=os_settings::language_tags()) const noexcept
Translate and format the message.
Definition txt.hpp:184
txt(std::string msg_id, Args &&...args) noexcept
Construct a localizable message.
Definition txt.hpp:151
T addressof(T... args)
T classic(T... args)
T empty(T... args)
T move(T... args)
T swap(T... args)