Repository: bitcoin/bitcoin
File: src/util/translation.h (C/C++)

Code before:
    consteval TranslatedLiteral(const char* str, const TranslateFn* fn = &G_TRANSLATION_FUN) : original{str}, translate_fn{fn} { assert(original); }
    operator std::string() const { return translate_fn && *translate_fn ? (*translate_fn)(original) : original; }
    operator bilingual_str() const { return {original, std::string{*this}}; }
};

// TranslatedLiteral operators for formatting and adding to strings.
inline std::ostream& operator<<(std::ostream& os, const TranslatedLiteral& lit) { return os << std::string{lit}; }
template<typename T>
T operator+(const T& lhs, const TranslatedLiteral& rhs) { return lhs + static_cast<T>(rhs); }
template<typename T>
T operator+(const TranslatedLiteral& lhs, const T& rhs) { return static_cast<T>(lhs) + rhs; }

template <unsigned num_params>
struct BilingualFmt {
    const ConstevalFormatString<num_params> original;
    TranslatedLiteral lit;
    consteval BilingualFmt(TranslatedLiteral l) : original{l.original}, lit{l} {}
};
} // namespace util

consteval auto _(util::TranslatedLiteral str) { return str; }

/** Mark a bilingual_str as untranslated */
inline bilingual_str Untranslated(std::string original) { return {original, original}; }
template <std::size_t N>
inline bilingual_str Untranslated(const char (&original)[N]) { return Untranslated(std::string{original}); }


// Provide an overload of tinyformat::format for BilingualFmt format strings and bilingual_str or TranslatedLiteral args.
namespace tinyformat {
template <typename... Args>
bilingual_str format(util::BilingualFmt<sizeof...(Args)> fmt, const Args&... args)
{
    const auto original_arg{[](const auto& arg) -> const auto& {
        if constexpr (std::is_same_v<decltype(arg), const bilingual_str&>) {
            return arg.original;
        } else if constexpr (std::is_same_v<decltype(arg), const util::TranslatedLiteral&>) {
            return arg.original;
        } else {
            return arg;
        }
    }};
    const auto translated_arg{[](const auto& arg) -> const auto& {
        if constexpr (std::is_same_v<decltype(arg), const bilingual_str&>) {
            return arg.translated;
        } else {
            return arg;
        }
    }};
    return bilingual_str{tfm::format(fmt.original, original_arg(args)...),
                         tfm::format(RuntimeFormat{std::string{fmt.lit}}, translated_arg(args)...)};

Review comment (suggestion):
not sure about this. I don't think we should be adding c++ code as an rough alternative to IWYU pragma export. Also, I am starting to think we should get rid of the pragma export to reduce the list of includes, because it doesn't interact well with letting iwyu minimize the include list.

Code after:
    consteval TranslatedLiteral(const char* str, const TranslateFn* fn = &G_TRANSLATION_FUN) : original{str}, translate_fn{fn} { assert(original); }
    operator std::string() const { return translate_fn && *translate_fn ? (*translate_fn)(original) : original; }
    operator bilingual_str() const { return {original, std::string{*this}}; }
};

// TranslatedLiteral operators for formatting and adding to strings.
inline std::ostream& operator<<(std::ostream& os, const TranslatedLiteral& lit) { return os << std::string{lit}; }
template<typename T>
T operator+(const T& lhs, const TranslatedLiteral& rhs) { return lhs + static_cast<T>(rhs); }
template<typename T>
T operator+(const TranslatedLiteral& lhs, const T& rhs) { return static_cast<T>(lhs) + rhs; }

template <unsigned num_params>
struct BilingualFmt {
    const ConstevalFormatString<num_params> original;
    TranslatedLiteral lit;
    consteval BilingualFmt(TranslatedLiteral l) : original{l.original}, lit{l} {}
};
} // namespace util

consteval auto _(util::TranslatedLiteral str) { return str; }

/** Mark a bilingual_str as untranslated */
inline bilingual_str Untranslated(std::string original) { return {original, original}; }

// Provide an overload of tinyformat::format for BilingualFmt format strings and bilingual_str or TranslatedLiteral args.
namespace tinyformat {
template <typename... Args>
bilingual_str format(util::BilingualFmt<sizeof...(Args)> fmt, const Args&... args)
{
    const auto original_arg{[](const auto& arg) -> const auto& {
        if constexpr (std::is_same_v<decltype(arg), const bilingual_str&>) {
            return arg.original;
        } else if constexpr (std::is_same_v<decltype(arg), const util::TranslatedLiteral&>) {
            return arg.original;
        } else {
            return arg;
        }
    }};
    const auto translated_arg{[](const auto& arg) -> const auto& {
        if constexpr (std::is_same_v<decltype(arg), const bilingual_str&>) {
            return arg.translated;
        } else {
            return arg;
        }
    }};
    return bilingual_str{tfm::format(fmt.original, original_arg(args)...),
                         tfm::format(RuntimeFormat{std::string{fmt.lit}}, translated_arg(args)...)};
}
} // namespace tinyformat