HikoGUI
A low latency retained GUI
Loading...
Searching...
No Matches
translate.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 "../forward_value.hpp"
9#include "../utility/module.hpp"
10#include "../os_settings.hpp"
11#include "../text/module.hpp"
12#include <memory>
13#include <string>
14#include <string_view>
15#include <tuple>
16
17namespace hi::inline v1 {
18namespace detail {
20public:
21 virtual ~translate_args_base() {}
22 translate_args_base() = default;
25 translate_args_base& operator=(translate_args_base const&) = default;
26 translate_args_base& operator=(translate_args_base&&) = default;
27
31 [[nodiscard]] virtual std::string format(std::string_view fmt) const noexcept = 0;
32
37 [[nodiscard]] virtual std::string format(std::locale const& loc, std::string_view fmt) const noexcept = 0;
38
42 [[nodiscard]] virtual long long n() const noexcept = 0;
43
46 [[nodiscard]] virtual std::unique_ptr<translate_args_base> unique_copy() const noexcept = 0;
47
48 [[nodiscard]] virtual bool equal_to(translate_args_base const& rhs) const noexcept = 0;
49
50 [[nodiscard]] bool friend operator==(translate_args_base const& lhs, translate_args_base const& rhs) noexcept
51 {
52 return lhs.equal_to(rhs);
53 }
54};
55
60template<typename... Values>
62public:
63 translate_args(translate_args&&) noexcept = default;
64 translate_args(translate_args const&) noexcept = default;
65 translate_args& operator=(translate_args&&) noexcept = default;
66 translate_args& operator=(translate_args const&) noexcept = default;
67
80 template<typename... Args>
81 translate_args(Args const&...args) noexcept : _values(args...)
82 {
83 }
84
85 [[nodiscard]] std::unique_ptr<translate_args_base> unique_copy() const noexcept override
86 {
87 return std::make_unique<translate_args>(*this);
88 }
89
90 [[nodiscard]] bool equal_to(translate_args_base const& rhs) const noexcept override
91 {
92 if (auto *rhs_ = dynamic_cast<translate_args const *>(&rhs)) {
93 return _values == rhs_->_values;
94 } else {
95 return false;
96 }
97 }
98
99 [[nodiscard]] std::string format(std::string_view fmt) const noexcept override
100 {
101 return std::apply(format_wrapper<Values const&...>, std::tuple_cat(std::tuple{fmt}, _values));
102 }
103
104 [[nodiscard]] std::string format(std::locale const& loc, std::string_view fmt) const noexcept override
105 {
106 return std::apply(format_locale_wrapper<Values const&...>, std::tuple_cat(std::tuple{loc, fmt}, _values));
107 }
108
109 template<std::size_t I>
110 [[nodiscard]] long long n_recurse() const noexcept
111 {
112 if constexpr (I < sizeof...(Values)) {
113 if constexpr (std::is_integral_v<decltype(std::get<I>(_values))>) {
114 return narrow_cast<long long>(std::get<I>(_values));
115 } else {
116 return n_recurse<I + 1>();
117 }
118 } else {
119 return 0;
120 }
121 }
122
123 [[nodiscard]] long long n() const noexcept override
124 {
125 return n_recurse<0>();
126 }
127
128private:
129 std::tuple<Values...> _values;
130
131 template<typename... Args>
132 static std::string format_wrapper(std::string_view fmt, Args const&...args)
133 {
134 return std::vformat(fmt, std::make_format_args(args...));
135 }
136
137 template<typename... Args>
138 static std::string format_locale_wrapper(std::locale const& loc, std::string_view fmt, Args const&...args)
139 {
140 return std::vformat(loc, fmt, std::make_format_args(args...));
141 }
142};
143
144template<typename... Args>
145translate_args(Args&&...) -> translate_args<forward_value_t<Args>...>;
146
147} // namespace detail
148
156public:
157 ~translate() = default;
158
161 constexpr translate() noexcept : _msg_id(), _args(nullptr), _has_args(false) {}
162
163 constexpr translate(translate&& other) noexcept :
164 _msg_id(std::move(other._msg_id)), _args(nullptr), _has_args(other._has_args)
165 {
166 if (_has_args) {
167 _args = std::move(other._args);
168 }
169 }
170
171 constexpr translate& operator=(translate&& other) noexcept
172 {
173 _msg_id = std::move(other._msg_id);
174 _has_args = other._has_args;
175 if (_has_args) {
176 _args = std::move(other._args);
177 }
178 return *this;
179 }
180
181 constexpr translate(translate const& other) noexcept : _msg_id(other._msg_id), _args(nullptr), _has_args(other._has_args)
182 {
183 if (_has_args) {
184 _args = other._args->unique_copy();
185 }
186 }
187
188 constexpr translate& operator=(translate const& other) noexcept
189 {
190 _msg_id = other._msg_id;
191 _has_args = other._has_args;
192 if (_has_args) {
193 _args = other._args->unique_copy();
194 }
195 return *this;
196 }
197
198 [[nodiscard]] constexpr bool empty() const noexcept
199 {
200 return _msg_id.empty();
201 }
202
205 [[nodiscard]] constexpr explicit operator bool() const noexcept
206 {
207 return not empty();
208 }
209
220 constexpr translate(std::string_view msg_id) noexcept : _msg_id(msg_id), _args(nullptr), _has_args(false) {}
221
234 template<typename FirstArg, typename... Args>
235 translate(std::string_view msg_id, FirstArg const& first_arg, Args const&...args) noexcept :
236 _msg_id(msg_id),
237 _args(std::make_unique<detail::translate_args<forward_value_t<FirstArg>, forward_value_t<Args>...>>(first_arg, args...)),
238 _has_args(true)
239 {
240 }
241
248 [[nodiscard]] text operator()(std::vector<language_tag> const& languages = os_settings::language_tags()) const noexcept
249 {
250 if (_has_args) {
251 hilet[fmt, language_tag] = ::hi::get_translation(_msg_id, _args->n(), languages);
252 hilet msg = _args->format(fmt);
253 hilet default_attributes = character_attributes{language_tag.expand()};
254 return to_text_with_markup(msg, default_attributes);
255
256 } else {
257 hilet[msg, language_tag] = ::hi::get_translation(_msg_id, 0, languages);
258 hilet default_attributes = character_attributes{language_tag.expand()};
259 return to_text_with_markup(msg, default_attributes);
260 }
261 }
262
270 [[nodiscard]] text
271 operator()(std::locale const& loc, std::vector<language_tag> const& languages = os_settings::language_tags()) const noexcept
272 {
273 if (_has_args) {
274 hilet[fmt, language_tag] = ::hi::get_translation(_msg_id, _args->n(), languages);
275 hilet msg = _args->format(loc, fmt);
276 hilet default_attributes = character_attributes{language_tag.expand()};
277 return to_text_with_markup(msg, default_attributes);
278
279 } else {
280 hilet[msg, language_tag] = ::hi::get_translation(_msg_id, 0, languages);
281 hilet default_attributes = character_attributes{language_tag.expand()};
282 return to_text_with_markup(msg, default_attributes);
283 }
284 }
285
292 [[nodiscard]] constexpr friend bool operator==(translate const& lhs, translate const& rhs) noexcept
293 {
294 if (lhs._has_args != rhs._has_args) {
295 return false;
296 }
297
298 if (lhs._has_args and *lhs._args != *rhs._args) {
299 return false;
300 }
301
302 return lhs._msg_id == rhs._msg_id;
303 }
304
305private:
306 std::string _msg_id;
308 // Technically we could check _args for nullptr. However to get this working
309 // with constexpr constructor we need a way to disable the std::unique_ptr.
310 bool _has_args;
311};
312
313using tr = translate;
314
315} // namespace hi::inline v1
#define hilet
Invariant should be the default for variables.
Definition utility.hpp:23
@ other
The gui_event does not have associated data.
STL namespace.
DOXYGEN BUG.
Definition algorithm.hpp:13
typename forward_value< T >::type forward_value_t
Get the storage type of the forward_value functor.
Definition forward_value.hpp:83
The IETF BCP 47 language tag.
Definition language_tag.hpp:25
language_tag expand() const noexcept
Expand the language tag to include script and language.
Definition translate.hpp:19
virtual std::string format(std::string_view fmt) const noexcept=0
Format text from the arguments and the given format string.
virtual long long n() const noexcept=0
The numeric value of the first numeric argument.
virtual std::string format(std::locale const &loc, std::string_view fmt) const noexcept=0
Format text from the arguments and the given format string.
Delayed formatting.
Definition translate.hpp:61
std::unique_ptr< translate_args_base > unique_copy() const noexcept override
Make a unique copy of the arguments.
Definition translate.hpp:85
long long n() const noexcept override
The numeric value of the first numeric argument.
Definition translate.hpp:123
std::string format(std::string_view fmt) const noexcept override
Format text from the arguments and the given format string.
Definition translate.hpp:99
std::string format(std::locale const &loc, std::string_view fmt) const noexcept override
Format text from the arguments and the given format string.
Definition translate.hpp:104
translate_args(Args const &...args) noexcept
Construct a translate arguments.
Definition translate.hpp:81
A localizable message.
Definition translate.hpp:155
constexpr friend bool operator==(translate const &lhs, translate const &rhs) noexcept
Compare two localizable messages.
Definition translate.hpp:292
translate(std::string_view msg_id, FirstArg const &first_arg, Args const &...args) noexcept
Construct a localizable message.
Definition translate.hpp:235
text operator()(std::vector< language_tag > const &languages=os_settings::language_tags()) const noexcept
Translate and format the message.
Definition translate.hpp:248
constexpr translate(std::string_view msg_id) noexcept
Construct a localizable message.
Definition translate.hpp:220
constexpr translate() noexcept
Construct an empty message.
Definition translate.hpp:161
text operator()(std::locale const &loc, std::vector< language_tag > const &languages=os_settings::language_tags()) const noexcept
Translate and format the message.
Definition translate.hpp:271
T move(T... args)
T tuple_cat(T... args)