Files
ObsidianDragon/src/util/i18n.h
T
DanSandClaude Opus 4.8 9db73323b6 feat(ui): friendly RPC errors + pause-on-hover/ellipsis toasts
Two of the systemic error-surfacing foundations from the UX audit:

- util::friendlyRpcError() maps the common raw daemon/JSON-RPC errors
  (warming up / -28, locked / -13, method-not-found / -32601, insufficient
  funds, unreachable node) to short translated guidance with a next step,
  falling back to the trimmed raw text. Wired into the send (money) path: the
  toast shows the friendly cause, the overlay keeps the raw text below it for
  diagnostics. The helper is reusable for the remaining raw-error sites.
- Toasts now pause their auto-dismiss while hovered and ellipsize over-long
  text with the full message in a hover tooltip, instead of hard-clipping it
  mid-word (durations were already lengthened earlier).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-10-17 16:53:37 -05:00

97 lines
3.0 KiB
C++

// DragonX Wallet - ImGui Edition
// Copyright 2024-2026 The Hush Developers
// Released under the GPLv3
#pragma once
#include <string>
#include <unordered_map>
#include <vector>
#include <nlohmann/json_fwd.hpp>
namespace dragonx {
namespace util {
/**
* @brief Internationalization support
*
* Simple string table implementation for translating UI text.
* Strings are stored in JSON files in res/lang/ directory.
*/
class I18n {
public:
/**
* @brief Get the singleton instance
*/
static I18n& instance();
/**
* @brief Load a language file
* @param locale Language code (e.g., "en", "es", "zh")
* @return true if loaded successfully
*/
bool loadLanguage(const std::string& locale);
/**
* @brief Translate a string
* @param key The string key (usually English text)
* @return Translated string, or key if not found
*/
const char* translate(const char* key) const;
/**
* @brief Get current locale
*/
const std::string& getCurrentLocale() const { return current_locale_; }
/**
* @brief Get list of available languages
*/
const std::vector<std::pair<std::string, std::string>>& getAvailableLanguages() const { return available_languages_; }
/**
* @brief Register an available language
* @param code Language code (e.g., "en")
* @param name Display name (e.g., "English")
*/
void registerLanguage(const std::string& code, const std::string& name);
private:
I18n();
void loadBuiltinEnglish();
// Overlay translated strings onto the English base, but reject any value whose printf
// format-specifier signature differs from the English source (keep English instead).
// Many strings are used directly as printf/ImGui format strings, so a mismatched
// translation (dropped/changed specifier) is undefined behavior — this prevents it.
void overlayTranslations(const nlohmann::json& translations);
std::string current_locale_ = "en";
std::unordered_map<std::string, std::string> strings_;
std::vector<std::pair<std::string, std::string>> available_languages_;
};
/**
* @brief Convenience function for translation
* @param key The string key
* @return Translated string
*/
inline const char* tr(const char* key) {
return I18n::instance().translate(key);
}
/**
* @brief Map a raw daemon / JSON-RPC error string to a short, friendly, TRANSLATED explanation.
*
* Recognizes the common cases a user actually hits — a warming-up node, a locked wallet, an RPC the
* daemon is too old to have, insufficient funds, and an unreachable node — and returns plain guidance
* with a next step. Falls back to the raw text (trimmed) when nothing matches, so detail is never lost.
* Keep the raw text available elsewhere (a Details view / the console) for diagnostics.
*/
std::string friendlyRpcError(const std::string& raw);
} // namespace util
} // namespace dragonx
// Convenience macro for translations
#define TR(key) dragonx::util::tr(key)