HikoGUI
A low latency retained GUI
Loading...
Searching...
No Matches
l10n.hpp
1// Copyright Take Vos 2020.
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 "text/language.hpp"
8#include "text/translation.hpp"
9#include "forward_value.hpp"
10#include "cast.hpp"
11#include <memory>
12#include <string>
13#include <string_view>
14#include <tuple>
15
16namespace tt {
17namespace detail {
19public:
20 virtual ~l10n_args_base() {}
21
25 [[nodiscard]] virtual std::string format(std::string_view fmt) const noexcept = 0;
26
31 [[nodiscard]] virtual std::string format(std::locale const &loc, std::string_view fmt) const noexcept = 0;
32
36 [[nodiscard]] virtual long long n() const noexcept = 0;
37
40 [[nodiscard]] virtual std::unique_ptr<l10n_args_base> unique_copy() const noexcept = 0;
41
42 [[nodiscard]] virtual bool equal_to(l10n_args_base const &rhs) const noexcept = 0;
43
44 [[nodiscard]] bool friend operator==(l10n_args_base const &lhs, l10n_args_base const &rhs) noexcept
45 {
46 return lhs.equal_to(rhs);
47 }
48};
49
54template<typename... Values>
55class l10n_args : public l10n_args_base {
56public:
57 l10n_args(l10n_args &&) noexcept = default;
58 l10n_args(l10n_args const &) noexcept = default;
59 l10n_args &operator=(l10n_args &&) noexcept = default;
60 l10n_args &operator=(l10n_args const &) noexcept = default;
61
74 template<typename... Args>
75 l10n_args(Args const &...args) noexcept : _values(args...)
76 {
77 }
78
79 [[nodiscard]] std::unique_ptr<l10n_args_base> unique_copy() const noexcept
80 {
81 return std::make_unique<l10n_args>(*this);
82 }
83
84 [[nodiscard]] virtual bool equal_to(l10n_args_base const &rhs) const noexcept
85 {
86 if (auto *rhs_ = dynamic_cast<l10n_args const *>(&rhs)) {
87 return _values == rhs_->_values;
88 } else {
89 return false;
90 }
91 }
92
93 [[nodiscard]] std::string format(std::string_view fmt) const noexcept override
94 {
95 return std::apply(format_wrapper<Values const &...>, std::tuple_cat(std::tuple{fmt}, _values));
96 }
97
98 [[nodiscard]] std::string format(std::locale const &loc, std::string_view fmt) const noexcept override
99 {
100 return std::apply(format_locale_wrapper<Values const &...>, std::tuple_cat(std::tuple{loc, fmt}, _values));
101 }
102
103 template<size_t I>
104 [[nodiscard]] long long n_recurse() const noexcept
105 {
106 if constexpr (I < sizeof...(Values)) {
107 if constexpr (std::is_integral_v<decltype(std::get<I>(_values))>) {
108 return narrow_cast<long long>(std::get<I>(_values));
109 } else {
110 return n_recurse<I + 1>();
111 }
112 } else {
113 return 0;
114 }
115 }
116
117 [[nodiscard]] long long n() const noexcept override
118 {
119 return n_recurse<0>();
120 }
121
122private:
123 std::tuple<Values...> _values;
124
125 template<typename... Args>
126 static std::string format_wrapper(std::string_view fmt, Args const &...args)
127 {
128 return std::format(fmt, args...);
129 }
130
131 template<typename... Args>
132 static std::string format_locale_wrapper(std::locale const &loc, std::string_view fmt, Args const &...args)
133 {
134 return std::format(loc, fmt, args...);
135 }
136};
137
138template<typename... Args>
139l10n_args(Args &&...) -> l10n_args<forward_value_t<Args>...>;
140
141} // namespace detail
142
149class l10n {
150public:
153 constexpr l10n() noexcept : _msg_id(), _args(nullptr) {}
154
155 l10n(l10n &&) noexcept = default;
156 l10n &operator=(l10n &&) noexcept = default;
157
158 l10n(l10n const &other) noexcept : _msg_id(other._msg_id), _args(other._args ? other._args->unique_copy() : nullptr) {}
159
160 l10n &operator=(l10n const &other) noexcept
161 {
162 _msg_id = other._msg_id;
163 _args = other._args ? other._args->unique_copy() : nullptr;
164 return *this;
165 }
166
169 [[nodiscard]] explicit operator bool() const noexcept
170 {
171 return not _msg_id.empty();
172 }
173
187 template<typename... Args>
188 l10n(std::string_view msg_id, Args const &...args) noexcept :
189 _msg_id(msg_id), _args(sizeof...(Args) ? std::make_unique<detail::l10n_args<forward_value_t<Args>...>>(args...) : nullptr)
190 {
191 }
192
199 [[nodiscard]] std::string
200 operator()(std::vector<language *> const &languages = language::preferred_languages()) const noexcept
201 {
202 if (_args) {
203 auto fmt = ::tt::get_translation(_msg_id, _args->n(), languages);
204 return _args->format(fmt);
205 } else {
206 return std::string{::tt::get_translation(_msg_id, 0, languages)};
207 }
208 }
209
217 [[nodiscard]] std::string
218 operator()(std::locale const &loc, std::vector<language *> const &languages = language::preferred_languages()) const noexcept
219 {
220 if (_args) {
221 auto fmt = ::tt::get_translation(_msg_id, _args->n(), languages);
222 return _args->format(loc, fmt);
223 } else {
224 return std::string{::tt::get_translation(_msg_id, 0, languages)};
225 }
226 }
227
234 [[nodiscard]] friend bool operator==(l10n const &lhs, l10n const &rhs) noexcept
235 {
236 if (lhs._args == rhs._args) {
237 return lhs._msg_id == rhs._msg_id;
238 } else if (lhs._args and rhs._args) {
239 return lhs._msg_id == rhs._msg_id and *lhs._args == *rhs._args;
240 } else {
241 return false;
242 }
243 }
244
245private:
246 std::string _msg_id;
248};
249
250} // namespace tt
STL namespace.
Definition l10n.hpp:18
virtual std::string format(std::string_view fmt) const noexcept=0
Format text from the arguments and the given format string.
virtual std::unique_ptr< l10n_args_base > unique_copy() const noexcept=0
Make a unique copy of the arguments.
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.
virtual long long n() const noexcept=0
The numeric value of the first numeric argument.
Delayed formatting.
Definition l10n.hpp:55
l10n_args(Args const &...args) noexcept
Construct a l10n arguments.
Definition l10n.hpp:75
std::unique_ptr< l10n_args_base > unique_copy() const noexcept
Make a unique copy of the arguments.
Definition l10n.hpp:79
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 l10n.hpp:98
long long n() const noexcept override
The numeric value of the first numeric argument.
Definition l10n.hpp:117
std::string format(std::string_view fmt) const noexcept override
Format text from the arguments and the given format string.
Definition l10n.hpp:93
A localizable message.
Definition l10n.hpp:149
friend bool operator==(l10n const &lhs, l10n const &rhs) noexcept
Compare two localizable messages.
Definition l10n.hpp:234
constexpr l10n() noexcept
Construct an empty message.
Definition l10n.hpp:153
std::string operator()(std::locale const &loc, std::vector< language * > const &languages=language::preferred_languages()) const noexcept
Translate and format the message.
Definition l10n.hpp:218
std::string operator()(std::vector< language * > const &languages=language::preferred_languages()) const noexcept
Translate and format the message.
Definition l10n.hpp:200
l10n(std::string_view msg_id, Args const &...args) noexcept
Construct a localizable message.
Definition l10n.hpp:188
T empty(T... args)
T tuple_cat(T... args)