Branch data Line data Source code
1 : : // Copyright (c) 2019-present The Bitcoin Core developers
2 : : // Distributed under the MIT software license, see the accompanying
3 : : // file COPYING or http://www.opensource.org/licenses/mit-license.php.
4 : :
5 : : #ifndef BITCOIN_UTIL_TRANSLATION_H
6 : : #define BITCOIN_UTIL_TRANSLATION_H
7 : :
8 : : #include <tinyformat.h>
9 : : #include <util/string.h>
10 : :
11 : : #include <cassert>
12 : : #include <functional>
13 : : #include <string>
14 : :
15 : : /** Translate a message to the native language of the user. */
16 : : using TranslateFn = std::function<std::string(const char*)>;
17 : : const extern TranslateFn G_TRANSLATION_FUN;
18 : :
19 : : /**
20 : : * Bilingual messages:
21 : : * - in GUI: user's native language + untranslated (i.e. English)
22 : : * - in log and stderr: untranslated only
23 : : */
24 [ + - + - : 389490 : struct bilingual_str {
+ - ][ + +
- - - - -
- ][ + - +
- + - + +
- - + - +
- ][ + + +
- + - #
# ][ + - -
- + - - -
- - + - +
- ][ + - -
- - - + +
- - + + #
# ][ + - +
- # # # #
# # # # ]
25 : : std::string original;
26 : : std::string translated;
27 : :
28 : 281 : bilingual_str& operator+=(const bilingual_str& rhs)
29 : : {
30 : 281 : original += rhs.original;
31 : 281 : translated += rhs.translated;
32 : 281 : return *this;
33 : : }
34 : :
35 : 16625 : bool empty() const
36 : : {
37 [ + + + + : 16625 : return original.empty();
+ + ]
[ + + + - ]
[ - + + +
- + ]
38 : : }
39 : :
40 : : void clear()
41 : : {
42 : : original.clear();
43 : : translated.clear();
44 : : }
45 : : };
46 : :
47 : 134 : inline bilingual_str operator+(bilingual_str lhs, const bilingual_str& rhs)
48 : : {
49 [ - - - - : 134 : lhs += rhs;
- - - - -
- - - - -
- - + - -
- + - + -
+ - - - -
- + - + -
+ - + - ]
[ + - + - ]
[ + - # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # ]
[ + - + -
+ - + - +
- ]
50 : 134 : return lhs;
51 : : }
52 : :
53 : : namespace util {
54 : : //! Compile-time literal string that can be translated with an optional translation function.
55 : : struct TranslatedLiteral {
56 : : const char* const original;
57 : : const TranslateFn* translate_fn;
58 : :
59 : : consteval TranslatedLiteral(const char* str, const TranslateFn* fn = &G_TRANSLATION_FUN) : original{str}, translate_fn{fn} { assert(original); }
60 [ + - + + ]: 17890 : operator std::string() const { return translate_fn && *translate_fn ? (*translate_fn)(original) : original; }
61 [ + - ]: 9445 : operator bilingual_str() const { return {original, std::string{*this}}; }
62 : : };
63 : :
64 : : // TranslatedLiteral operators for formatting and adding to strings.
65 [ + - ]: 1287 : inline std::ostream& operator<<(std::ostream& os, const TranslatedLiteral& lit) { return os << std::string{lit}; }
66 : : template<typename T>
67 [ + - ]: 70 : T operator+(const T& lhs, const TranslatedLiteral& rhs) { return lhs + static_cast<T>(rhs); }
68 : : template<typename T>
69 [ + - ]: 60 : T operator+(const TranslatedLiteral& lhs, const T& rhs) { return static_cast<T>(lhs) + rhs; }
70 : :
71 : : template <unsigned num_params>
72 : : struct BilingualFmt {
73 : : const ConstevalFormatString<num_params> original;
74 : : TranslatedLiteral lit;
75 : : consteval BilingualFmt(TranslatedLiteral l) : original{l.original}, lit{l} {}
76 : : };
77 : : } // namespace util
78 : :
79 : : consteval auto _(util::TranslatedLiteral str) { return str; }
80 : :
81 : : /** Mark a bilingual_str as untranslated */
82 [ + - ]: 160232 : inline bilingual_str Untranslated(std::string original) { return {original, original}; }
83 : :
84 : : // Provide an overload of tinyformat::format for BilingualFmt format strings and bilingual_str or TranslatedLiteral args.
85 : : namespace tinyformat {
86 : : template <typename... Args>
87 : 329 : bilingual_str format(util::BilingualFmt<sizeof...(Args)> fmt, const Args&... args)
88 : : {
89 : 3 : const auto original_arg{[](const auto& arg) -> const auto& {
90 : : if constexpr (std::is_same_v<decltype(arg), const bilingual_str&>) {
91 : 2 : return arg.original;
92 : : } else if constexpr (std::is_same_v<decltype(arg), const util::TranslatedLiteral&>) {
93 : 1 : return arg.original;
94 : : } else {
95 : : return arg;
96 : : }
97 : : }};
98 : 2 : const auto translated_arg{[](const auto& arg) -> const auto& {
99 : : if constexpr (std::is_same_v<decltype(arg), const bilingual_str&>) {
100 : 2 : return arg.translated;
101 : : } else {
102 : : return arg;
103 : : }
104 : : }};
105 : 329 : return bilingual_str{tfm::format(fmt.original, original_arg(args)...),
106 [ + - ]: 658 : tfm::format(RuntimeFormat{std::string{fmt.lit}}, translated_arg(args)...)};
[ + - + - ]
107 [ + - + - ]: 330 : }
108 : : } // namespace tinyformat
109 : :
110 : : #endif // BITCOIN_UTIL_TRANSLATION_H
|