Merge #16224: gui: Bilingual GUI error messages

18bd83b1fee2eb47ed4ad05c91f2d6cc311fc9ad util: Cleanup translation.h (Hennadii Stepanov)
e95e658b8ec6e02229691a1941d688e96d4df6af doc: Do not translate technical or extremely rare errors (Hennadii Stepanov)
7e923d47ba9891856b86bc9f718cf2f1f773bdf6 Make InitError bilingual (Hennadii Stepanov)
917ca93553917251e0fd59717a347c63cdfd8a14 Make ThreadSafe{MessageBox|Question} bilingual (Hennadii Stepanov)
23b9fa2e5ec0425980301d2eebad81e660a5ea39 gui: Add detailed text to BitcoinGUI::message (Hennadii Stepanov)

Pull request description:

  This is an alternative to #15340 (it works with the `Chain` interface; see: https://github.com/bitcoin/bitcoin/pull/15340#issuecomment-502674004).
  Refs:
  - #16218 (partial fix)
  - https://github.com/bitcoin/bitcoin/pull/15894#issuecomment-487947077

  This PR:
  - makes GUI error messages bilingual: user's native language + untranslated (i.e. English)
  - insures that only untranslated messages are written to the debug log file and to `stderr` (that is not the case on master).

  If a translated string is unavailable only an English string appears to a user.

  Here are some **examples** (updated):

  ![Screenshot from 2020-04-24 17-08-37](https://user-images.githubusercontent.com/32963518/80222043-e2458780-864e-11ea-83fc-197b7121dba5.png)

  ![Screenshot from 2020-04-24 17-12-17](https://user-images.githubusercontent.com/32963518/80222051-e5407800-864e-11ea-92f7-dfef1144becd.png)

  * `qt5ct: using qt5ct plugin` message is my local environment specific; please ignore it.

  ---

  Note for reviewers: `InitWarning()` is out of this PR scope.

ACKs for top commit:
  Sjors:
    re-tACK 18bd83b1fee2eb47ed4ad05c91f2d6cc311fc9ad
  MarcoFalke:
    ACK 18bd83b1fee2eb47ed4ad05c91f2d6cc311fc9ad 🐦

Tree-SHA512: 3cc8ec44f84403e54b57d11714c86b0855ed90eb794b5472e432005073354b9e3f7b4e8e7bf347a4c21be47299dbc7170f2d0c4b80e308205ff09596e55a4f96

# Conflicts:
#	src/dashd.cpp
#	src/httpserver.cpp
#	src/index/base.cpp
#	src/init.cpp
#	src/interfaces/chain.cpp
#	src/interfaces/chain.h
#	src/interfaces/node.cpp
#	src/net.h
#	src/qt/bitcoingui.cpp
#	src/ui_interface.h
#	src/wallet/init.cpp
#	src/wallet/load.cpp
This commit is contained in:
MarcoFalke 2020-05-08 12:17:47 -04:00 committed by pasta
parent 903291788c
commit af00598c9a
23 changed files with 202 additions and 179 deletions

View File

@ -23,7 +23,8 @@ On a high level, these strings are to be translated:
### GUI strings
Anything that appears to the user in the GUI is to be translated. This includes labels, menu items, button texts, tooltips and window titles.
Do not translate technical or extremely rare errors.
Anything else that appears to the user in the GUI is to be translated. This includes labels, menu items, button texts, tooltips and window titles.
This includes messages passed to the GUI through the UI interface through `InitMessage`, `ThreadSafeMessageBox` or `ShowProgress`.
General recommendations

View File

@ -56,7 +56,7 @@ static bool AppInit(int argc, char* argv[])
SetupServerArgs();
std::string error;
if (!gArgs.ParseParameters(argc, argv, error)) {
return InitError(strprintf("Error parsing command line arguments: %s\n", error));
return InitError(Untranslated(strprintf("Error parsing command line arguments: %s\n", error)));
}
if (gArgs.IsArgSet("-printcrashinfo")) {
@ -87,10 +87,10 @@ static bool AppInit(int argc, char* argv[])
bool datadirFromCmdLine = gArgs.IsArgSet("-datadir");
if (datadirFromCmdLine && !fs::is_directory(GetDataDir(false)))
{
return InitError(strprintf("Specified data directory \"%s\" does not exist.\n", gArgs.GetArg("-datadir", "")));
return InitError(Untranslated(strprintf("Specified data directory \"%s\" does not exist.\n", gArgs.GetArg("-datadir", ""))));
}
if (!gArgs.ReadConfigFiles(error, true)) {
return InitError(strprintf("Error reading configuration file: %s\n", error));
return InitError(Untranslated(strprintf("Error reading configuration file: %s\n", error)));
}
if (!datadirFromCmdLine && !fs::is_directory(GetDataDir(false)))
{
@ -101,13 +101,13 @@ static bool AppInit(int argc, char* argv[])
try {
SelectParams(gArgs.GetChainName());
} catch (const std::exception& e) {
return InitError(strprintf("%s\n", e.what()));
return InitError(Untranslated(strprintf("%s\n", e.what())));
}
// Error out when loose non-argument tokens are encountered on command line
for (int i = 1; i < argc; i++) {
if (!IsSwitchChar(argv[i][0])) {
return InitError(strprintf("Command line contains unexpected token '%s', see dashd -h for a list of options.\n", argv[i]));
return InitError(Untranslated(strprintf("Command line contains unexpected token '%s', see dashd -h for a list of options.\n", argv[i])));
}
}
@ -142,13 +142,13 @@ static bool AppInit(int argc, char* argv[])
// Daemonize
if (daemon(1, 0)) { // don't chdir (1), do close FDs (0)
return InitError(strprintf("daemon() failed: %s\n", strerror(errno)));
return InitError(Untranslated(strprintf("daemon() failed: %s\n", strerror(errno))));
}
#if defined(MAC_OSX)
#pragma GCC diagnostic pop
#endif
#else
return InitError("-daemon is not supported on this operating system\n");
return InitError(Untranslated("-daemon is not supported on this operating system\n"));
#endif // HAVE_DECL_DAEMON
}
// Lock data directory after daemonization

View File

@ -219,7 +219,7 @@ static bool InitRPCAuthentication()
LogPrintf("Using random cookie authentication.\n");
if (!GenerateAuthCookie(&strRPCUserColonPass)) {
uiInterface.ThreadSafeMessageBox(
_("Error: A fatal internal error occurred, see debug.log for details").translated, // Same message as AbortNode
_("Error: A fatal internal error occurred, see debug.log for details"), // Same message as AbortNode
"", CClientUIInterface::MSG_ERROR);
return false;
}

View File

@ -5,14 +5,15 @@
#include <httpserver.h>
#include <chainparamsbase.h>
#include <util/system.h>
#include <util/strencodings.h>
#include <util/threadnames.h>
#include <netbase.h>
#include <rpc/protocol.h> // For HTTP status codes
#include <shutdown.h>
#include <sync.h>
#include <ui_interface.h>
#include <util/strencodings.h>
#include <util/system.h>
#include <util/threadnames.h>
#include <util/translation.h>
#include <deque>
#include <stdio.h>
@ -173,7 +174,7 @@ static bool InitHTTPAllowList()
LookupSubNet(strAllow.c_str(), subnet);
if (!subnet.IsValid()) {
uiInterface.ThreadSafeMessageBox(
strprintf("Invalid -rpcallowip subnet specification: %s. Valid are a single IP (e.g. 1.2.3.4), a network/netmask (e.g. 1.2.3.4/255.255.255.0) or a network/CIDR (e.g. 1.2.3.4/24).", strAllow),
strprintf(Untranslated("Invalid -rpcallowip subnet specification: %s. Valid are a single IP (e.g. 1.2.3.4), a network/netmask (e.g. 1.2.3.4/255.255.255.0) or a network/CIDR (e.g. 1.2.3.4/24)."), strAllow),
"", CClientUIInterface::MSG_ERROR);
return false;
}

View File

@ -7,6 +7,7 @@
#include <shutdown.h>
#include <tinyformat.h>
#include <ui_interface.h>
#include <util/translation.h>
#include <validation.h>
#include <warnings.h>
@ -22,7 +23,7 @@ static void FatalError(const char* fmt, const Args&... args)
SetMiscWarning(strMessage);
LogPrintf("*** %s\n", strMessage);
uiInterface.ThreadSafeMessageBox(
"Error: A fatal internal error occurred, see debug.log for details",
Untranslated("Error: A fatal internal error occurred, see debug.log for details"),
"", CClientUIInterface::MSG_ERROR);
StartShutdown();
}

View File

@ -151,7 +151,7 @@ static fs::path GetPidFile()
tfm::format(file, "%d\n", getpid());
return true;
} else {
return InitError(strprintf(_("Unable to create the PID file '%s': %s").translated, GetPidFile().string(), std::strerror(errno)));
return InitError(strprintf(_("Unable to create the PID file '%s': %s"), GetPidFile().string(), std::strerror(errno)));
}
}
#endif
@ -1031,9 +1031,8 @@ void PeriodicStats()
*/
static bool InitSanityCheck()
{
if(!ECC_InitSanityCheck()) {
InitError("Elliptic curve cryptography sanity check failure. Aborting.");
return false;
if (!ECC_InitSanityCheck()) {
return InitError(Untranslated("Elliptic curve cryptography sanity check failure. Aborting."));
}
if (!glibc_sanity_test() || !glibcxx_sanity_test())
@ -1044,8 +1043,7 @@ static bool InitSanityCheck()
}
if (!Random_SanityCheck()) {
InitError("OS cryptographic RNG sanity check failure. Aborting.");
return false;
return InitError(Untranslated("OS cryptographic RNG sanity check failure. Aborting."));
}
return true;
@ -1230,8 +1228,9 @@ bool AppInitBasicSetup()
HeapSetInformation(nullptr, HeapEnableTerminationOnCorruption, nullptr, 0);
#endif
if (!SetupNetworking())
return InitError("Initializing networking failed");
if (!SetupNetworking()) {
return InitError(Untranslated("Initializing networking failed."));
}
#ifndef WIN32
if (!gArgs.GetBoolArg("-sysperms", false)) {
@ -1268,7 +1267,7 @@ bool AppInitParameterInteraction()
// on the command line or in this network's section of the config file.
std::string network = gArgs.GetChainName();
for (const auto& arg : gArgs.GetUnsuitableSectionOnlyArgs()) {
return InitError(strprintf(_("Config setting for %s only applied on %s network when in [%s] section.").translated, arg, network, network));
return InitError(strprintf(_("Config setting for %s only applied on %s network when in [%s] section."), arg, network, network));
}
// Warn if unrecognized section name are present in the config file.
@ -1277,7 +1276,7 @@ bool AppInitParameterInteraction()
}
if (!fs::is_directory(GetBlocksDir())) {
return InitError(strprintf(_("Specified blocks directory \"%s\" does not exist.").translated, gArgs.GetArg("-blocksdir", "")));
return InitError(strprintf(_("Specified blocks directory \"%s\" does not exist."), gArgs.GetArg("-blocksdir", "")));
}
// parse and validate enabled filter types
@ -1289,7 +1288,7 @@ bool AppInitParameterInteraction()
for (const auto& name : names) {
BlockFilterType filter_type;
if (!BlockFilterTypeByName(name, filter_type)) {
return InitError(strprintf(_("Unknown -blockfilterindex value %s.").translated, name));
return InitError(strprintf(_("Unknown -blockfilterindex value %s."), name));
}
g_enabled_filter_types.insert(filter_type);
}
@ -1298,7 +1297,7 @@ bool AppInitParameterInteraction()
// Signal NODE_COMPACT_FILTERS if peerblockfilters and basic filters index are both enabled.
if (gArgs.GetBoolArg("-peerblockfilters", DEFAULT_PEERBLOCKFILTERS)) {
if (g_enabled_filter_types.count(BlockFilterType::BASIC_FILTER) != 1) {
return InitError(_("Cannot set -peerblockfilters without -blockfilterindex.").translated);
return InitError(_("Cannot set -peerblockfilters without -blockfilterindex."));
}
nLocalServices = ServiceFlags(nLocalServices | NODE_COMPACT_FILTERS);
@ -1307,25 +1306,25 @@ bool AppInitParameterInteraction()
// if using block pruning, then disallow txindex and require disabling governance validation
if (gArgs.GetArg("-prune", 0)) {
if (gArgs.GetBoolArg("-txindex", DEFAULT_TXINDEX))
return InitError(_("Prune mode is incompatible with -txindex.").translated);
return InitError(_("Prune mode is incompatible with -txindex."));
if (!gArgs.GetBoolArg("-disablegovernance", false)) {
return InitError(_("Prune mode is incompatible with -disablegovernance=false.").translated);
return InitError(_("Prune mode is incompatible with -disablegovernance=false."));
}
if (!g_enabled_filter_types.empty()) {
return InitError(_("Prune mode is incompatible with -blockfilterindex.").translated);
return InitError(_("Prune mode is incompatible with -blockfilterindex."));
}
}
if (gArgs.IsArgSet("-devnet")) {
// Require setting of ports when running devnet
if (gArgs.GetArg("-listen", DEFAULT_LISTEN) && !gArgs.IsArgSet("-port")) {
return InitError(_("-port must be specified when -devnet and -listen are specified").translated);
return InitError(_("-port must be specified when -devnet and -listen are specified"));
}
if (gArgs.GetArg("-server", false) && !gArgs.IsArgSet("-rpcport")) {
return InitError(_("-rpcport must be specified when -devnet and -server are specified").translated);
return InitError(_("-rpcport must be specified when -devnet and -server are specified"));
}
if (gArgs.GetArgs("-devnet").size() > 1) {
return InitError(_("-devnet can only be specified once").translated);
return InitError(_("-devnet can only be specified once"));
}
}
@ -1334,7 +1333,7 @@ bool AppInitParameterInteraction()
// -bind and -whitebind can't be set when not listening
size_t nUserBind = gArgs.GetArgs("-bind").size() + gArgs.GetArgs("-whitebind").size();
if (nUserBind != 0 && !gArgs.GetBoolArg("-listen", DEFAULT_LISTEN)) {
return InitError("Cannot set -bind or -whitebind together with -listen=0");
return InitError(Untranslated("Cannot set -bind or -whitebind together with -listen=0"));
}
// Make sure enough file descriptors are available
@ -1352,7 +1351,7 @@ bool AppInitParameterInteraction()
#endif
nMaxConnections = std::max(std::min<int>(nMaxConnections, fd_max - nBind - MIN_CORE_FILEDESCRIPTORS - MAX_ADDNODE_CONNECTIONS), 0);
if (nFD < MIN_CORE_FILEDESCRIPTORS)
return InitError(_("Not enough file descriptors available.").translated);
return InitError(_("Not enough file descriptors available."));
nMaxConnections = std::min(nFD - MIN_CORE_FILEDESCRIPTORS - MAX_ADDNODE_CONNECTIONS, nMaxConnections);
if (nMaxConnections < nUserMaxConnections)
@ -1397,7 +1396,7 @@ bool AppInitParameterInteraction()
if (gArgs.IsArgSet("-minimumchainwork")) {
const std::string minChainWorkStr = gArgs.GetArg("-minimumchainwork", "");
if (!IsHexNumber(minChainWorkStr)) {
return InitError(strprintf("Invalid non-hex (%s) minimum chain work value specified", minChainWorkStr));
return InitError(strprintf(Untranslated("Invalid non-hex (%s) minimum chain work value specified"), minChainWorkStr));
}
nMinimumChainWork = UintToArith256(uint256S(minChainWorkStr));
} else {
@ -1412,21 +1411,21 @@ bool AppInitParameterInteraction()
int64_t nMempoolSizeMax = gArgs.GetArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000;
int64_t nMempoolSizeMin = gArgs.GetArg("-limitdescendantsize", DEFAULT_DESCENDANT_SIZE_LIMIT) * 1000 * 40;
if (nMempoolSizeMax < 0 || nMempoolSizeMax < nMempoolSizeMin)
return InitError(strprintf(_("-maxmempool must be at least %d MB").translated, std::ceil(nMempoolSizeMin / 1000000.0)));
return InitError(strprintf(_("-maxmempool must be at least %d MB"), std::ceil(nMempoolSizeMin / 1000000.0)));
// incremental relay fee sets the minimum feerate increase necessary for BIP 125 replacement in the mempool
// and the amount the mempool min fee increases above the feerate of txs evicted due to mempool limiting.
if (gArgs.IsArgSet("-incrementalrelayfee"))
{
CAmount n = 0;
if (!ParseMoney(gArgs.GetArg("-incrementalrelayfee", ""), n))
return InitError(AmountErrMsg("incrementalrelayfee", gArgs.GetArg("-incrementalrelayfee", "")));
return InitError(Untranslated(AmountErrMsg("incrementalrelayfee", gArgs.GetArg("-incrementalrelayfee", ""))));
incrementalRelayFee = CFeeRate(n);
}
// block pruning; get the amount of disk space (in MiB) to allot for block & undo files
int64_t nPruneArg = gArgs.GetArg("-prune", 0);
if (nPruneArg < 0) {
return InitError(_("Prune cannot be configured with a negative value.").translated);
return InitError(_("Prune cannot be configured with a negative value."));
}
nPruneTarget = (uint64_t) nPruneArg * 1024 * 1024;
if (nPruneArg == 1) { // manual pruning: -prune=1
@ -1437,11 +1436,11 @@ bool AppInitParameterInteraction()
if (gArgs.GetBoolArg("-regtest", false)) {
// we use 1MB blocks to test this on regtest
if (nPruneTarget < 550 * 1024 * 1024) {
return InitError(strprintf(_("Prune configured below the minimum of %d MiB. Please use a higher number.").translated, 550));
return InitError(strprintf(_("Prune configured below the minimum of %d MiB. Please use a higher number."), 550));
}
} else {
if (nPruneTarget < MIN_DISK_SPACE_FOR_BLOCK_FILES) {
return InitError(strprintf(_("Prune configured below the minimum of %d MiB. Please use a higher number.").translated, MIN_DISK_SPACE_FOR_BLOCK_FILES / 1024 / 1024));
return InitError(strprintf(_("Prune configured below the minimum of %d MiB. Please use a higher number."), MIN_DISK_SPACE_FOR_BLOCK_FILES / 1024 / 1024));
}
}
LogPrintf("Prune configured to target %u MiB on disk for block and undo files.\n", nPruneTarget / 1024 / 1024);
@ -1455,13 +1454,13 @@ bool AppInitParameterInteraction()
peer_connect_timeout = gArgs.GetArg("-peertimeout", DEFAULT_PEER_CONNECT_TIMEOUT);
if (peer_connect_timeout <= 0) {
return InitError("peertimeout cannot be configured with a negative value.");
return InitError(Untranslated("peertimeout cannot be configured with a negative value."));
}
if (gArgs.IsArgSet("-minrelaytxfee")) {
CAmount n = 0;
if (!ParseMoney(gArgs.GetArg("-minrelaytxfee", ""), n)) {
return InitError(AmountErrMsg("minrelaytxfee", gArgs.GetArg("-minrelaytxfee", "")));
return InitError(Untranslated(AmountErrMsg("minrelaytxfee", gArgs.GetArg("-minrelaytxfee", ""))));
}
// High fee check is done afterward in CWallet::CreateWalletFromFile()
::minRelayTxFee = CFeeRate(n);
@ -1477,7 +1476,7 @@ bool AppInitParameterInteraction()
{
CAmount n = 0;
if (!ParseMoney(gArgs.GetArg("-blockmintxfee", ""), n))
return InitError(AmountErrMsg("blockmintxfee", gArgs.GetArg("-blockmintxfee", "")));
return InitError(Untranslated(AmountErrMsg("blockmintxfee", gArgs.GetArg("-blockmintxfee", ""))));
}
// Feerate used to define dust. Shouldn't be changed lightly as old
@ -1486,13 +1485,13 @@ bool AppInitParameterInteraction()
{
CAmount n = 0;
if (!ParseMoney(gArgs.GetArg("-dustrelayfee", ""), n))
return InitError(AmountErrMsg("dustrelayfee", gArgs.GetArg("-dustrelayfee", "")));
return InitError(Untranslated(AmountErrMsg("dustrelayfee", gArgs.GetArg("-dustrelayfee", ""))));
dustRelayFee = CFeeRate(n);
}
fRequireStandard = !gArgs.GetBoolArg("-acceptnonstdtxn", !chainparams.RequireStandard());
if (!chainparams.IsTestChain() && !fRequireStandard) {
return InitError(strprintf("acceptnonstdtxn is not currently supported for %s chain", chainparams.NetworkIDString()));
return InitError(strprintf(Untranslated("acceptnonstdtxn is not currently supported for %s chain"), chainparams.NetworkIDString()));
}
nBytesPerSigOp = gArgs.GetArg("-bytespersigop", nBytesPerSigOp);
@ -1517,7 +1516,7 @@ bool AppInitParameterInteraction()
InitWarning("-llmq-qvvec-sync set but recovery is disabled due to -llmq-data-recovery=0");
}
} catch (const std::invalid_argument& e) {
return InitError(e.what());
return InitError(Untranslated(e.what()));
}
if (gArgs.IsArgSet("-maxorphantx")) {
@ -1530,22 +1529,22 @@ bool AppInitParameterInteraction()
if (gArgs.IsArgSet("-masternodeblsprivkey")) {
if (!gArgs.GetBoolArg("-listen", DEFAULT_LISTEN) && Params().RequireRoutableExternalIP()) {
return InitError("Masternode must accept connections from outside, set -listen=1");
return InitError(Untranslated("Masternode must accept connections from outside, set -listen=1"));
}
if (!gArgs.GetBoolArg("-txindex", DEFAULT_TXINDEX)) {
return InitError("Masternode must have transaction index enabled, set -txindex=1");
return InitError(Untranslated("Masternode must have transaction index enabled, set -txindex=1"));
}
if (!gArgs.GetBoolArg("-peerbloomfilters", DEFAULT_PEERBLOOMFILTERS)) {
return InitError("Masternode must have bloom filters enabled, set -peerbloomfilters=1");
return InitError(Untranslated("Masternode must have bloom filters enabled, set -peerbloomfilters=1"));
}
if (gArgs.GetArg("-prune", 0) > 0) {
return InitError("Masternode must have no pruning enabled, set -prune=0");
return InitError(Untranslated("Masternode must have no pruning enabled, set -prune=0"));
}
if (gArgs.GetArg("-maxconnections", DEFAULT_MAX_PEER_CONNECTIONS) < DEFAULT_MAX_PEER_CONNECTIONS) {
return InitError(strprintf("Masternode must be able to handle at least %d connections, set -maxconnections=%d", DEFAULT_MAX_PEER_CONNECTIONS, DEFAULT_MAX_PEER_CONNECTIONS));
return InitError(strprintf(Untranslated("Masternode must be able to handle at least %d connections, set -maxconnections=%d"), DEFAULT_MAX_PEER_CONNECTIONS, DEFAULT_MAX_PEER_CONNECTIONS));
}
if (gArgs.GetBoolArg("-disablegovernance", false)) {
return InitError(_("You can not disable governance validation on a masternode.").translated);
return InitError(_("You can not disable governance validation on a masternode."));
}
}
@ -1569,10 +1568,10 @@ static bool LockDataDirectory(bool probeOnly)
// Make sure only a single Dash Core process is using the data directory.
fs::path datadir = GetDataDir();
if (!DirIsWritable(datadir)) {
return InitError(strprintf(_("Cannot write to data directory '%s'; check permissions.").translated, datadir.string()));
return InitError(strprintf(_("Cannot write to data directory '%s'; check permissions."), datadir.string()));
}
if (!LockDirectory(datadir, ".lock", probeOnly)) {
return InitError(strprintf(_("Cannot obtain a lock on data directory %s. %s is probably already running.").translated, datadir.string(), PACKAGE_NAME));
return InitError(strprintf(_("Cannot obtain a lock on data directory %s. %s is probably already running."), datadir.string(), PACKAGE_NAME));
}
return true;
}
@ -1590,7 +1589,7 @@ bool AppInitSanityChecks()
// Sanity check
if (!InitSanityCheck())
return InitError(strprintf(_("Initialization sanity check failed. %s is shutting down.").translated, PACKAGE_NAME));
return InitError(strprintf(_("Initialization sanity check failed. %s is shutting down."), PACKAGE_NAME));
// Probe the data directory lock to give an early error message, if possible
// We cannot hold the data directory lock here, as the forking for daemon() hasn't yet happened,
@ -1628,7 +1627,7 @@ bool AppInitMain(InitInterfaces& interfaces)
}
}
if (!LogInstance().StartLogging()) {
return InitError(strprintf("Could not open debug log file %s",
return InitError(strprintf(Untranslated("Could not open debug log file %s"),
LogInstance().m_file_path.string()));
}
@ -1690,19 +1689,19 @@ bool AppInitMain(InitInterfaces& interfaces)
}
for (const auto& address: vSporkAddresses) {
if (!sporkManager.SetSporkAddress(address)) {
return InitError(_("Invalid spork address specified with -sporkaddr").translated);
return InitError(_("Invalid spork address specified with -sporkaddr"));
}
}
int minsporkkeys = gArgs.GetArg("-minsporkkeys", Params().MinSporkKeys());
if (!sporkManager.SetMinSporkKeys(minsporkkeys)) {
return InitError(_("Invalid minimum number of spork signers specified with -minsporkkeys").translated);
return InitError(_("Invalid minimum number of spork signers specified with -minsporkkeys"));
}
if (gArgs.IsArgSet("-sporkkey")) { // spork priv key
if (!sporkManager.SetPrivKey(gArgs.GetArg("-sporkkey", ""))) {
return InitError(_("Unable to sign spork message, wrong key?").translated);
return InitError(_("Unable to sign spork message, wrong key?"));
}
}
@ -1742,7 +1741,7 @@ bool AppInitMain(InitInterfaces& interfaces)
{
uiInterface.InitMessage_connect(SetRPCWarmupStatus);
if (!AppInitServers())
return InitError(_("Unable to start HTTP server. See debug log for details.").translated);
return InitError(_("Unable to start HTTP server. See debug log for details."));
}
// ********************************************************* Step 5: verify wallet database integrity
@ -1778,12 +1777,12 @@ bool AppInitMain(InitInterfaces& interfaces)
for (const std::string& cmt : gArgs.GetArgs("-uacomment")) {
if (cmt != SanitizeString(cmt, SAFE_CHARS_UA_COMMENT))
return InitError(strprintf(_("User Agent comment (%s) contains unsafe characters.").translated, cmt));
return InitError(strprintf(_("User Agent comment (%s) contains unsafe characters."), cmt));
uacomments.push_back(cmt);
}
strSubVersion = FormatSubVersion(CLIENT_NAME, CLIENT_VERSION, uacomments);
if (strSubVersion.size() > MAX_SUBVERSION_LENGTH) {
return InitError(strprintf(_("Total length of network version string (%i) exceeds maximum length (%i). Reduce the number or size of uacomments.").translated,
return InitError(strprintf(_("Total length of network version string (%i) exceeds maximum length (%i). Reduce the number or size of uacomments."),
strSubVersion.size(), MAX_SUBVERSION_LENGTH));
}
@ -1792,7 +1791,7 @@ bool AppInitMain(InitInterfaces& interfaces)
for (const std::string& snet : gArgs.GetArgs("-onlynet")) {
enum Network net = ParseNetwork(snet);
if (net == NET_UNROUTABLE)
return InitError(strprintf(_("Unknown network specified in -onlynet: '%s'").translated, snet));
return InitError(strprintf(_("Unknown network specified in -onlynet: '%s'"), snet));
nets.insert(net);
}
for (int n = 0; n < NET_MAX; n++) {
@ -1813,12 +1812,12 @@ bool AppInitMain(InitInterfaces& interfaces)
if (proxyArg != "" && proxyArg != "0") {
CService proxyAddr;
if (!Lookup(proxyArg.c_str(), proxyAddr, 9050, fNameLookup)) {
return InitError(strprintf(_("Invalid -proxy address or hostname: '%s'").translated, proxyArg));
return InitError(strprintf(_("Invalid -proxy address or hostname: '%s'"), proxyArg));
}
proxyType addrProxy = proxyType(proxyAddr, proxyRandomize);
if (!addrProxy.IsValid())
return InitError(strprintf(_("Invalid -proxy address or hostname: '%s'").translated, proxyArg));
return InitError(strprintf(_("Invalid -proxy address or hostname: '%s'"), proxyArg));
SetProxy(NET_IPV4, addrProxy);
SetProxy(NET_IPV6, addrProxy);
@ -1837,11 +1836,11 @@ bool AppInitMain(InitInterfaces& interfaces)
} else {
CService onionProxy;
if (!Lookup(onionArg.c_str(), onionProxy, 9050, fNameLookup)) {
return InitError(strprintf(_("Invalid -onion address or hostname: '%s'").translated, onionArg));
return InitError(strprintf(_("Invalid -onion address or hostname: '%s'"), onionArg));
}
proxyType addrOnion = proxyType(onionProxy, proxyRandomize);
if (!addrOnion.IsValid())
return InitError(strprintf(_("Invalid -onion address or hostname: '%s'").translated, onionArg));
return InitError(strprintf(_("Invalid -onion address or hostname: '%s'"), onionArg));
SetProxy(NET_ONION, addrOnion);
SetReachable(NET_ONION, true);
}
@ -1857,7 +1856,7 @@ bool AppInitMain(InitInterfaces& interfaces)
if (Lookup(strAddr.c_str(), addrLocal, GetListenPort(), fNameLookup) && addrLocal.IsValid())
AddLocal(addrLocal, LOCAL_MANUAL);
else
return InitError(ResolveErrMsg("externalip", strAddr));
return InitError(Untranslated(ResolveErrMsg("externalip", strAddr)));
}
// Read asmap file if configured
@ -1870,12 +1869,12 @@ bool AppInitMain(InitInterfaces& interfaces)
asmap_path = GetDataDir() / asmap_path;
}
if (!fs::exists(asmap_path)) {
InitError(strprintf(_("Could not find asmap file %s").translated, asmap_path));
InitError(strprintf(_("Could not find asmap file %s"), asmap_path));
return false;
}
std::vector<bool> asmap = CAddrMan::DecodeAsmap(asmap_path);
if (asmap.size() == 0) {
InitError(strprintf(_("Could not parse asmap file %s").translated, asmap_path));
InitError(strprintf(_("Could not parse asmap file %s"), asmap_path));
return false;
}
const uint256 asmap_version = SerializeHash(asmap);
@ -1908,7 +1907,7 @@ bool AppInitMain(InitInterfaces& interfaces)
uiInterface.InitMessage(_("Loading sporks cache...").translated);
CFlatDB<CSporkManager> flatdb6("sporks.dat", "magicSporkCache");
if (!flatdb6.Load(sporkManager)) {
return InitError(_("Failed to load sporks cache from").translated + "\n" + (GetDataDir() / "sporks.dat").string());
return InitError(strprintf(_("Failed to load sporks cache from %s"), (GetDataDir() / "sporks.dat").string()));
}
// ********************************************************* Step 7b: load block chain
@ -1953,7 +1952,7 @@ bool AppInitMain(InitInterfaces& interfaces)
while (!fLoaded && !ShutdownRequested()) {
bool fReset = fReindex;
std::string strLoadError;
bilingual_str strLoadError;
uiInterface.InitMessage(_("Loading block index...").translated);
@ -1994,47 +1993,47 @@ bool AppInitMain(InitInterfaces& interfaces)
// From here on out fReindex and fReset mean something different!
if (!LoadBlockIndex(chainparams)) {
if (ShutdownRequested()) break;
strLoadError = _("Error loading block database").translated;
strLoadError = _("Error loading block database");
break;
}
if (!fDisableGovernance && !gArgs.GetBoolArg("-txindex", DEFAULT_TXINDEX)
&& chainparams.NetworkIDString() != CBaseChainParams::REGTEST) { // TODO remove this when pruning is fixed. See https://github.com/dashpay/dash/pull/1817 and https://github.com/dashpay/dash/pull/1743
return InitError(_("Transaction index can't be disabled with governance validation enabled. Either start with -disablegovernance command line switch or enable transaction index.").translated);
return InitError(_("Transaction index can't be disabled with governance validation enabled. Either start with -disablegovernance command line switch or enable transaction index."));
}
// If the loaded chain has a wrong genesis, bail out immediately
// (we're likely using a testnet datadir, or the other way around).
if (!::BlockIndex().empty() &&
!LookupBlockIndex(chainparams.GetConsensus().hashGenesisBlock)) {
return InitError(_("Incorrect or no genesis block found. Wrong datadir for network?").translated);
return InitError(_("Incorrect or no genesis block found. Wrong datadir for network?"));
}
if (!chainparams.GetConsensus().hashDevnetGenesisBlock.IsNull() && !::BlockIndex().empty() && ::BlockIndex().count(chainparams.GetConsensus().hashDevnetGenesisBlock) == 0)
return InitError(_("Incorrect or no devnet genesis block found. Wrong datadir for devnet specified?").translated);
return InitError(_("Incorrect or no devnet genesis block found. Wrong datadir for devnet specified?"));
// Check for changed -addressindex state
if (fAddressIndex != gArgs.GetBoolArg("-addressindex", DEFAULT_ADDRESSINDEX)) {
strLoadError = _("You need to rebuild the database using -reindex to change -addressindex").translated;
strLoadError = _("You need to rebuild the database using -reindex to change -addressindex");
break;
}
// Check for changed -timestampindex state
if (fTimestampIndex != gArgs.GetBoolArg("-timestampindex", DEFAULT_TIMESTAMPINDEX)) {
strLoadError = _("You need to rebuild the database using -reindex to change -timestampindex").translated;
strLoadError = _("You need to rebuild the database using -reindex to change -timestampindex");
break;
}
// Check for changed -spentindex state
if (fSpentIndex != gArgs.GetBoolArg("-spentindex", DEFAULT_SPENTINDEX)) {
strLoadError = _("You need to rebuild the database using -reindex to change -spentindex").translated;
strLoadError = _("You need to rebuild the database using -reindex to change -spentindex");
break;
}
// Check for changed -prune state. What we are concerned about is a user who has pruned blocks
// in the past, but is now trying to run unpruned.
if (fHavePruned && !fPruneMode) {
strLoadError = _("You need to rebuild the database using -reindex to go back to unpruned mode. This will redownload the entire blockchain").translated;
strLoadError = _("You need to rebuild the database using -reindex to go back to unpruned mode. This will redownload the entire blockchain");
break;
}
@ -2043,7 +2042,7 @@ bool AppInitMain(InitInterfaces& interfaces)
// (otherwise we use the one already on disk).
// This is called again in ThreadImport after the reindex completes.
if (!fReindex && !LoadGenesisBlock(chainparams)) {
strLoadError = _("Error initializing block database").translated;
strLoadError = _("Error initializing block database");
break;
}
@ -2057,20 +2056,20 @@ bool AppInitMain(InitInterfaces& interfaces)
::ChainstateActive().CoinsErrorCatcher().AddReadErrCallback([]() {
uiInterface.ThreadSafeMessageBox(
_("Error reading from database, shutting down.").translated,
_("Error reading from database, shutting down."),
"", CClientUIInterface::MSG_ERROR);
});
// If necessary, upgrade from older database format.
// This is a no-op if we cleared the coinsviewdb with -reindex or -reindex-chainstate
if (!::ChainstateActive().CoinsDB().Upgrade()) {
strLoadError = _("Error upgrading chainstate database").translated;
strLoadError = _("Error upgrading chainstate database");
break;
}
// ReplayBlocks is a no-op if we cleared the coinsviewdb with -reindex or -reindex-chainstate
if (!::ChainstateActive().ReplayBlocks(chainparams)) {
strLoadError = _("Unable to replay blocks. You will need to rebuild the database using -reindex-chainstate.").translated;
strLoadError = _("Unable to replay blocks. You will need to rebuild the database using -reindex-chainstate.");
break;
}
@ -2080,7 +2079,7 @@ bool AppInitMain(InitInterfaces& interfaces)
// flush evodb
if (!evoDb->CommitRootTransaction()) {
strLoadError = _("Failed to commit EvoDB").translated;
strLoadError = _("Failed to commit EvoDB");
break;
}
@ -2089,7 +2088,7 @@ bool AppInitMain(InitInterfaces& interfaces)
if (!is_coinsview_empty) {
// LoadChainTip initializes the chain based on CoinsTip()'s best block
if (!::ChainstateActive().LoadChainTip(chainparams)) {
strLoadError = _("Error initializing block database").translated;
strLoadError = _("Error initializing block database");
break;
}
assert(::ChainActive().Tip() != NULL);
@ -2097,12 +2096,12 @@ bool AppInitMain(InitInterfaces& interfaces)
if (is_coinsview_empty && !evoDb->IsEmpty()) {
// EvoDB processed some blocks earlier but we have no blocks anymore, something is wrong
strLoadError = _("Error initializing block database").translated;
strLoadError = _("Error initializing block database");
break;
}
if (!deterministicMNManager->UpgradeDBIfNeeded() || !llmq::quorumBlockProcessor->UpgradeDB()) {
strLoadError = _("Error upgrading evo database").translated;
strLoadError = _("Error upgrading evo database");
break;
}
@ -2118,13 +2117,13 @@ bool AppInitMain(InitInterfaces& interfaces)
if (tip && tip->nTime > GetAdjustedTime() + 2 * 60 * 60) {
strLoadError = _("The block database contains a block which appears to be from the future. "
"This may be due to your computer's date and time being set incorrectly. "
"Only rebuild the block database if you are sure that your computer's date and time are correct").translated;
"Only rebuild the block database if you are sure that your computer's date and time are correct");
break;
}
if (!CVerifyDB().VerifyDB(chainparams, &::ChainstateActive().CoinsDB(), gArgs.GetArg("-checklevel", DEFAULT_CHECKLEVEL),
gArgs.GetArg("-checkblocks", DEFAULT_CHECKBLOCKS))) {
strLoadError = _("Corrupted block database detected").translated;
strLoadError = _("Corrupted block database detected");
break;
}
@ -2134,7 +2133,7 @@ bool AppInitMain(InitInterfaces& interfaces)
}
} catch (const std::exception& e) {
LogPrintf("%s\n", e.what());
strLoadError = _("Error opening block database").translated;
strLoadError = _("Error opening block database");
break;
}
@ -2146,8 +2145,8 @@ bool AppInitMain(InitInterfaces& interfaces)
// first suggest a reindex
if (!fReset) {
bool fRet = uiInterface.ThreadSafeQuestion(
strLoadError + ".\n\n" + _("Do you want to rebuild the block database now?").translated,
strLoadError + ".\nPlease restart with -reindex or -reindex-chainstate to recover.",
strLoadError + Untranslated(".\n\n") + _("Do you want to rebuild the block database now?"),
strLoadError.original + ".\nPlease restart with -reindex or -reindex-chainstate to recover.",
"", CClientUIInterface::MSG_ERROR | CClientUIInterface::BTN_ABORT);
if (fRet) {
fReindex = true;
@ -2231,7 +2230,7 @@ bool AppInitMain(InitInterfaces& interfaces)
auto binKey = ParseHex(strMasterNodeBLSPrivKey);
CBLSSecretKey keyOperator(binKey);
if (!keyOperator.IsValid()) {
return InitError(_("Invalid masternodeblsprivkey. Please see documentation.").translated);
return InitError(_("Invalid masternodeblsprivkey. Please see documentation."));
}
fMasternodeMode = true;
{
@ -2284,12 +2283,12 @@ bool AppInitMain(InitInterfaces& interfaces)
CFlatDB<CMasternodeMetaMan> flatdb1(strDBName, "magicMasternodeCache");
if (fLoadCacheFiles) {
if(!flatdb1.Load(mmetaman)) {
return InitError(_("Failed to load masternode cache from").translated + "\n" + (pathDB / strDBName).string());
return InitError(strprintf(_("Failed to load masternode cache from %s"), (pathDB / strDBName).string()));
}
} else {
CMasternodeMetaMan mmetamanTmp;
if(!flatdb1.Dump(mmetamanTmp)) {
return InitError(_("Failed to clear masternode cache at").translated + "\n" + (pathDB / strDBName).string());
return InitError(strprintf(_("Failed to clear masternode cache at %s"), (pathDB / strDBName).string()));
}
}
@ -2298,13 +2297,13 @@ bool AppInitMain(InitInterfaces& interfaces)
CFlatDB<CGovernanceManager> flatdb3(strDBName, "magicGovernanceCache");
if (fLoadCacheFiles && !fDisableGovernance) {
if(!flatdb3.Load(governance)) {
return InitError(_("Failed to load governance cache from").translated + "\n" + (pathDB / strDBName).string());
return InitError(strprintf(_("Failed to load governance cache from %s"), (pathDB / strDBName).string()));
}
governance.InitOnLoad();
} else {
CGovernanceManager governanceTmp;
if(!flatdb3.Dump(governanceTmp)) {
return InitError(_("Failed to clear governance cache at").translated + "\n" + (pathDB / strDBName).string());
return InitError(strprintf(_("Failed to clear governance cache at %s"), (pathDB / strDBName).string()));
}
}
@ -2313,12 +2312,12 @@ bool AppInitMain(InitInterfaces& interfaces)
CFlatDB<CNetFulfilledRequestManager> flatdb4(strDBName, "magicFulfilledCache");
if (fLoadCacheFiles) {
if(!flatdb4.Load(netfulfilledman)) {
return InitError(_("Failed to load fulfilled requests cache from").translated + "\n" + (pathDB / strDBName).string());
return InitError(strprintf(_("Failed to load fulfilled requests cache from %s"),(pathDB / strDBName).string()));
}
} else {
CNetFulfilledRequestManager netfulfilledmanTmp;
if(!flatdb4.Dump(netfulfilledmanTmp)) {
return InitError(_("Failed to clear fulfilled requests cache at").translated + "\n" + (pathDB / strDBName).string());
return InitError(strprintf(_("Failed to clear fulfilled requests cache at %s"),(pathDB / strDBName).string()));
}
}
@ -2347,11 +2346,11 @@ bool AppInitMain(InitInterfaces& interfaces)
// ********************************************************* Step 11: import blocks
if (!CheckDiskSpace(GetDataDir())) {
InitError(strprintf(_("Error: Disk space is low for %s").translated, GetDataDir()));
InitError(strprintf(_("Error: Disk space is low for %s"), GetDataDir()));
return false;
}
if (!CheckDiskSpace(GetBlocksDir())) {
InitError(strprintf(_("Error: Disk space is low for %s").translated, GetBlocksDir()));
InitError(strprintf(_("Error: Disk space is low for %s"), GetBlocksDir()));
return false;
}
@ -2433,21 +2432,21 @@ bool AppInitMain(InitInterfaces& interfaces)
for (const std::string& strBind : gArgs.GetArgs("-bind")) {
CService addrBind;
if (!Lookup(strBind.c_str(), addrBind, GetListenPort(), false)) {
return InitError(ResolveErrMsg("bind", strBind));
return InitError(Untranslated(ResolveErrMsg("bind", strBind)));
}
connOptions.vBinds.push_back(addrBind);
}
for (const std::string& strBind : gArgs.GetArgs("-whitebind")) {
NetWhitebindPermissions whitebind;
std::string error;
if (!NetWhitebindPermissions::TryParse(strBind, whitebind, error)) return InitError(error);
if (!NetWhitebindPermissions::TryParse(strBind, whitebind, error)) return InitError(Untranslated(error));
connOptions.vWhiteBinds.push_back(whitebind);
}
for (const auto& net : gArgs.GetArgs("-whitelist")) {
NetWhitelistPermissions subnet;
std::string error;
if (!NetWhitelistPermissions::TryParse(net, subnet, error)) return InitError(error);
if (!NetWhitelistPermissions::TryParse(net, subnet, error)) return InitError(Untranslated(error));
connOptions.vWhitelistedRange.push_back(subnet);
}
@ -2478,7 +2477,7 @@ bool AppInitMain(InitInterfaces& interfaces)
connOptions.socketEventsMode = CConnman::SOCKETEVENTS_KQUEUE;
#endif
} else {
return InitError(strprintf(_("Invalid -socketevents ('%s') specified. Only these modes are supported: %s").translated, strSocketEventsMode, GetSupportedSocketEventsStr()));
return InitError(strprintf(_("Invalid -socketevents ('%s') specified. Only these modes are supported: %s"), strSocketEventsMode, GetSupportedSocketEventsStr()));
}
if (!g_connman->Start(scheduler, connOptions)) {

View File

@ -345,7 +345,7 @@ public:
int64_t getAdjustedTime() override { return GetAdjustedTime(); }
void initMessage(const std::string& message) override { ::uiInterface.InitMessage(message); }
void initWarning(const std::string& message) override { InitWarning(message); }
void initError(const std::string& message) override { InitError(message); }
void initError(const bilingual_str& message) override { InitError(message); }
void loadWallet(std::unique_ptr<Wallet> wallet) override { ::uiInterface.LoadWallet(wallet); }
void showProgress(const std::string& title, int progress, bool resume_possible) override
{

View File

@ -23,6 +23,7 @@ class CFeeRate;
class CBlockIndex;
class Coin;
class uint256;
struct bilingual_str;
struct CBlockLocator;
struct FeeCalculation;
enum class MemPoolRemovalReason;
@ -216,7 +217,7 @@ public:
virtual void initWarning(const std::string& message) = 0;
//! Send init error.
virtual void initError(const std::string& message) = 0;
virtual void initError(const bilingual_str& message) = 0;
//! Send wallet load notification to the GUI.
virtual void loadWallet(std::unique_ptr<Wallet> wallet) = 0;

View File

@ -33,6 +33,7 @@
#include <txmempool.h>
#include <ui_interface.h>
#include <util/system.h>
#include <util/translation.h>
#include <validation.h>
#include <warnings.h>
@ -177,7 +178,7 @@ public:
MasternodeSyncImpl m_masternodeSync;
CoinJoinOptionsImpl m_coinjoin;
void initError(const std::string& message) override { InitError(message); }
void initError(const std::string& message) override { InitError(Untranslated(message)); }
bool parseParameters(int argc, const char* const argv[], std::string& error) override
{
return gArgs.ParseParameters(argc, argv, error);

View File

@ -294,11 +294,11 @@ public:
//! Register handler for message box messages.
using MessageBoxFn =
std::function<bool(const std::string& message, const std::string& caption, unsigned int style)>;
std::function<bool(const bilingual_str& message, const std::string& caption, unsigned int style)>;
virtual std::unique_ptr<Handler> handleMessageBox(MessageBoxFn fn) = 0;
//! Register handler for question messages.
using QuestionFn = std::function<bool(const std::string& message,
using QuestionFn = std::function<bool(const bilingual_str& message,
const std::string& non_interactive_message,
const std::string& caption,
unsigned int style)>;

View File

@ -2612,9 +2612,8 @@ void CConnman::ThreadMessageHandler()
bool CConnman::BindListenPort(const CService& addrBind, std::string& strError, NetPermissionFlags permissions)
bool CConnman::BindListenPort(const CService& addrBind, bilingual_str& strError, NetPermissionFlags permissions)
{
strError = "";
int nOne = 1;
// Create socket for listening for incoming connections
@ -2622,16 +2621,16 @@ bool CConnman::BindListenPort(const CService& addrBind, std::string& strError, N
socklen_t len = sizeof(sockaddr);
if (!addrBind.GetSockAddr((struct sockaddr*)&sockaddr, &len))
{
strError = strprintf("Error: Bind address family for %s not supported", addrBind.ToString());
LogPrintf("%s\n", strError);
strError = strprintf(Untranslated("Error: Bind address family for %s not supported"), addrBind.ToString());
LogPrintf("%s\n", strError.original);
return false;
}
SOCKET hListenSocket = CreateSocket(addrBind);
if (hListenSocket == INVALID_SOCKET)
{
strError = strprintf("Error: Couldn't open socket for incoming connections (socket returned error %s)", NetworkErrorString(WSAGetLastError()));
LogPrintf("%s\n", strError);
strError = strprintf(Untranslated("Error: Couldn't open socket for incoming connections (socket returned error %s)"), NetworkErrorString(WSAGetLastError()));
LogPrintf("%s\n", strError.original);
return false;
}
@ -2655,10 +2654,10 @@ bool CConnman::BindListenPort(const CService& addrBind, std::string& strError, N
{
int nErr = WSAGetLastError();
if (nErr == WSAEADDRINUSE)
strError = strprintf(_("Unable to bind to %s on this computer. %s is probably already running.").translated, addrBind.ToString(), PACKAGE_NAME);
strError = strprintf(_("Unable to bind to %s on this computer. %s is probably already running."), addrBind.ToString(), PACKAGE_NAME);
else
strError = strprintf(_("Unable to bind to %s on this computer (bind returned error %s)").translated, addrBind.ToString(), NetworkErrorString(nErr));
LogPrintf("%s\n", strError);
strError = strprintf(_("Unable to bind to %s on this computer (bind returned error %s)"), addrBind.ToString(), NetworkErrorString(nErr));
LogPrintf("%s\n", strError.original);
CloseSocket(hListenSocket);
return false;
}
@ -2667,8 +2666,8 @@ bool CConnman::BindListenPort(const CService& addrBind, std::string& strError, N
// Listen for incoming connections
if (listen(hListenSocket, SOMAXCONN) == SOCKET_ERROR)
{
strError = strprintf(_("Error: Listening for incoming connections failed (listen returned error %s)").translated, NetworkErrorString(WSAGetLastError()));
LogPrintf("%s\n", strError);
strError = strprintf(_("Error: Listening for incoming connections failed (listen returned error %s)"), NetworkErrorString(WSAGetLastError()));
LogPrintf("%s\n", strError.original);
CloseSocket(hListenSocket);
return false;
}
@ -2678,8 +2677,8 @@ bool CConnman::BindListenPort(const CService& addrBind, std::string& strError, N
struct kevent event;
EV_SET(&event, hListenSocket, EVFILT_READ, EV_ADD, 0, 0, nullptr);
if (kevent(kqueuefd, &event, 1, nullptr, 0, nullptr) != 0) {
strError = strprintf(_("Error: failed to add socket to kqueuefd (kevent returned error %s)").translated, NetworkErrorString(WSAGetLastError()));
LogPrintf("%s\n", strError);
strError = strprintf(_("Error: failed to add socket to kqueuefd (kevent returned error %s)"), NetworkErrorString(WSAGetLastError()));
LogPrintf("%s\n", strError.original);
CloseSocket(hListenSocket);
return false;
}
@ -2692,8 +2691,8 @@ bool CConnman::BindListenPort(const CService& addrBind, std::string& strError, N
event.data.fd = hListenSocket;
event.events = EPOLLIN;
if (epoll_ctl(epollfd, EPOLL_CTL_ADD, hListenSocket, &event) != 0) {
strError = strprintf(_("Error: failed to add socket to epollfd (epoll_ctl returned error %s)").translated, NetworkErrorString(WSAGetLastError()));
LogPrintf("%s\n", strError);
strError = strprintf(_("Error: failed to add socket to epollfd (epoll_ctl returned error %s)"), NetworkErrorString(WSAGetLastError()));
LogPrintf("%s\n", strError.original);
CloseSocket(hListenSocket);
return false;
}
@ -2795,7 +2794,7 @@ NodeId CConnman::GetNewNodeId()
bool CConnman::Bind(const CService &addr, unsigned int flags, NetPermissionFlags permissions) {
if (!(flags & BF_EXPLICIT) && !IsReachable(addr))
return false;
std::string strError;
bilingual_str strError;
if (!BindListenPort(addr, strError, permissions)) {
if ((flags & BF_REPORT_ERROR) && clientInterface) {
clientInterface->ThreadSafeMessageBox(strError, "", CClientUIInterface::MSG_ERROR);
@ -2862,7 +2861,7 @@ bool CConnman::Start(CScheduler& scheduler, const Options& connOptions)
if (fListen && !InitBinds(connOptions.vBinds, connOptions.vWhiteBinds)) {
if (clientInterface) {
clientInterface->ThreadSafeMessageBox(
_("Failed to listen on any port. Use -listen=0 if you want this.").translated,
_("Failed to listen on any port. Use -listen=0 if you want this."),
"", CClientUIInterface::MSG_ERROR);
}
return false;
@ -2969,7 +2968,7 @@ bool CConnman::Start(CScheduler& scheduler, const Options& connOptions)
if (connOptions.m_use_addrman_outgoing && !connOptions.m_specified_outgoing.empty()) {
if (clientInterface) {
clientInterface->ThreadSafeMessageBox(
_("Cannot provide specific connections and have addrman find outgoing connections at the same.").translated,
_("Cannot provide specific connections and have addrman find outgoing connections at the same."),
"", CClientUIInterface::MSG_ERROR);
}
return false;

View File

@ -22,9 +22,9 @@
#include <saltedhasher.h>
#include <streams.h>
#include <sync.h>
#include <threadinterrupt.h>
#include <uint256.h>
#include <util/system.h>
#include <threadinterrupt.h>
#include <consensus/params.h>
#include <atomic>
@ -48,6 +48,7 @@
class CScheduler;
class CNode;
class BanMan;
struct bilingual_str;
/** Default for -whitelistrelay. */
static const bool DEFAULT_WHITELISTRELAY = true;
@ -483,7 +484,7 @@ private:
NetPermissionFlags m_permissions;
};
bool BindListenPort(const CService& bindAddr, std::string& strError, NetPermissionFlags permissions);
bool BindListenPort(const CService& bindAddr, bilingual_str& strError, NetPermissionFlags permissions);
bool Bind(const CService& addr, unsigned int flags, NetPermissionFlags permissions);
bool InitBinds(const std::vector<CService>& binds, const std::vector<NetWhitebindPermissions>& whiteBinds);
void ThreadOpenAddedConnections();

View File

@ -6,8 +6,9 @@
#include <noui.h>
#include <logging.h>
#include <ui_interface.h>
#include <util/system.h>
#include <util/translation.h>
#include <string>
@ -18,7 +19,7 @@ boost::signals2::connection noui_ThreadSafeMessageBoxConn;
boost::signals2::connection noui_ThreadSafeQuestionConn;
boost::signals2::connection noui_InitMessageConn;
bool noui_ThreadSafeMessageBox(const std::string& message, const std::string& caption, unsigned int style)
bool noui_ThreadSafeMessageBox(const bilingual_str& message, const std::string& caption, unsigned int style)
{
bool fSecure = style & CClientUIInterface::SECURE;
style &= ~CClientUIInterface::SECURE;
@ -43,15 +44,15 @@ bool noui_ThreadSafeMessageBox(const std::string& message, const std::string& ca
}
if (!fSecure) {
LogPrintf("%s%s\n", strCaption, message);
LogPrintf("%s%s\n", strCaption, message.original);
}
tfm::format(std::cerr, "%s%s\n", strCaption, message);
tfm::format(std::cerr, "%s%s\n", strCaption, message.original);
return false;
}
bool noui_ThreadSafeQuestion(const std::string& /* ignored interactive message */, const std::string& message, const std::string& caption, unsigned int style)
bool noui_ThreadSafeQuestion(const bilingual_str& /* ignored interactive message */, const std::string& message, const std::string& caption, unsigned int style)
{
return noui_ThreadSafeMessageBox(message, caption, style);
return noui_ThreadSafeMessageBox(Untranslated(message), caption, style);
}
void noui_InitMessage(const std::string& message)
@ -66,13 +67,13 @@ void noui_connect()
noui_InitMessageConn = uiInterface.InitMessage_connect(noui_InitMessage);
}
bool noui_ThreadSafeMessageBoxRedirect(const std::string& message, const std::string& caption, unsigned int style)
bool noui_ThreadSafeMessageBoxRedirect(const bilingual_str& message, const std::string& caption, unsigned int style)
{
LogPrintf("%s: %s\n", caption, message);
LogPrintf("%s: %s\n", caption, message.original);
return false;
}
bool noui_ThreadSafeQuestionRedirect(const std::string& /* ignored interactive message */, const std::string& message, const std::string& caption, unsigned int style)
bool noui_ThreadSafeQuestionRedirect(const bilingual_str& /* ignored interactive message */, const std::string& message, const std::string& caption, unsigned int style)
{
LogPrintf("%s: %s\n", caption, message);
return false;

View File

@ -7,10 +7,12 @@
#include <string>
struct bilingual_str;
/** Non-GUI handler, which logs and prints messages. */
bool noui_ThreadSafeMessageBox(const std::string& message, const std::string& caption, unsigned int style);
bool noui_ThreadSafeMessageBox(const bilingual_str& message, const std::string& caption, unsigned int style);
/** Non-GUI handler, which logs and prints questions. */
bool noui_ThreadSafeQuestion(const std::string& /* ignored interactive message */, const std::string& message, const std::string& caption, unsigned int style);
bool noui_ThreadSafeQuestion(const bilingual_str& /* ignored interactive message */, const std::string& message, const std::string& caption, unsigned int style);
/** Non-GUI handler, which only logs a message. */
void noui_InitMessage(const std::string& message);

View File

@ -38,6 +38,7 @@
#include <qt/masternodelist.h>
#include <ui_interface.h>
#include <util/system.h>
#include <util/translation.h>
#include <QAction>
#include <QApplication>
@ -1494,7 +1495,7 @@ void BitcoinGUI::setAdditionalDataSyncProgress(double nSyncProgress)
progressBar->setToolTip(tooltip);
}
void BitcoinGUI::message(const QString& title, QString message, unsigned int style, bool* ret)
void BitcoinGUI::message(const QString& title, QString message, unsigned int style, bool* ret, const QString& detailed_message)
{
// Default title. On macOS, the window title is ignored (as required by the macOS Guidelines).
QString strTitle{PACKAGE_NAME};
@ -1548,6 +1549,7 @@ void BitcoinGUI::message(const QString& title, QString message, unsigned int sty
showNormalIfMinimized();
QMessageBox mBox(static_cast<QMessageBox::Icon>(nMBoxIcon), strTitle, message, buttons, this);
mBox.setTextFormat(Qt::PlainText);
mBox.setDetailedText(detailed_message);
int r = mBox.exec();
if (ret != nullptr)
*ret = r == QMessageBox::Ok;
@ -1925,20 +1927,27 @@ void BitcoinGUI::showModalOverlay()
modalOverlay->toggleVisibility();
}
static bool ThreadSafeMessageBox(BitcoinGUI* gui, const std::string& message, const std::string& caption, unsigned int style)
static bool ThreadSafeMessageBox(BitcoinGUI* gui, const bilingual_str& message, const std::string& caption, unsigned int style)
{
bool modal = (style & CClientUIInterface::MODAL);
// The SECURE flag has no effect in the Qt GUI.
// bool secure = (style & CClientUIInterface::SECURE);
style &= ~CClientUIInterface::SECURE;
bool ret = false;
QString detailed_message; // This is original message, in English, for googling and referencing.
if (message.original != message.translated) {
detailed_message = BitcoinGUI::tr("Original message:") + "\n" + QString::fromStdString(message.original);
}
// In case of modal message, use blocking connection to wait for user to click a button
bool invoked = QMetaObject::invokeMethod(gui, "message",
modal ? GUIUtil::blockingGUIThreadConnection() : Qt::QueuedConnection,
Q_ARG(QString, QString::fromStdString(caption)),
Q_ARG(QString, QString::fromStdString(message)),
Q_ARG(QString, QString::fromStdString(message.translated)),
Q_ARG(unsigned int, style),
Q_ARG(bool*, &ret));
Q_ARG(bool*, &ret),
Q_ARG(QString, detailed_message));
assert(invoked);
return ret;
}

View File

@ -262,8 +262,9 @@ public Q_SLOTS:
@param[in] style modality and style definitions (icon and used buttons - buttons only for message boxes)
@see CClientUIInterface::MessageBoxFlags
@param[in] ret pointer to a bool that will be modified to whether Ok was clicked (modal only)
@param[in] detailed_message the text to be displayed in the details area
*/
void message(const QString& title, QString message, unsigned int style, bool* ret = nullptr);
void message(const QString& title, QString message, unsigned int style, bool* ret = nullptr, const QString& detailed_message = QString());
#ifdef ENABLE_WALLET
void setCurrentWallet(WalletModel* wallet_model);

View File

@ -101,8 +101,8 @@ void AddTimeData(const CNetAddr& ip, int64_t nOffsetSample)
if (!fMatch)
{
fDone = true;
std::string strMessage = strprintf(_("Please check that your computer's date and time are correct! If your clock is wrong, %s will not work properly.").translated, PACKAGE_NAME);
SetMiscWarning(strMessage);
bilingual_str strMessage = strprintf(_("Please check that your computer's date and time are correct! If your clock is wrong, %s will not work properly."), PACKAGE_NAME);
SetMiscWarning(strMessage.translated);
uiInterface.ThreadSafeMessageBox(strMessage, "", CClientUIInterface::MSG_WARNING);
}
}

View File

@ -4,6 +4,8 @@
#include <ui_interface.h>
#include <util/translation.h>
#include <boost/signals2/last_value.hpp>
#include <boost/signals2/signal.hpp>
@ -48,8 +50,8 @@ ADD_SIGNALS_IMPL_WRAPPER(NotifyMasternodeListChanged);
ADD_SIGNALS_IMPL_WRAPPER(NotifyAdditionalDataSyncProgressChanged);
ADD_SIGNALS_IMPL_WRAPPER(BannedListChanged);
bool CClientUIInterface::ThreadSafeMessageBox(const std::string& message, const std::string& caption, unsigned int style) { return g_ui_signals.ThreadSafeMessageBox(message, caption, style); }
bool CClientUIInterface::ThreadSafeQuestion(const std::string& message, const std::string& non_interactive_message, const std::string& caption, unsigned int style) { return g_ui_signals.ThreadSafeQuestion(message, non_interactive_message, caption, style); }
bool CClientUIInterface::ThreadSafeMessageBox(const bilingual_str& message, const std::string& caption, unsigned int style) { return g_ui_signals.ThreadSafeMessageBox(message, caption, style); }
bool CClientUIInterface::ThreadSafeQuestion(const bilingual_str& message, const std::string& non_interactive_message, const std::string& caption, unsigned int style) { return g_ui_signals.ThreadSafeQuestion(message, non_interactive_message, caption, style); }
void CClientUIInterface::InitMessage(const std::string& message) { return g_ui_signals.InitMessage(message); }
void CClientUIInterface::NotifyNumConnectionsChanged(int newNumConnections) { return g_ui_signals.NotifyNumConnectionsChanged(newNumConnections); }
void CClientUIInterface::NotifyNetworkActiveChanged(bool networkActive) { return g_ui_signals.NotifyNetworkActiveChanged(networkActive); }
@ -63,8 +65,7 @@ void CClientUIInterface::NotifyMasternodeListChanged(const CDeterministicMNList&
void CClientUIInterface::NotifyAdditionalDataSyncProgressChanged(double nSyncProgress) { return g_ui_signals.NotifyAdditionalDataSyncProgressChanged(nSyncProgress); }
void CClientUIInterface::BannedListChanged() { return g_ui_signals.BannedListChanged(); }
bool InitError(const std::string& str)
bool InitError(const bilingual_str& str)
{
uiInterface.ThreadSafeMessageBox(str, "", CClientUIInterface::MSG_ERROR);
return false;
@ -72,5 +73,5 @@ bool InitError(const std::string& str)
void InitWarning(const std::string& str)
{
uiInterface.ThreadSafeMessageBox(str, "", CClientUIInterface::MSG_WARNING);
uiInterface.ThreadSafeMessageBox(Untranslated(str), "", CClientUIInterface::MSG_WARNING);
}

View File

@ -11,7 +11,10 @@
#include <string>
class CBlockIndex;
struct bilingual_str;
class CDeterministicMNList;
namespace boost {
namespace signals2 {
class connection;
@ -87,10 +90,10 @@ public:
boost::signals2::connection signal_name##_connect(std::function<signal_name##Sig> fn);
/** Show message box. */
ADD_SIGNALS_DECL_WRAPPER(ThreadSafeMessageBox, bool, const std::string& message, const std::string& caption, unsigned int style);
ADD_SIGNALS_DECL_WRAPPER(ThreadSafeMessageBox, bool, const bilingual_str& message, const std::string& caption, unsigned int style);
/** If possible, ask the user a question. If not, falls back to ThreadSafeMessageBox(noninteractive_message, caption, style) and returns false. */
ADD_SIGNALS_DECL_WRAPPER(ThreadSafeQuestion, bool, const std::string& message, const std::string& noninteractive_message, const std::string& caption, unsigned int style);
ADD_SIGNALS_DECL_WRAPPER(ThreadSafeQuestion, bool, const bilingual_str& message, const std::string& noninteractive_message, const std::string& caption, unsigned int style);
/** Progress message during initialization. */
ADD_SIGNALS_DECL_WRAPPER(InitMessage, void, const std::string& message);
@ -135,10 +138,11 @@ public:
};
/** Show warning message **/
// TODO: InitWarning() should take a bilingual_str parameter.
void InitWarning(const std::string& str);
/** Show error message **/
bool InitError(const std::string& str);
bool InitError(const bilingual_str& str);
extern CClientUIInterface uiInterface;

View File

@ -27,11 +27,11 @@ inline bilingual_str operator+(const bilingual_str& lhs, const bilingual_str& rh
}
/** Mark a bilingual_str as untranslated */
inline static bilingual_str Untranslated(std::string original) { return {original, original}; }
inline bilingual_str Untranslated(std::string original) { return {original, original}; }
/** Unary operator to return the original */
inline static std::string OpOriginal(const bilingual_str& b) { return b.original; }
inline std::string OpOriginal(const bilingual_str& b) { return b.original; }
/** Unary operator to return the translation */
inline static std::string OpTranslated(const bilingual_str& b) { return b.translated; }
inline std::string OpTranslated(const bilingual_str& b) { return b.translated; }
namespace tinyformat {
template <typename... Args>

View File

@ -1574,14 +1574,15 @@ bool UndoReadFromDisk(CBlockUndo& blockundo, const CBlockIndex* pindex)
}
/** Abort with a message */
// TODO: AbortNode() should take bilingual_str userMessage parameter.
static bool AbortNode(const std::string& strMessage, const std::string& userMessage = "", unsigned int prefix = 0)
{
SetMiscWarning(strMessage);
LogPrintf("*** %s\n", strMessage);
if (!userMessage.empty()) {
uiInterface.ThreadSafeMessageBox(userMessage, "", CClientUIInterface::MSG_ERROR | prefix);
uiInterface.ThreadSafeMessageBox(Untranslated(userMessage), "", CClientUIInterface::MSG_ERROR | prefix);
} else {
uiInterface.ThreadSafeMessageBox(_("Error: A fatal internal error occurred, see debug.log for details").translated, "", CClientUIInterface::MSG_ERROR | CClientUIInterface::MSG_NOPREFIX);
uiInterface.ThreadSafeMessageBox(_("Error: A fatal internal error occurred, see debug.log for details"), "", CClientUIInterface::MSG_ERROR | CClientUIInterface::MSG_NOPREFIX);
}
StartShutdown();
return false;

View File

@ -102,7 +102,7 @@ bool WalletInit::ParameterInteraction() const
return true;
} else if (gArgs.IsArgSet("-masternodeblsprivkey")) {
return InitError(_("You can not start a masternode with wallet enabled.").translated);
return InitError(_("You can not start a masternode with wallet enabled."));
}
const bool is_multiwallet = gArgs.GetArgs("-wallet").size() > 1;
@ -120,7 +120,7 @@ bool WalletInit::ParameterInteraction() const
// -zapwallettxes implies a rescan
if (zapwallettxes) {
if (is_multiwallet) {
return InitError(strprintf("%s is only allowed with a single wallet file", "-zapwallettxes"));
return InitError(strprintf(Untranslated("%s is only allowed with a single wallet file"), "-zapwallettxes"));
}
if (gArgs.SoftSetBoolArg("-rescan", true)) {
LogPrintf("%s: parameter interaction: -zapwallettxes enabled -> setting -rescan=1\n", __func__);
@ -136,14 +136,14 @@ bool WalletInit::ParameterInteraction() const
if (is_multiwallet) {
if (gArgs.GetBoolArg("-upgradewallet", false)) {
return InitError(strprintf("%s is only allowed with a single wallet file", "-upgradewallet"));
return InitError(strprintf(_("%s is only allowed with a single wallet file"), "-upgradewallet"));
}
}
if (gArgs.GetBoolArg("-sysperms", false))
return InitError("-sysperms is not allowed in combination with enabled wallet functionality");
return InitError(Untranslated("-sysperms is not allowed in combination with enabled wallet functionality"));
if (gArgs.GetArg("-prune", 0) && gArgs.GetBoolArg("-rescan", false))
return InitError(_("Rescans are not possible in pruned mode. You will need to use -reindex which will download the whole blockchain again.").translated);
return InitError(_("Rescans are not possible in pruned mode. You will need to use -reindex which will download the whole blockchain again."));
if (gArgs.IsArgSet("-walletbackupsdir")) {
if (!fs::is_directory(gArgs.GetArg("-walletbackupsdir", ""))) {
@ -226,7 +226,7 @@ bool WalletInit::ParameterInteraction() const
// end PrivateSend -> CoinJoin migration
if (gArgs.GetArg("-coinjoindenomshardcap", DEFAULT_COINJOIN_DENOMS_HARDCAP) < gArgs.GetArg("-coinjoindenomsgoal", DEFAULT_COINJOIN_DENOMS_GOAL)) {
return InitError(strprintf(_("%s can't be lower than %s").translated, "-coinjoindenomshardcap", "-coinjoindenomsgoal"));
return InitError(strprintf(_("%s can't be lower than %s"), "-coinjoindenomshardcap", "-coinjoindenomsgoal"));
}
return true;

View File

@ -23,14 +23,14 @@ bool VerifyWallets(interfaces::Chain& chain, const std::vector<std::string>& wal
// The canonical path cleans the path, preventing >1 Berkeley environment instances for the same directory
fs::path canonical_wallet_dir = fs::canonical(wallet_dir, error);
if (error || !fs::exists(wallet_dir)) {
chain.initError(strprintf(_("Specified -walletdir \"%s\" does not exist").translated, wallet_dir.string()));
chain.initError(strprintf(_("Specified -walletdir \"%s\" does not exist"), wallet_dir.string()));
return false;
} else if (!fs::is_directory(wallet_dir)) {
chain.initError(strprintf(_("Specified -walletdir \"%s\" is not a directory").translated, wallet_dir.string()));
chain.initError(strprintf(_("Specified -walletdir \"%s\" is not a directory"), wallet_dir.string()));
return false;
// The canonical path transforms relative paths into absolute ones, so we check the non-canonical version
} else if (!wallet_dir.is_absolute()) {
chain.initError(strprintf(_("Specified -walletdir \"%s\" is a relative path").translated, wallet_dir.string()));
chain.initError(strprintf(_("Specified -walletdir \"%s\" is a relative path"), wallet_dir.string()));
return false;
}
gArgs.ForceSetArg("-walletdir", canonical_wallet_dir.string());
@ -47,7 +47,7 @@ bool VerifyWallets(interfaces::Chain& chain, const std::vector<std::string>& wal
WalletLocation location(wallet_file);
if (!wallet_paths.insert(location.GetPath()).second) {
chain.initError(strprintf(_("Error loading wallet %s. Duplicate -wallet filename specified.").translated, wallet_file));
chain.initError(strprintf(_("Error loading wallet %s. Duplicate -wallet filename specified."), wallet_file));
return false;
}
@ -56,7 +56,7 @@ bool VerifyWallets(interfaces::Chain& chain, const std::vector<std::string>& wal
bool verify_success = CWallet::Verify(chain, location, error_string, warnings);
if (!warnings.empty()) chain.initWarning(Join(warnings, "\n", OpTranslated));
if (!verify_success) {
chain.initError(error_string.translated);
chain.initError(error_string);
return false;
}
}
@ -72,7 +72,7 @@ bool LoadWallets(interfaces::Chain& chain, const std::vector<std::string>& walle
std::shared_ptr<CWallet> pwallet = CWallet::CreateWalletFromFile(chain, WalletLocation(walletFile), error_string, warnings);
if (!warnings.empty()) chain.initWarning(Join(warnings, "\n", OpTranslated));
if (!pwallet) {
chain.initError(error_string.translated);
chain.initError(error_string);
return false;
}
}