Also (not sure about this, but) it might be nice to add an explicit conversion method to Original class, so we could write something like _("Error opening block database").str() instead of bilingual_str{_("Error opening block database")}
Sure, I am happy to add bilingual_str str() and operator bilingual_str() to the Original type and remove the constructors from bilingual_str. However, this means that calling bilingual_str{Original{}} is now forbidden and one would have to use () over {}, or call the .str() method.
Let me know if this is fine and I should go ahead and push this diff:
  0diff --git a/src/init.cpp b/src/init.cpp
  1index fb2028281a..c849f83b05 100644
  2--- a/src/init.cpp
  3+++ b/src/init.cpp
  4@@ -1261,7 +1261,7 @@ static ChainstateLoadResult InitAndLoadChainstate(
  5             return f();
  6         } catch (const std::exception& e) {
  7             LogError("%s\n", e.what());
  8-            return std::make_tuple(node::ChainstateLoadStatus::FAILURE, bilingual_str{_("Error opening block database")});
  9+            return std::make_tuple(node::ChainstateLoadStatus::FAILURE, _("Error opening block database").str());
 10         }
 11     };
 12     auto [status, error] = catch_exceptions([&] { return LoadChainstate(chainman, cache_sizes, options); });
 13diff --git a/src/test/result_tests.cpp b/src/test/result_tests.cpp
 14index 45337c6801..c829d56faa 100644
 15--- a/src/test/result_tests.cpp
 16+++ b/src/test/result_tests.cpp
 17@@ -63,7 +63,7 @@ void ExpectSuccess(const util::Result<T>& result, const bilingual_str& str, Args
 18 {
 19     ExpectResult(result, true, str);
 20     BOOST_CHECK_EQUAL(result.has_value(), true);
 21-    BOOST_CHECK_EQUAL(result.value(), T{std::forward<Args>(args)...});
 22+    BOOST_CHECK_EQUAL(result.value(), T(std::forward<Args>(args)...));
 23     BOOST_CHECK_EQUAL(&result.value(), &*result);
 24 }
 25 
 26@@ -89,8 +89,8 @@ BOOST_AUTO_TEST_CASE(check_value_or)
 27     BOOST_CHECK_EQUAL(IntFn(10, false).value_or(20), 20);
 28     BOOST_CHECK_EQUAL(NoCopyFn(10, true).value_or(20), 10);
 29     BOOST_CHECK_EQUAL(NoCopyFn(10, false).value_or(20), 20);
 30-    BOOST_CHECK_EQUAL(StrFn(Untranslated("A"), true).value_or(Untranslated("B")), bilingual_str{Untranslated("A")});
 31-    BOOST_CHECK_EQUAL(StrFn(Untranslated("A"), false).value_or(Untranslated("B")), bilingual_str{Untranslated("B")});
 32+    BOOST_CHECK_EQUAL(StrFn(Untranslated("A"), true).value_or(Untranslated("B")), Untranslated("A").str());
 33+    BOOST_CHECK_EQUAL(StrFn(Untranslated("A"), false).value_or(Untranslated("B")), Untranslated("B").str());
 34 }
 35 
 36 BOOST_AUTO_TEST_SUITE_END()
 37diff --git a/src/util/translation.h b/src/util/translation.h
 38index 08df892733..a06f7b982f 100644
 39--- a/src/util/translation.h
 40+++ b/src/util/translation.h
 41@@ -14,24 +14,6 @@
 42 /** Translate a message to the native language of the user. */
 43 const extern std::function<std::string(const char*)> G_TRANSLATION_FUN;
 44 
 45-namespace util {
 46-/**
 47- * Translation function.
 48- * If no translation function is set, simply return the input.
 49- */
 50-inline std::string translate(const char* lit)
 51-{
 52-    return G_TRANSLATION_FUN ? G_TRANSLATION_FUN(lit) : lit;
 53-}
 54-/** Type to denote whether an orginal string literal is translatable */
 55-template <bool translatable = true>
 56-struct Original {
 57-    const char* const lit;
 58-    consteval Original(const char* str) : lit{str} { assert(lit); }
 59-    std::string translate() const { return translatable ? util::translate(lit) : lit; }
 60-};
 61-} // namespace util
 62-
 63 /**
 64  * Bilingual messages:
 65  *   - in GUI: user's native language + untranslated (i.e. English)
 66@@ -41,13 +23,6 @@ struct bilingual_str {
 67     std::string original;
 68     std::string translated;
 69 
 70-    bilingual_str() = default;
 71-    bilingual_str(std::string original, std::string translated) : original{original}, translated{translated} {}
 72-    template <bool translatable>
 73-    bilingual_str(util::Original<translatable> original) : original{original.lit}, translated{original.translate()}
 74-    {
 75-    }
 76-
 77     bilingual_str& operator+=(const bilingual_str& rhs)
 78     {
 79         original += rhs.original;
 80@@ -73,6 +48,26 @@ inline bilingual_str operator+(bilingual_str lhs, const bilingual_str& rhs)
 81     return lhs;
 82 }
 83 
 84+namespace util {
 85+/**
 86+ * Translation function.
 87+ * If no translation function is set, simply return the input.
 88+ */
 89+inline std::string translate(const char* lit)
 90+{
 91+    return G_TRANSLATION_FUN ? G_TRANSLATION_FUN(lit) : lit;
 92+}
 93+/** Type to denote whether an orginal string literal is translatable */
 94+template <bool translatable = true>
 95+struct Original {
 96+    const char* const lit;
 97+    consteval Original(const char* str) : lit{str} { assert(lit); }
 98+    std::string translate() const { return translatable ? util::translate(lit) : lit; }
 99+    bilingual_str str() const { return {lit, translate()}; }
100+    operator bilingual_str() const { return str(); }
101+};
102+} // namespace util
103+
104 consteval auto _(util::Original<true> str) { return str; }
105 
106 /** Mark a bilingual_str as untranslated */