diff --git a/apitest/src/main/java/bisq/apitest/linux/BitcoinDaemon.java b/apitest/src/main/java/bisq/apitest/linux/BitcoinDaemon.java index cc2e495200..4deaa8863c 100644 --- a/apitest/src/main/java/bisq/apitest/linux/BitcoinDaemon.java +++ b/apitest/src/main/java/bisq/apitest/linux/BitcoinDaemon.java @@ -59,7 +59,7 @@ public class BitcoinDaemon extends AbstractLinuxProcess implements LinuxProcess + " -rpcport=" + config.bitcoinRpcPort + " -rpcuser=" + config.bitcoinRpcUser + " -rpcpassword=" + config.bitcoinRpcPassword - + " -blocknotify=" + config.bitcoinDatadir + "/blocknotify"; + + " -blocknotify=" + "\"" + config.bitcoinDatadir + "/blocknotify" + " %s\""; BashCommand cmd = new BashCommand(bitcoindCmd).run(); log.info("Starting ...\n$ {}", cmd.getCommand()); diff --git a/apitest/src/test/java/bisq/apitest/ApiTestCase.java b/apitest/src/test/java/bisq/apitest/ApiTestCase.java index 7d1f4ddf01..6c7a9f8286 100644 --- a/apitest/src/test/java/bisq/apitest/ApiTestCase.java +++ b/apitest/src/test/java/bisq/apitest/ApiTestCase.java @@ -19,7 +19,6 @@ package bisq.apitest; import java.net.InetAddress; -import java.io.File; import java.io.IOException; import java.util.HashMap; @@ -73,16 +72,6 @@ public class ApiTestCase { // gRPC service stubs are used by method & scenario tests, but not e2e tests. private static final Map grpcStubsCache = new HashMap<>(); - public static void setUpScaffold(File callRateMeteringConfigFile, - Enum... supportingApps) - throws InterruptedException, ExecutionException, IOException { - scaffold = new Scaffold(stream(supportingApps).map(Enum::name) - .collect(Collectors.joining(","))) - .setUp(); - config = scaffold.config; - bitcoinCli = new BitcoinCliHelper((config)); - } - public static void setUpScaffold(Enum... supportingApps) throws InterruptedException, ExecutionException, IOException { scaffold = new Scaffold(stream(supportingApps).map(Enum::name) @@ -107,6 +96,10 @@ public class ApiTestCase { scaffold.tearDown(); } + protected static String getEnumArrayAsString(Enum[] supportingApps) { + return stream(supportingApps).map(Enum::name).collect(Collectors.joining(",")); + } + protected static GrpcStubs grpcStubs(BisqAppConfig bisqAppConfig) { if (grpcStubsCache.containsKey(bisqAppConfig)) { return grpcStubsCache.get(bisqAppConfig); diff --git a/apitest/src/test/java/bisq/apitest/method/MethodTest.java b/apitest/src/test/java/bisq/apitest/method/MethodTest.java index da078e1efc..f4fd94b517 100644 --- a/apitest/src/test/java/bisq/apitest/method/MethodTest.java +++ b/apitest/src/test/java/bisq/apitest/method/MethodTest.java @@ -19,6 +19,7 @@ package bisq.apitest.method; import bisq.core.api.model.PaymentAccountForm; import bisq.core.api.model.TxFeeRateInfo; +import bisq.core.payment.F2FAccount; import bisq.core.proto.CoreProtoResolver; import bisq.common.util.Utilities; @@ -34,6 +35,7 @@ import bisq.proto.grpc.CreatePaymentAccountRequest; import bisq.proto.grpc.GetAddressBalanceRequest; import bisq.proto.grpc.GetBalancesRequest; import bisq.proto.grpc.GetFundingAddressesRequest; +import bisq.proto.grpc.GetMyOfferRequest; import bisq.proto.grpc.GetOfferRequest; import bisq.proto.grpc.GetPaymentAccountFormRequest; import bisq.proto.grpc.GetPaymentAccountsRequest; @@ -133,9 +135,9 @@ public class MethodTest extends ApiTestCase { } } - private static void doPostStartup(boolean registerDisputeAgents, - boolean generateBtcBlock, - Enum... supportingApps) { + protected static void doPostStartup(boolean registerDisputeAgents, + boolean generateBtcBlock, + Enum... supportingApps) { if (registerDisputeAgents) { registerDisputeAgents(arbdaemon); } @@ -223,6 +225,10 @@ public class MethodTest extends ApiTestCase { return GetOfferRequest.newBuilder().setId(offerId).build(); } + protected final GetMyOfferRequest createGetMyOfferRequest(String offerId) { + return GetMyOfferRequest.newBuilder().setId(offerId).build(); + } + protected final CancelOfferRequest createCancelOfferRequest(String offerId) { return CancelOfferRequest.newBuilder().setId(offerId).build(); } @@ -401,6 +407,11 @@ public class MethodTest extends ApiTestCase { return grpcStubs(bisqAppConfig).offersService.getOffer(req).getOffer(); } + protected final OfferInfo getMyOffer(BisqAppConfig bisqAppConfig, String offerId) { + var req = createGetMyOfferRequest(offerId); + return grpcStubs(bisqAppConfig).offersService.getMyOffer(req).getOffer(); + } + @SuppressWarnings("ResultOfMethodCallIgnored") protected final void cancelOffer(BisqAppConfig bisqAppConfig, String offerId) { var req = createCancelOfferRequest(offerId); @@ -464,6 +475,21 @@ public class MethodTest extends ApiTestCase { return grpcStubs(bisqAppConfig).walletsService.getTransaction(req).getTxInfo(); } + public bisq.core.payment.PaymentAccount createDummyF2FAccount(BisqAppConfig bisqAppConfig, + String countryCode) { + String f2fAccountJsonString = "{\n" + + " \"_COMMENTS_\": \"This is a dummy account.\",\n" + + " \"paymentMethodId\": \"F2F\",\n" + + " \"accountName\": \"Dummy " + countryCode.toUpperCase() + " F2F Account\",\n" + + " \"city\": \"Anytown\",\n" + + " \"contact\": \"Morse Code\",\n" + + " \"country\": \"" + countryCode.toUpperCase() + "\",\n" + + " \"extraInfo\": \"Salt Lick #213\"\n" + + "}\n"; + F2FAccount f2FAccount = (F2FAccount) createPaymentAccount(bisqAppConfig, f2fAccountJsonString); + return f2FAccount; + } + // Static conveniences for test methods and test case fixture setups. protected static RegisterDisputeAgentRequest createRegisterDisputeAgentRequest(String disputeAgentType) { diff --git a/apitest/src/test/java/bisq/apitest/method/offer/AbstractOfferTest.java b/apitest/src/test/java/bisq/apitest/method/offer/AbstractOfferTest.java index cd9a5771a8..84242c1087 100644 --- a/apitest/src/test/java/bisq/apitest/method/offer/AbstractOfferTest.java +++ b/apitest/src/test/java/bisq/apitest/method/offer/AbstractOfferTest.java @@ -18,13 +18,13 @@ package bisq.apitest.method.offer; import bisq.core.monetary.Altcoin; +import bisq.core.payment.PaymentAccount; import bisq.proto.grpc.CreateOfferRequest; +import bisq.proto.grpc.GetMyOffersRequest; import bisq.proto.grpc.GetOffersRequest; import bisq.proto.grpc.OfferInfo; -import protobuf.PaymentAccount; - import org.bitcoinj.utils.Fiat; import java.math.BigDecimal; @@ -121,6 +121,10 @@ public abstract class AbstractOfferTest extends MethodTest { return aliceStubs.offersService.getOffer(createGetOfferRequest(offerId)).getOffer(); } + protected final OfferInfo getMyOffer(String offerId) { + return aliceStubs.offersService.getMyOffer(createGetMyOfferRequest(offerId)).getOffer(); + } + @SuppressWarnings("ResultOfMethodCallIgnored") protected final void cancelOffer(GrpcStubs grpcStubs, String offerId) { grpcStubs.offersService.cancelOffer(createCancelOfferRequest(offerId)); @@ -134,11 +138,9 @@ public abstract class AbstractOfferTest extends MethodTest { return offerInfoList.get(offerInfoList.size() - 1); } - protected final int getOpenOffersCount(GrpcStubs grpcStubs, String direction, String currencyCode) { - return getOffersSortedByDate(grpcStubs, direction, currencyCode).size(); - } - - protected final List getOffersSortedByDate(GrpcStubs grpcStubs, String direction, String currencyCode) { + protected final List getOffersSortedByDate(GrpcStubs grpcStubs, + String direction, + String currencyCode) { var req = GetOffersRequest.newBuilder() .setDirection(direction) .setCurrencyCode(currencyCode).build(); @@ -146,6 +148,16 @@ public abstract class AbstractOfferTest extends MethodTest { return sortOffersByDate(reply.getOffersList()); } + protected final List getMyOffersSortedByDate(GrpcStubs grpcStubs, + String direction, + String currencyCode) { + var req = GetMyOffersRequest.newBuilder() + .setDirection(direction) + .setCurrencyCode(currencyCode).build(); + var reply = grpcStubs.offersService.getMyOffers(req); + return sortOffersByDate(reply.getOffersList()); + } + protected final List sortOffersByDate(List offerInfoList) { return offerInfoList.stream() .sorted(comparing(OfferInfo::getDate)) diff --git a/apitest/src/test/java/bisq/apitest/method/offer/CancelOfferTest.java b/apitest/src/test/java/bisq/apitest/method/offer/CancelOfferTest.java index 8ec90aedad..9be112e16b 100644 --- a/apitest/src/test/java/bisq/apitest/method/offer/CancelOfferTest.java +++ b/apitest/src/test/java/bisq/apitest/method/offer/CancelOfferTest.java @@ -18,6 +18,7 @@ package bisq.apitest.method.offer; import bisq.core.btc.wallet.Restrictions; +import bisq.core.payment.PaymentAccount; import bisq.proto.grpc.CreateOfferRequest; import bisq.proto.grpc.OfferInfo; @@ -32,6 +33,7 @@ import org.junit.jupiter.api.Order; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.TestMethodOrder; +import static bisq.apitest.config.BisqAppConfig.alicedaemon; import static org.junit.jupiter.api.Assertions.assertEquals; @Disabled @@ -39,15 +41,18 @@ import static org.junit.jupiter.api.Assertions.assertEquals; @TestMethodOrder(MethodOrderer.OrderAnnotation.class) public class CancelOfferTest extends AbstractOfferTest { + private static final String DIRECTION = "buy"; + private static final String CURRENCY_CODE = "cad"; private static final int MAX_OFFERS = 3; @Test @Order(1) public void testCancelOffer() { + PaymentAccount cadAccount = createDummyF2FAccount(alicedaemon, "CA"); var req = CreateOfferRequest.newBuilder() - .setPaymentAccountId(alicesDummyAcct.getId()) - .setDirection("buy") - .setCurrencyCode("cad") + .setPaymentAccountId(cadAccount.getId()) + .setDirection(DIRECTION) + .setCurrencyCode(CURRENCY_CODE) .setAmount(10000000) .setMinAmount(10000000) .setUseMarketBasedPrice(true) @@ -66,18 +71,19 @@ public class CancelOfferTest extends AbstractOfferTest { sleep(2500); } - List offers = getOffersSortedByDate(aliceStubs, "buy", "cad"); + List offers = getMyOffersSortedByDate(aliceStubs, DIRECTION, CURRENCY_CODE); assertEquals(MAX_OFFERS, offers.size()); // Cancel the offers, checking the open offer count after each offer removal. for (int i = 1; i <= MAX_OFFERS; i++) { cancelOffer(aliceStubs, offers.remove(0).getId()); - assertEquals(MAX_OFFERS - i, getOpenOffersCount(aliceStubs, "buy", "cad")); + offers = getMyOffersSortedByDate(aliceStubs, DIRECTION, CURRENCY_CODE); + assertEquals(MAX_OFFERS - i, offers.size()); } sleep(1000); // wait for offer removal - offers = getOffersSortedByDate(aliceStubs, "buy", "cad"); + offers = getMyOffersSortedByDate(aliceStubs, DIRECTION, CURRENCY_CODE); assertEquals(0, offers.size()); } } diff --git a/apitest/src/test/java/bisq/apitest/method/offer/CreateOfferUsingFixedPriceTest.java b/apitest/src/test/java/bisq/apitest/method/offer/CreateOfferUsingFixedPriceTest.java index daa85d5e8e..8f43660914 100644 --- a/apitest/src/test/java/bisq/apitest/method/offer/CreateOfferUsingFixedPriceTest.java +++ b/apitest/src/test/java/bisq/apitest/method/offer/CreateOfferUsingFixedPriceTest.java @@ -17,7 +17,7 @@ package bisq.apitest.method.offer; -import bisq.core.btc.wallet.Restrictions; +import bisq.core.payment.PaymentAccount; import bisq.proto.grpc.CreateOfferRequest; @@ -29,6 +29,8 @@ import org.junit.jupiter.api.Order; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.TestMethodOrder; +import static bisq.apitest.config.BisqAppConfig.alicedaemon; +import static bisq.core.btc.wallet.Restrictions.getDefaultBuyerSecurityDepositAsPercent; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertNotEquals; @@ -43,16 +45,17 @@ public class CreateOfferUsingFixedPriceTest extends AbstractOfferTest { @Test @Order(1) public void testCreateAUDBTCBuyOfferUsingFixedPrice16000() { + PaymentAccount audAccount = createDummyF2FAccount(alicedaemon, "AU"); var req = CreateOfferRequest.newBuilder() - .setPaymentAccountId(alicesDummyAcct.getId()) + .setPaymentAccountId(audAccount.getId()) .setDirection("buy") .setCurrencyCode("aud") .setAmount(10000000) .setMinAmount(10000000) .setUseMarketBasedPrice(false) .setMarketPriceMargin(0.00) - .setPrice("16000") - .setBuyerSecurityDeposit(Restrictions.getDefaultBuyerSecurityDepositAsPercent()) + .setPrice("36000") + .setBuyerSecurityDeposit(getDefaultBuyerSecurityDepositAsPercent()) .setMakerFeeCurrencyCode(MAKER_FEE_CURRENCY_CODE) .build(); var newOffer = aliceStubs.offersService.createOffer(req).getOffer(); @@ -60,24 +63,24 @@ public class CreateOfferUsingFixedPriceTest extends AbstractOfferTest { assertNotEquals("", newOfferId); assertEquals("BUY", newOffer.getDirection()); assertFalse(newOffer.getUseMarketBasedPrice()); - assertEquals(160000000, newOffer.getPrice()); + assertEquals(360000000, newOffer.getPrice()); assertEquals(10000000, newOffer.getAmount()); assertEquals(10000000, newOffer.getMinAmount()); assertEquals(1500000, newOffer.getBuyerSecurityDeposit()); - assertEquals(alicesDummyAcct.getId(), newOffer.getPaymentAccountId()); + assertEquals(audAccount.getId(), newOffer.getPaymentAccountId()); assertEquals("BTC", newOffer.getBaseCurrencyCode()); assertEquals("AUD", newOffer.getCounterCurrencyCode()); assertFalse(newOffer.getIsCurrencyForMakerFeeBtc()); - newOffer = getOffer(newOfferId); + newOffer = getMyOffer(newOfferId); assertEquals(newOfferId, newOffer.getId()); assertEquals("BUY", newOffer.getDirection()); assertFalse(newOffer.getUseMarketBasedPrice()); - assertEquals(160000000, newOffer.getPrice()); + assertEquals(360000000, newOffer.getPrice()); assertEquals(10000000, newOffer.getAmount()); assertEquals(10000000, newOffer.getMinAmount()); assertEquals(1500000, newOffer.getBuyerSecurityDeposit()); - assertEquals(alicesDummyAcct.getId(), newOffer.getPaymentAccountId()); + assertEquals(audAccount.getId(), newOffer.getPaymentAccountId()); assertEquals("BTC", newOffer.getBaseCurrencyCode()); assertEquals("AUD", newOffer.getCounterCurrencyCode()); assertFalse(newOffer.getIsCurrencyForMakerFeeBtc()); @@ -86,16 +89,17 @@ public class CreateOfferUsingFixedPriceTest extends AbstractOfferTest { @Test @Order(2) public void testCreateUSDBTCBuyOfferUsingFixedPrice100001234() { + PaymentAccount usdAccount = createDummyF2FAccount(alicedaemon, "US"); var req = CreateOfferRequest.newBuilder() - .setPaymentAccountId(alicesDummyAcct.getId()) + .setPaymentAccountId(usdAccount.getId()) .setDirection("buy") .setCurrencyCode("usd") .setAmount(10000000) .setMinAmount(10000000) .setUseMarketBasedPrice(false) .setMarketPriceMargin(0.00) - .setPrice("10000.1234") - .setBuyerSecurityDeposit(Restrictions.getDefaultBuyerSecurityDepositAsPercent()) + .setPrice("30000.1234") + .setBuyerSecurityDeposit(getDefaultBuyerSecurityDepositAsPercent()) .setMakerFeeCurrencyCode(MAKER_FEE_CURRENCY_CODE) .build(); var newOffer = aliceStubs.offersService.createOffer(req).getOffer(); @@ -103,24 +107,24 @@ public class CreateOfferUsingFixedPriceTest extends AbstractOfferTest { assertNotEquals("", newOfferId); assertEquals("BUY", newOffer.getDirection()); assertFalse(newOffer.getUseMarketBasedPrice()); - assertEquals(100001234, newOffer.getPrice()); + assertEquals(300001234, newOffer.getPrice()); assertEquals(10000000, newOffer.getAmount()); assertEquals(10000000, newOffer.getMinAmount()); assertEquals(1500000, newOffer.getBuyerSecurityDeposit()); - assertEquals(alicesDummyAcct.getId(), newOffer.getPaymentAccountId()); + assertEquals(usdAccount.getId(), newOffer.getPaymentAccountId()); assertEquals("BTC", newOffer.getBaseCurrencyCode()); assertEquals("USD", newOffer.getCounterCurrencyCode()); assertFalse(newOffer.getIsCurrencyForMakerFeeBtc()); - newOffer = getOffer(newOfferId); + newOffer = getMyOffer(newOfferId); assertEquals(newOfferId, newOffer.getId()); assertEquals("BUY", newOffer.getDirection()); assertFalse(newOffer.getUseMarketBasedPrice()); - assertEquals(100001234, newOffer.getPrice()); + assertEquals(300001234, newOffer.getPrice()); assertEquals(10000000, newOffer.getAmount()); assertEquals(10000000, newOffer.getMinAmount()); assertEquals(1500000, newOffer.getBuyerSecurityDeposit()); - assertEquals(alicesDummyAcct.getId(), newOffer.getPaymentAccountId()); + assertEquals(usdAccount.getId(), newOffer.getPaymentAccountId()); assertEquals("BTC", newOffer.getBaseCurrencyCode()); assertEquals("USD", newOffer.getCounterCurrencyCode()); assertFalse(newOffer.getIsCurrencyForMakerFeeBtc()); @@ -129,16 +133,17 @@ public class CreateOfferUsingFixedPriceTest extends AbstractOfferTest { @Test @Order(3) public void testCreateEURBTCSellOfferUsingFixedPrice95001234() { + PaymentAccount eurAccount = createDummyF2FAccount(alicedaemon, "FR"); var req = CreateOfferRequest.newBuilder() - .setPaymentAccountId(alicesDummyAcct.getId()) + .setPaymentAccountId(eurAccount.getId()) .setDirection("sell") .setCurrencyCode("eur") .setAmount(10000000) .setMinAmount(10000000) .setUseMarketBasedPrice(false) .setMarketPriceMargin(0.00) - .setPrice("9500.1234") - .setBuyerSecurityDeposit(Restrictions.getDefaultBuyerSecurityDepositAsPercent()) + .setPrice("29500.1234") + .setBuyerSecurityDeposit(getDefaultBuyerSecurityDepositAsPercent()) .setMakerFeeCurrencyCode(MAKER_FEE_CURRENCY_CODE) .build(); var newOffer = aliceStubs.offersService.createOffer(req).getOffer(); @@ -146,24 +151,24 @@ public class CreateOfferUsingFixedPriceTest extends AbstractOfferTest { assertNotEquals("", newOfferId); assertEquals("SELL", newOffer.getDirection()); assertFalse(newOffer.getUseMarketBasedPrice()); - assertEquals(95001234, newOffer.getPrice()); + assertEquals(295001234, newOffer.getPrice()); assertEquals(10000000, newOffer.getAmount()); assertEquals(10000000, newOffer.getMinAmount()); assertEquals(1500000, newOffer.getBuyerSecurityDeposit()); - assertEquals(alicesDummyAcct.getId(), newOffer.getPaymentAccountId()); + assertEquals(eurAccount.getId(), newOffer.getPaymentAccountId()); assertEquals("BTC", newOffer.getBaseCurrencyCode()); assertEquals("EUR", newOffer.getCounterCurrencyCode()); assertFalse(newOffer.getIsCurrencyForMakerFeeBtc()); - newOffer = getOffer(newOfferId); + newOffer = getMyOffer(newOfferId); assertEquals(newOfferId, newOffer.getId()); assertEquals("SELL", newOffer.getDirection()); assertFalse(newOffer.getUseMarketBasedPrice()); - assertEquals(95001234, newOffer.getPrice()); + assertEquals(295001234, newOffer.getPrice()); assertEquals(10000000, newOffer.getAmount()); assertEquals(10000000, newOffer.getMinAmount()); assertEquals(1500000, newOffer.getBuyerSecurityDeposit()); - assertEquals(alicesDummyAcct.getId(), newOffer.getPaymentAccountId()); + assertEquals(eurAccount.getId(), newOffer.getPaymentAccountId()); assertEquals("BTC", newOffer.getBaseCurrencyCode()); assertEquals("EUR", newOffer.getCounterCurrencyCode()); assertFalse(newOffer.getIsCurrencyForMakerFeeBtc()); diff --git a/apitest/src/test/java/bisq/apitest/method/offer/CreateOfferUsingMarketPriceMarginTest.java b/apitest/src/test/java/bisq/apitest/method/offer/CreateOfferUsingMarketPriceMarginTest.java index dbf712c935..30dfaca4ac 100644 --- a/apitest/src/test/java/bisq/apitest/method/offer/CreateOfferUsingMarketPriceMarginTest.java +++ b/apitest/src/test/java/bisq/apitest/method/offer/CreateOfferUsingMarketPriceMarginTest.java @@ -17,7 +17,7 @@ package bisq.apitest.method.offer; -import bisq.core.btc.wallet.Restrictions; +import bisq.core.payment.PaymentAccount; import bisq.proto.grpc.CreateOfferRequest; import bisq.proto.grpc.OfferInfo; @@ -32,8 +32,10 @@ import org.junit.jupiter.api.Order; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.TestMethodOrder; +import static bisq.apitest.config.BisqAppConfig.alicedaemon; import static bisq.common.util.MathUtils.scaleDownByPowerOf10; import static bisq.common.util.MathUtils.scaleUpByPowerOf10; +import static bisq.core.btc.wallet.Restrictions.getDefaultBuyerSecurityDepositAsPercent; import static java.lang.Math.abs; import static java.lang.String.format; import static org.junit.jupiter.api.Assertions.assertEquals; @@ -55,9 +57,10 @@ public class CreateOfferUsingMarketPriceMarginTest extends AbstractOfferTest { @Test @Order(1) public void testCreateUSDBTCBuyOffer5PctPriceMargin() { + PaymentAccount usdAccount = createDummyF2FAccount(alicedaemon, "US"); double priceMarginPctInput = 5.00; var req = CreateOfferRequest.newBuilder() - .setPaymentAccountId(alicesDummyAcct.getId()) + .setPaymentAccountId(usdAccount.getId()) .setDirection("buy") .setCurrencyCode("usd") .setAmount(10000000) @@ -65,7 +68,7 @@ public class CreateOfferUsingMarketPriceMarginTest extends AbstractOfferTest { .setUseMarketBasedPrice(true) .setMarketPriceMargin(priceMarginPctInput) .setPrice("0") - .setBuyerSecurityDeposit(Restrictions.getDefaultBuyerSecurityDepositAsPercent()) + .setBuyerSecurityDeposit(getDefaultBuyerSecurityDepositAsPercent()) .setMakerFeeCurrencyCode(MAKER_FEE_CURRENCY_CODE) .build(); var newOffer = aliceStubs.offersService.createOffer(req).getOffer(); @@ -76,19 +79,19 @@ public class CreateOfferUsingMarketPriceMarginTest extends AbstractOfferTest { assertEquals(10000000, newOffer.getAmount()); assertEquals(10000000, newOffer.getMinAmount()); assertEquals(1500000, newOffer.getBuyerSecurityDeposit()); - assertEquals(alicesDummyAcct.getId(), newOffer.getPaymentAccountId()); + assertEquals(usdAccount.getId(), newOffer.getPaymentAccountId()); assertEquals("BTC", newOffer.getBaseCurrencyCode()); assertEquals("USD", newOffer.getCounterCurrencyCode()); assertTrue(newOffer.getIsCurrencyForMakerFeeBtc()); - newOffer = getOffer(newOfferId); + newOffer = getMyOffer(newOfferId); assertEquals(newOfferId, newOffer.getId()); assertEquals("BUY", newOffer.getDirection()); assertTrue(newOffer.getUseMarketBasedPrice()); assertEquals(10000000, newOffer.getAmount()); assertEquals(10000000, newOffer.getMinAmount()); assertEquals(1500000, newOffer.getBuyerSecurityDeposit()); - assertEquals(alicesDummyAcct.getId(), newOffer.getPaymentAccountId()); + assertEquals(usdAccount.getId(), newOffer.getPaymentAccountId()); assertEquals("BTC", newOffer.getBaseCurrencyCode()); assertEquals("USD", newOffer.getCounterCurrencyCode()); assertTrue(newOffer.getIsCurrencyForMakerFeeBtc()); @@ -99,9 +102,10 @@ public class CreateOfferUsingMarketPriceMarginTest extends AbstractOfferTest { @Test @Order(2) public void testCreateNZDBTCBuyOfferMinus2PctPriceMargin() { + PaymentAccount nzdAccount = createDummyF2FAccount(alicedaemon, "NZ"); double priceMarginPctInput = -2.00; var req = CreateOfferRequest.newBuilder() - .setPaymentAccountId(alicesDummyAcct.getId()) + .setPaymentAccountId(nzdAccount.getId()) .setDirection("buy") .setCurrencyCode("nzd") .setAmount(10000000) @@ -109,7 +113,7 @@ public class CreateOfferUsingMarketPriceMarginTest extends AbstractOfferTest { .setUseMarketBasedPrice(true) .setMarketPriceMargin(priceMarginPctInput) .setPrice("0") - .setBuyerSecurityDeposit(Restrictions.getDefaultBuyerSecurityDepositAsPercent()) + .setBuyerSecurityDeposit(getDefaultBuyerSecurityDepositAsPercent()) .setMakerFeeCurrencyCode(MAKER_FEE_CURRENCY_CODE) .build(); var newOffer = aliceStubs.offersService.createOffer(req).getOffer(); @@ -120,19 +124,19 @@ public class CreateOfferUsingMarketPriceMarginTest extends AbstractOfferTest { assertEquals(10000000, newOffer.getAmount()); assertEquals(10000000, newOffer.getMinAmount()); assertEquals(1500000, newOffer.getBuyerSecurityDeposit()); - assertEquals(alicesDummyAcct.getId(), newOffer.getPaymentAccountId()); + assertEquals(nzdAccount.getId(), newOffer.getPaymentAccountId()); assertEquals("BTC", newOffer.getBaseCurrencyCode()); assertEquals("NZD", newOffer.getCounterCurrencyCode()); assertTrue(newOffer.getIsCurrencyForMakerFeeBtc()); - newOffer = getOffer(newOfferId); + newOffer = getMyOffer(newOfferId); assertEquals(newOfferId, newOffer.getId()); assertEquals("BUY", newOffer.getDirection()); assertTrue(newOffer.getUseMarketBasedPrice()); assertEquals(10000000, newOffer.getAmount()); assertEquals(10000000, newOffer.getMinAmount()); assertEquals(1500000, newOffer.getBuyerSecurityDeposit()); - assertEquals(alicesDummyAcct.getId(), newOffer.getPaymentAccountId()); + assertEquals(nzdAccount.getId(), newOffer.getPaymentAccountId()); assertEquals("BTC", newOffer.getBaseCurrencyCode()); assertEquals("NZD", newOffer.getCounterCurrencyCode()); assertTrue(newOffer.getIsCurrencyForMakerFeeBtc()); @@ -143,9 +147,10 @@ public class CreateOfferUsingMarketPriceMarginTest extends AbstractOfferTest { @Test @Order(3) public void testCreateGBPBTCSellOfferMinus1Point5PctPriceMargin() { + PaymentAccount gbpAccount = createDummyF2FAccount(alicedaemon, "GB"); double priceMarginPctInput = -1.5; var req = CreateOfferRequest.newBuilder() - .setPaymentAccountId(alicesDummyAcct.getId()) + .setPaymentAccountId(gbpAccount.getId()) .setDirection("sell") .setCurrencyCode("gbp") .setAmount(10000000) @@ -153,7 +158,7 @@ public class CreateOfferUsingMarketPriceMarginTest extends AbstractOfferTest { .setUseMarketBasedPrice(true) .setMarketPriceMargin(priceMarginPctInput) .setPrice("0") - .setBuyerSecurityDeposit(Restrictions.getDefaultBuyerSecurityDepositAsPercent()) + .setBuyerSecurityDeposit(getDefaultBuyerSecurityDepositAsPercent()) .setMakerFeeCurrencyCode(MAKER_FEE_CURRENCY_CODE) .build(); var newOffer = aliceStubs.offersService.createOffer(req).getOffer(); @@ -165,19 +170,19 @@ public class CreateOfferUsingMarketPriceMarginTest extends AbstractOfferTest { assertEquals(10000000, newOffer.getAmount()); assertEquals(10000000, newOffer.getMinAmount()); assertEquals(1500000, newOffer.getBuyerSecurityDeposit()); - assertEquals(alicesDummyAcct.getId(), newOffer.getPaymentAccountId()); + assertEquals(gbpAccount.getId(), newOffer.getPaymentAccountId()); assertEquals("BTC", newOffer.getBaseCurrencyCode()); assertEquals("GBP", newOffer.getCounterCurrencyCode()); assertTrue(newOffer.getIsCurrencyForMakerFeeBtc()); - newOffer = getOffer(newOfferId); + newOffer = getMyOffer(newOfferId); assertEquals(newOfferId, newOffer.getId()); assertEquals("SELL", newOffer.getDirection()); assertTrue(newOffer.getUseMarketBasedPrice()); assertEquals(10000000, newOffer.getAmount()); assertEquals(10000000, newOffer.getMinAmount()); assertEquals(1500000, newOffer.getBuyerSecurityDeposit()); - assertEquals(alicesDummyAcct.getId(), newOffer.getPaymentAccountId()); + assertEquals(gbpAccount.getId(), newOffer.getPaymentAccountId()); assertEquals("BTC", newOffer.getBaseCurrencyCode()); assertEquals("GBP", newOffer.getCounterCurrencyCode()); assertTrue(newOffer.getIsCurrencyForMakerFeeBtc()); @@ -188,9 +193,10 @@ public class CreateOfferUsingMarketPriceMarginTest extends AbstractOfferTest { @Test @Order(4) public void testCreateBRLBTCSellOffer6Point55PctPriceMargin() { + PaymentAccount brlAccount = createDummyF2FAccount(alicedaemon, "BR"); double priceMarginPctInput = 6.55; var req = CreateOfferRequest.newBuilder() - .setPaymentAccountId(alicesDummyAcct.getId()) + .setPaymentAccountId(brlAccount.getId()) .setDirection("sell") .setCurrencyCode("brl") .setAmount(10000000) @@ -198,7 +204,7 @@ public class CreateOfferUsingMarketPriceMarginTest extends AbstractOfferTest { .setUseMarketBasedPrice(true) .setMarketPriceMargin(priceMarginPctInput) .setPrice("0") - .setBuyerSecurityDeposit(Restrictions.getDefaultBuyerSecurityDepositAsPercent()) + .setBuyerSecurityDeposit(getDefaultBuyerSecurityDepositAsPercent()) .setMakerFeeCurrencyCode(MAKER_FEE_CURRENCY_CODE) .build(); var newOffer = aliceStubs.offersService.createOffer(req).getOffer(); @@ -210,19 +216,19 @@ public class CreateOfferUsingMarketPriceMarginTest extends AbstractOfferTest { assertEquals(10000000, newOffer.getAmount()); assertEquals(10000000, newOffer.getMinAmount()); assertEquals(1500000, newOffer.getBuyerSecurityDeposit()); - assertEquals(alicesDummyAcct.getId(), newOffer.getPaymentAccountId()); + assertEquals(brlAccount.getId(), newOffer.getPaymentAccountId()); assertEquals("BTC", newOffer.getBaseCurrencyCode()); assertEquals("BRL", newOffer.getCounterCurrencyCode()); assertTrue(newOffer.getIsCurrencyForMakerFeeBtc()); - newOffer = getOffer(newOfferId); + newOffer = getMyOffer(newOfferId); assertEquals(newOfferId, newOffer.getId()); assertEquals("SELL", newOffer.getDirection()); assertTrue(newOffer.getUseMarketBasedPrice()); assertEquals(10000000, newOffer.getAmount()); assertEquals(10000000, newOffer.getMinAmount()); assertEquals(1500000, newOffer.getBuyerSecurityDeposit()); - assertEquals(alicesDummyAcct.getId(), newOffer.getPaymentAccountId()); + assertEquals(brlAccount.getId(), newOffer.getPaymentAccountId()); assertEquals("BTC", newOffer.getBaseCurrencyCode()); assertEquals("BRL", newOffer.getCounterCurrencyCode()); assertTrue(newOffer.getIsCurrencyForMakerFeeBtc()); diff --git a/apitest/src/test/java/bisq/apitest/method/offer/ValidateCreateOfferTest.java b/apitest/src/test/java/bisq/apitest/method/offer/ValidateCreateOfferTest.java index 0225238b6a..14b935abe4 100644 --- a/apitest/src/test/java/bisq/apitest/method/offer/ValidateCreateOfferTest.java +++ b/apitest/src/test/java/bisq/apitest/method/offer/ValidateCreateOfferTest.java @@ -17,7 +17,7 @@ package bisq.apitest.method.offer; -import bisq.core.btc.wallet.Restrictions; +import bisq.core.payment.PaymentAccount; import bisq.proto.grpc.CreateOfferRequest; @@ -31,6 +31,8 @@ import org.junit.jupiter.api.Order; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.TestMethodOrder; +import static bisq.apitest.config.BisqAppConfig.alicedaemon; +import static bisq.core.btc.wallet.Restrictions.getDefaultBuyerSecurityDepositAsPercent; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertThrows; @@ -42,8 +44,9 @@ public class ValidateCreateOfferTest extends AbstractOfferTest { @Test @Order(1) public void testAmtTooLargeShouldThrowException() { + PaymentAccount usdAccount = createDummyF2FAccount(alicedaemon, "US"); var req = CreateOfferRequest.newBuilder() - .setPaymentAccountId(alicesDummyAcct.getId()) + .setPaymentAccountId(usdAccount.getId()) .setDirection("buy") .setCurrencyCode("usd") .setAmount(100000000000L) @@ -51,7 +54,7 @@ public class ValidateCreateOfferTest extends AbstractOfferTest { .setUseMarketBasedPrice(false) .setMarketPriceMargin(0.00) .setPrice("10000.0000") - .setBuyerSecurityDeposit(Restrictions.getDefaultBuyerSecurityDepositAsPercent()) + .setBuyerSecurityDeposit(getDefaultBuyerSecurityDepositAsPercent()) .setMakerFeeCurrencyCode("bsq") .build(); @SuppressWarnings("ResultOfMethodCallIgnored") diff --git a/apitest/src/test/java/bisq/apitest/method/payment/AbstractPaymentAccountTest.java b/apitest/src/test/java/bisq/apitest/method/payment/AbstractPaymentAccountTest.java index e83bfe6db7..c31daec51d 100644 --- a/apitest/src/test/java/bisq/apitest/method/payment/AbstractPaymentAccountTest.java +++ b/apitest/src/test/java/bisq/apitest/method/payment/AbstractPaymentAccountTest.java @@ -33,7 +33,7 @@ import static bisq.apitest.config.BisqAppConfig.alicedaemon; import static java.lang.String.format; import static java.lang.System.getProperty; import static java.nio.charset.StandardCharsets.UTF_8; -import static org.junit.Assert.*; +import static org.junit.jupiter.api.Assertions.*; @@ -176,7 +176,6 @@ public class AbstractPaymentAccountTest extends MethodTest { tmpJsonForm = File.createTempFile("temp_acct_form_", ".json", Paths.get(getProperty("java.io.tmpdir")).toFile()); - tmpJsonForm.deleteOnExit(); JsonWriter writer = new JsonWriter(new OutputStreamWriter(new FileOutputStream(tmpJsonForm), UTF_8)); writer.beginObject(); @@ -199,6 +198,7 @@ public class AbstractPaymentAccountTest extends MethodTest { log.error("", ex); fail(format("Could not write json file from form entries %s", COMPLETED_FORM_MAP)); } + tmpJsonForm.deleteOnExit(); return tmpJsonForm; } } diff --git a/apitest/src/test/java/bisq/apitest/method/trade/TakeBuyBTCOfferTest.java b/apitest/src/test/java/bisq/apitest/method/trade/TakeBuyBTCOfferTest.java index ffbf75ffee..5eeba3d788 100644 --- a/apitest/src/test/java/bisq/apitest/method/trade/TakeBuyBTCOfferTest.java +++ b/apitest/src/test/java/bisq/apitest/method/trade/TakeBuyBTCOfferTest.java @@ -17,6 +17,8 @@ package bisq.apitest.method.trade; +import bisq.core.payment.PaymentAccount; + import bisq.proto.grpc.BtcBalanceInfo; import io.grpc.StatusRuntimeException; @@ -59,7 +61,8 @@ public class TakeBuyBTCOfferTest extends AbstractTradeTest { @Order(1) public void testTakeAlicesBuyOffer(final TestInfo testInfo) { try { - var alicesOffer = createAliceOffer(alicesDummyAcct, + PaymentAccount alicesUsdAccount = createDummyF2FAccount(alicedaemon, "US"); + var alicesOffer = createAliceOffer(alicesUsdAccount, "buy", "usd", 12500000, @@ -70,17 +73,20 @@ public class TakeBuyBTCOfferTest extends AbstractTradeTest { // Wait for Alice's AddToOfferBook task. // Wait times vary; my logs show >= 2 second delay. sleep(3000); // TODO loop instead of hard code wait time - assertEquals(1, getOpenOffersCount(aliceStubs, "buy", "usd")); + var alicesUsdOffers = getMyOffersSortedByDate(aliceStubs, "buy", "usd"); + assertEquals(1, alicesUsdOffers.size()); - var trade = takeAlicesOffer(offerId, bobsDummyAcct.getId(), TRADE_FEE_CURRENCY_CODE); + PaymentAccount bobsUsdAccount = createDummyF2FAccount(bobdaemon, "US"); + var trade = takeAlicesOffer(offerId, bobsUsdAccount.getId(), TRADE_FEE_CURRENCY_CODE); assertNotNull(trade); assertEquals(offerId, trade.getTradeId()); assertFalse(trade.getIsCurrencyForTakerFeeBtc()); // Cache the trade id for the other tests. tradeId = trade.getTradeId(); - genBtcBlocksThenWait(1, 2250); - assertEquals(0, getOpenOffersCount(aliceStubs, "buy", "usd")); + genBtcBlocksThenWait(1, 1000); + alicesUsdOffers = getMyOffersSortedByDate(aliceStubs, "buy", "usd"); + assertEquals(0, alicesUsdOffers.size()); trade = getTrade(bobdaemon, trade.getTradeId()); EXPECTED_PROTOCOL_STATUS.setState(SELLER_PUBLISHED_DEPOSIT_TX) @@ -89,7 +95,7 @@ public class TakeBuyBTCOfferTest extends AbstractTradeTest { verifyExpectedProtocolStatus(trade); logTrade(log, testInfo, "Bob's view after taking offer and sending deposit", trade); - genBtcBlocksThenWait(1, 2250); + genBtcBlocksThenWait(1, 1000); trade = getTrade(bobdaemon, trade.getTradeId()); EXPECTED_PROTOCOL_STATUS.setState(DEPOSIT_CONFIRMED_IN_BLOCK_CHAIN) .setPhase(DEPOSIT_CONFIRMED) @@ -142,14 +148,14 @@ public class TakeBuyBTCOfferTest extends AbstractTradeTest { @Test @Order(4) public void testAlicesKeepFunds(final TestInfo testInfo) { - genBtcBlocksThenWait(1, 2250); + genBtcBlocksThenWait(1, 1000); var trade = getTrade(alicedaemon, tradeId); logTrade(log, testInfo, "Alice's view before keeping funds", trade); keepFunds(alicedaemon, tradeId); - genBtcBlocksThenWait(1, 2250); + genBtcBlocksThenWait(1, 1000); trade = getTrade(alicedaemon, tradeId); EXPECTED_PROTOCOL_STATUS.setState(BUYER_RECEIVED_PAYOUT_TX_PUBLISHED_MSG) @@ -157,7 +163,7 @@ public class TakeBuyBTCOfferTest extends AbstractTradeTest { verifyExpectedProtocolStatus(trade); logTrade(log, testInfo, "Alice's view after keeping funds", trade); BtcBalanceInfo currentBalance = getBtcBalances(bobdaemon); - log.info("{} Alice's current available balance: {} BTC", + log.debug("{} Alice's current available balance: {} BTC", testName(testInfo), formatSatoshis(currentBalance.getAvailableBalance())); } diff --git a/apitest/src/test/java/bisq/apitest/method/trade/TakeSellBTCOfferTest.java b/apitest/src/test/java/bisq/apitest/method/trade/TakeSellBTCOfferTest.java index 673792c4f5..02d7ff8f43 100644 --- a/apitest/src/test/java/bisq/apitest/method/trade/TakeSellBTCOfferTest.java +++ b/apitest/src/test/java/bisq/apitest/method/trade/TakeSellBTCOfferTest.java @@ -17,6 +17,8 @@ package bisq.apitest.method.trade; +import bisq.core.payment.PaymentAccount; + import bisq.proto.grpc.BtcBalanceInfo; import io.grpc.StatusRuntimeException; @@ -58,7 +60,8 @@ public class TakeSellBTCOfferTest extends AbstractTradeTest { @Order(1) public void testTakeAlicesSellOffer(final TestInfo testInfo) { try { - var alicesOffer = createAliceOffer(alicesDummyAcct, + PaymentAccount alicesUsdAccount = createDummyF2FAccount(alicedaemon, "US"); + var alicesOffer = createAliceOffer(alicesUsdAccount, "sell", "usd", 12500000, @@ -70,9 +73,11 @@ public class TakeSellBTCOfferTest extends AbstractTradeTest { // Wait times vary; my logs show >= 2 second delay, but taking sell offers // seems to require more time to prepare. sleep(3000); // TODO loop instead of hard code wait time - assertEquals(1, getOpenOffersCount(bobStubs, "sell", "usd")); + var alicesUsdOffers = getMyOffersSortedByDate(aliceStubs, "sell", "usd"); + assertEquals(1, alicesUsdOffers.size()); - var trade = takeAlicesOffer(offerId, bobsDummyAcct.getId(), TRADE_FEE_CURRENCY_CODE); + PaymentAccount bobsUsdAccount = createDummyF2FAccount(bobdaemon, "US"); + var trade = takeAlicesOffer(offerId, bobsUsdAccount.getId(), TRADE_FEE_CURRENCY_CODE); assertNotNull(trade); assertEquals(offerId, trade.getTradeId()); assertTrue(trade.getIsCurrencyForTakerFeeBtc()); @@ -80,7 +85,8 @@ public class TakeSellBTCOfferTest extends AbstractTradeTest { tradeId = trade.getTradeId(); genBtcBlocksThenWait(1, 4000); - assertEquals(0, getOpenOffersCount(bobStubs, "sell", "usd")); + var takeableUsdOffers = getOffersSortedByDate(bobStubs, "sell", "usd"); + assertEquals(0, takeableUsdOffers.size()); trade = getTrade(bobdaemon, trade.getTradeId()); EXPECTED_PROTOCOL_STATUS.setState(BUYER_RECEIVED_DEPOSIT_TX_PUBLISHED_MSG) @@ -90,7 +96,7 @@ public class TakeSellBTCOfferTest extends AbstractTradeTest { logTrade(log, testInfo, "Bob's view after taking offer and sending deposit", trade); - genBtcBlocksThenWait(1, 2250); + genBtcBlocksThenWait(1, 1000); trade = getTrade(bobdaemon, trade.getTradeId()); EXPECTED_PROTOCOL_STATUS.setState(DEPOSIT_CONFIRMED_IN_BLOCK_CHAIN) .setPhase(DEPOSIT_CONFIRMED) @@ -143,7 +149,7 @@ public class TakeSellBTCOfferTest extends AbstractTradeTest { @Test @Order(4) public void testBobsBtcWithdrawalToExternalAddress(final TestInfo testInfo) { - genBtcBlocksThenWait(1, 2250); + genBtcBlocksThenWait(1, 1000); var trade = getTrade(bobdaemon, tradeId); logTrade(log, testInfo, "Bob's view before withdrawing funds to external wallet", trade); @@ -151,7 +157,7 @@ public class TakeSellBTCOfferTest extends AbstractTradeTest { String toAddress = bitcoinCli.getNewBtcAddress(); withdrawFunds(bobdaemon, tradeId, toAddress, WITHDRAWAL_TX_MEMO); - genBtcBlocksThenWait(1, 2250); + genBtcBlocksThenWait(1, 1000); trade = getTrade(bobdaemon, tradeId); EXPECTED_PROTOCOL_STATUS.setState(WITHDRAW_COMPLETED) diff --git a/apitest/src/test/java/bisq/apitest/method/wallet/BsqWalletTest.java b/apitest/src/test/java/bisq/apitest/method/wallet/BsqWalletTest.java index 2884555e3c..04b7ee9fdc 100644 --- a/apitest/src/test/java/bisq/apitest/method/wallet/BsqWalletTest.java +++ b/apitest/src/test/java/bisq/apitest/method/wallet/BsqWalletTest.java @@ -20,11 +20,14 @@ import static bisq.apitest.config.BisqAppConfig.alicedaemon; import static bisq.apitest.config.BisqAppConfig.arbdaemon; import static bisq.apitest.config.BisqAppConfig.bobdaemon; import static bisq.apitest.config.BisqAppConfig.seednode; +import static bisq.apitest.method.wallet.WalletTestUtil.ALICES_INITIAL_BSQ_BALANCES; +import static bisq.apitest.method.wallet.WalletTestUtil.BOBS_INITIAL_BSQ_BALANCES; +import static bisq.apitest.method.wallet.WalletTestUtil.bsqBalanceModel; +import static bisq.apitest.method.wallet.WalletTestUtil.verifyBsqBalances; import static bisq.cli.TableFormat.formatBsqBalanceInfoTbl; import static org.bitcoinj.core.NetworkParameters.PAYMENT_PROTOCOL_ID_MAINNET; import static org.bitcoinj.core.NetworkParameters.PAYMENT_PROTOCOL_ID_REGTEST; import static org.bitcoinj.core.NetworkParameters.PAYMENT_PROTOCOL_ID_TESTNET; -import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertNotEquals; import static org.junit.jupiter.api.Assertions.assertTrue; @@ -40,24 +43,6 @@ import bisq.apitest.method.MethodTest; @TestMethodOrder(OrderAnnotation.class) public class BsqWalletTest extends MethodTest { - // Alice's regtest BSQ wallet is initialized with 1,000,000 BSQ. - private static final bisq.core.api.model.BsqBalanceInfo ALICES_INITIAL_BSQ_BALANCES = - expectedBsqBalanceModel(100000000, - 0, - 0, - 0, - 0, - 0); - - // Bob's regtest BSQ wallet is initialized with 1,500,000 BSQ. - private static final bisq.core.api.model.BsqBalanceInfo BOBS_INITIAL_BSQ_BALANCES = - expectedBsqBalanceModel(150000000, - 0, - 0, - 0, - 0, - 0); - private static final String SEND_BSQ_AMOUNT = "25000.50"; @BeforeAll @@ -112,7 +97,7 @@ public class BsqWalletTest extends MethodTest { sleep(2000); BsqBalanceInfo alicesBsqBalances = getBsqBalances(alicedaemon); - BsqBalanceInfo bobsBsqBalances = waitForNonZeroUnverifiedBalance(bobdaemon); + BsqBalanceInfo bobsBsqBalances = waitForNonZeroBsqUnverifiedBalance(bobdaemon); log.debug("BSQ Balances Before BTC Block Gen..."); printBobAndAliceBsqBalances(testInfo, @@ -120,7 +105,7 @@ public class BsqWalletTest extends MethodTest { alicesBsqBalances, alicedaemon); - verifyBsqBalances(expectedBsqBalanceModel(150000000, + verifyBsqBalances(bsqBalanceModel(150000000, 2500050, 0, 0, @@ -128,7 +113,7 @@ public class BsqWalletTest extends MethodTest { 0), bobsBsqBalances); - verifyBsqBalances(expectedBsqBalanceModel(97499950, + verifyBsqBalances(bsqBalanceModel(97499950, 97499950, 97499950, 0, @@ -145,7 +130,7 @@ public class BsqWalletTest extends MethodTest { genBtcBlocksThenWait(1, 4000); BsqBalanceInfo alicesBsqBalances = getBsqBalances(alicedaemon); - BsqBalanceInfo bobsBsqBalances = waitForNewAvailableConfirmedBalance(bobdaemon, 150000000); + BsqBalanceInfo bobsBsqBalances = waitForBsqNewAvailableConfirmedBalance(bobdaemon, 150000000); log.debug("See Available Confirmed BSQ Balances..."); printBobAndAliceBsqBalances(testInfo, @@ -153,7 +138,7 @@ public class BsqWalletTest extends MethodTest { alicesBsqBalances, alicedaemon); - verifyBsqBalances(expectedBsqBalanceModel(152500050, + verifyBsqBalances(bsqBalanceModel(152500050, 0, 0, 0, @@ -161,7 +146,7 @@ public class BsqWalletTest extends MethodTest { 0), bobsBsqBalances); - verifyBsqBalances(expectedBsqBalanceModel(97499950, + verifyBsqBalances(bsqBalanceModel(97499950, 0, 0, 0, @@ -175,17 +160,7 @@ public class BsqWalletTest extends MethodTest { tearDownScaffold(); } - private void verifyBsqBalances(bisq.core.api.model.BsqBalanceInfo expected, - BsqBalanceInfo actual) { - assertEquals(expected.getAvailableConfirmedBalance(), actual.getAvailableConfirmedBalance()); - assertEquals(expected.getUnverifiedBalance(), actual.getUnverifiedBalance()); - assertEquals(expected.getUnconfirmedChangeBalance(), actual.getUnconfirmedChangeBalance()); - assertEquals(expected.getLockedForVotingBalance(), actual.getLockedForVotingBalance()); - assertEquals(expected.getLockupBondsBalance(), actual.getLockupBondsBalance()); - assertEquals(expected.getUnlockingBondsBalance(), actual.getUnlockingBondsBalance()); - } - - private BsqBalanceInfo waitForNonZeroUnverifiedBalance(BisqAppConfig daemon) { + private BsqBalanceInfo waitForNonZeroBsqUnverifiedBalance(BisqAppConfig daemon) { // A BSQ recipient needs to wait for her daemon to detect a new tx. // Loop here until her unverifiedBalance != 0, or give up after 15 seconds. // A slow test is preferred over a flaky test. @@ -197,8 +172,8 @@ public class BsqWalletTest extends MethodTest { return bsqBalance; } - private BsqBalanceInfo waitForNewAvailableConfirmedBalance(BisqAppConfig daemon, - long staleBalance) { + private BsqBalanceInfo waitForBsqNewAvailableConfirmedBalance(BisqAppConfig daemon, + long staleBalance) { BsqBalanceInfo bsqBalance = getBsqBalances(daemon); for (int numRequests = 1; numRequests <= 15 && bsqBalance.getAvailableConfirmedBalance() == staleBalance; @@ -226,19 +201,4 @@ public class BsqWalletTest extends MethodTest { SEND_BSQ_AMOUNT, formatBsqBalanceInfoTbl(alicesBsqBalances)); } - - @SuppressWarnings("SameParameterValue") - private static bisq.core.api.model.BsqBalanceInfo expectedBsqBalanceModel(long availableConfirmedBalance, - long unverifiedBalance, - long unconfirmedChangeBalance, - long lockedForVotingBalance, - long lockupBondsBalance, - long unlockingBondsBalance) { - return bisq.core.api.model.BsqBalanceInfo.valueOf(availableConfirmedBalance, - unverifiedBalance, - unconfirmedChangeBalance, - lockedForVotingBalance, - lockupBondsBalance, - unlockingBondsBalance); - } } diff --git a/apitest/src/test/java/bisq/apitest/method/wallet/BtcWalletTest.java b/apitest/src/test/java/bisq/apitest/method/wallet/BtcWalletTest.java index 90c46a3c81..33cd43e7c4 100644 --- a/apitest/src/test/java/bisq/apitest/method/wallet/BtcWalletTest.java +++ b/apitest/src/test/java/bisq/apitest/method/wallet/BtcWalletTest.java @@ -17,6 +17,8 @@ import static bisq.apitest.Scaffold.BitcoinCoreApp.bitcoind; import static bisq.apitest.config.BisqAppConfig.alicedaemon; import static bisq.apitest.config.BisqAppConfig.bobdaemon; import static bisq.apitest.config.BisqAppConfig.seednode; +import static bisq.apitest.method.wallet.WalletTestUtil.INITIAL_BTC_BALANCES; +import static bisq.apitest.method.wallet.WalletTestUtil.verifyBtcBalances; import static bisq.cli.TableFormat.formatAddressBalanceTbl; import static bisq.cli.TableFormat.formatBtcBalanceInfoTbl; import static java.util.Collections.singletonList; @@ -36,14 +38,6 @@ public class BtcWalletTest extends MethodTest { private static final String TX_MEMO = "tx memo"; - // All api tests depend on the DAO / regtest environment, and Bob & Alice's wallets - // are initialized with 10 BTC during the scaffolding setup. - private static final bisq.core.api.model.BtcBalanceInfo INITIAL_BTC_BALANCES = - bisq.core.api.model.BtcBalanceInfo.valueOf(1000000000, - 0, - 1000000000, - 0); - @BeforeAll public static void setUp() { startSupportingApps(false, @@ -60,10 +54,10 @@ public class BtcWalletTest extends MethodTest { // Bob & Alice's regtest Bisq wallets were initialized with 10 BTC. BtcBalanceInfo alicesBalances = getBtcBalances(alicedaemon); - log.info("{} Alice's BTC Balances:\n{}", testName(testInfo), formatBtcBalanceInfoTbl(alicesBalances)); + log.debug("{} Alice's BTC Balances:\n{}", testName(testInfo), formatBtcBalanceInfoTbl(alicesBalances)); BtcBalanceInfo bobsBalances = getBtcBalances(bobdaemon); - log.info("{} Bob's BTC Balances:\n{}", testName(testInfo), formatBtcBalanceInfoTbl(bobsBalances)); + log.debug("{} Bob's BTC Balances:\n{}", testName(testInfo), formatBtcBalanceInfoTbl(bobsBalances)); assertEquals(INITIAL_BTC_BALANCES.getAvailableBalance(), alicesBalances.getAvailableBalance()); assertEquals(INITIAL_BTC_BALANCES.getAvailableBalance(), bobsBalances.getAvailableBalance()); @@ -74,13 +68,13 @@ public class BtcWalletTest extends MethodTest { public void testFundAlicesBtcWallet(final TestInfo testInfo) { String newAddress = getUnusedBtcAddress(alicedaemon); bitcoinCli.sendToAddress(newAddress, "2.5"); - genBtcBlocksThenWait(1, 1500); + genBtcBlocksThenWait(1, 1000); BtcBalanceInfo btcBalanceInfo = getBtcBalances(alicedaemon); // New balance is 12.5 BTC assertEquals(1250000000, btcBalanceInfo.getAvailableBalance()); - log.info("{} -> Alice's Funded Address Balance -> \n{}", + log.debug("{} -> Alice's Funded Address Balance -> \n{}", testName(testInfo), formatAddressBalanceTbl(singletonList(getAddressBalance(alicedaemon, newAddress)))); @@ -92,7 +86,7 @@ public class BtcWalletTest extends MethodTest { 1250000000, 0); verifyBtcBalances(alicesExpectedBalances, btcBalanceInfo); - log.info("{} -> Alice's BTC Balances After Sending 2.5 BTC -> \n{}", + log.debug("{} -> Alice's BTC Balances After Sending 2.5 BTC -> \n{}", testName(testInfo), formatBtcBalanceInfoTbl(btcBalanceInfo)); } @@ -112,7 +106,7 @@ public class BtcWalletTest extends MethodTest { // Note that the memo is not set on the tx yet. assertTrue(txInfo.getMemo().isEmpty()); - genBtcBlocksThenWait(1, 3000); + genBtcBlocksThenWait(1, 1000); // Fetch the tx and check for confirmation and memo. txInfo = getTransaction(alicedaemon, txInfo.getTxId()); @@ -134,9 +128,9 @@ public class BtcWalletTest extends MethodTest { log.debug("{} Bob's BTC Balances:\n{}", testName(testInfo), formatBtcBalanceInfoTbl(bobsBalances)); - // We cannot (?) predict the exact tx size and calculate how much in tx fees were - // deducted from the 5.5 BTC sent to Bob, but we do know Bob should have something - // between 15.49978000 and 15.49978100 BTC. + // The sendbtc tx weight and size randomly varies between two distinct values + // (876 wu, 219 bytes, OR 880 wu, 220 bytes) from test run to test run, hence + // the assertion of an available balance range [1549978000, 1549978100]. assertTrue(bobsBalances.getAvailableBalance() >= 1549978000); assertTrue(bobsBalances.getAvailableBalance() <= 1549978100); } @@ -145,12 +139,4 @@ public class BtcWalletTest extends MethodTest { public static void tearDown() { tearDownScaffold(); } - - private void verifyBtcBalances(bisq.core.api.model.BtcBalanceInfo expected, - BtcBalanceInfo actual) { - assertEquals(expected.getAvailableBalance(), actual.getAvailableBalance()); - assertEquals(expected.getReservedBalance(), actual.getReservedBalance()); - assertEquals(expected.getTotalAvailableBalance(), actual.getTotalAvailableBalance()); - assertEquals(expected.getLockedBalance(), actual.getLockedBalance()); - } } diff --git a/apitest/src/test/java/bisq/apitest/method/wallet/WalletTestUtil.java b/apitest/src/test/java/bisq/apitest/method/wallet/WalletTestUtil.java new file mode 100644 index 0000000000..85b9f04e84 --- /dev/null +++ b/apitest/src/test/java/bisq/apitest/method/wallet/WalletTestUtil.java @@ -0,0 +1,72 @@ +package bisq.apitest.method.wallet; + +import bisq.proto.grpc.BsqBalanceInfo; +import bisq.proto.grpc.BtcBalanceInfo; + +import lombok.extern.slf4j.Slf4j; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +@Slf4j +public class WalletTestUtil { + + // All api tests depend on the DAO / regtest environment, and Bob & Alice's wallets + // are initialized with 10 BTC during the scaffolding setup. + public static final bisq.core.api.model.BtcBalanceInfo INITIAL_BTC_BALANCES = + bisq.core.api.model.BtcBalanceInfo.valueOf(1000000000, + 0, + 1000000000, + 0); + + + // Alice's regtest BSQ wallet is initialized with 1,000,000 BSQ. + public static final bisq.core.api.model.BsqBalanceInfo ALICES_INITIAL_BSQ_BALANCES = + bsqBalanceModel(100000000, + 0, + 0, + 0, + 0, + 0); + + // Bob's regtest BSQ wallet is initialized with 1,500,000 BSQ. + public static final bisq.core.api.model.BsqBalanceInfo BOBS_INITIAL_BSQ_BALANCES = + bsqBalanceModel(150000000, + 0, + 0, + 0, + 0, + 0); + + @SuppressWarnings("SameParameterValue") + public static bisq.core.api.model.BsqBalanceInfo bsqBalanceModel(long availableConfirmedBalance, + long unverifiedBalance, + long unconfirmedChangeBalance, + long lockedForVotingBalance, + long lockupBondsBalance, + long unlockingBondsBalance) { + return bisq.core.api.model.BsqBalanceInfo.valueOf(availableConfirmedBalance, + unverifiedBalance, + unconfirmedChangeBalance, + lockedForVotingBalance, + lockupBondsBalance, + unlockingBondsBalance); + } + + public static void verifyBsqBalances(bisq.core.api.model.BsqBalanceInfo expected, + BsqBalanceInfo actual) { + assertEquals(expected.getAvailableConfirmedBalance(), actual.getAvailableConfirmedBalance()); + assertEquals(expected.getUnverifiedBalance(), actual.getUnverifiedBalance()); + assertEquals(expected.getUnconfirmedChangeBalance(), actual.getUnconfirmedChangeBalance()); + assertEquals(expected.getLockedForVotingBalance(), actual.getLockedForVotingBalance()); + assertEquals(expected.getLockupBondsBalance(), actual.getLockupBondsBalance()); + assertEquals(expected.getUnlockingBondsBalance(), actual.getUnlockingBondsBalance()); + } + + public static void verifyBtcBalances(bisq.core.api.model.BtcBalanceInfo expected, + BtcBalanceInfo actual) { + assertEquals(expected.getAvailableBalance(), actual.getAvailableBalance()); + assertEquals(expected.getReservedBalance(), actual.getReservedBalance()); + assertEquals(expected.getTotalAvailableBalance(), actual.getTotalAvailableBalance()); + assertEquals(expected.getLockedBalance(), actual.getLockedBalance()); + } +} diff --git a/build.gradle b/build.gradle index edf54f3013..0672c88a64 100644 --- a/build.gradle +++ b/build.gradle @@ -28,7 +28,7 @@ configure(subprojects) { ext { // in alphabetical order bcVersion = '1.63' - bitcoinjVersion = 'dcf8af0' + bitcoinjVersion = '2a80db4' btcdCli4jVersion = '27b94333' codecVersion = '1.13' easybindVersion = '1.0.3' @@ -386,7 +386,7 @@ configure(project(':desktop')) { apply plugin: 'witness' apply from: '../gradle/witness/gradle-witness.gradle' - version = '1.5.1-SNAPSHOT' + version = '1.5.4-SNAPSHOT' mainClassName = 'bisq.desktop.app.BisqAppMain' diff --git a/cli/src/main/java/bisq/cli/CliMain.java b/cli/src/main/java/bisq/cli/CliMain.java index 4853e3a76b..9fc3acbb47 100644 --- a/cli/src/main/java/bisq/cli/CliMain.java +++ b/cli/src/main/java/bisq/cli/CliMain.java @@ -25,6 +25,8 @@ import bisq.proto.grpc.CreatePaymentAccountRequest; import bisq.proto.grpc.GetAddressBalanceRequest; import bisq.proto.grpc.GetBalancesRequest; import bisq.proto.grpc.GetFundingAddressesRequest; +import bisq.proto.grpc.GetMyOfferRequest; +import bisq.proto.grpc.GetMyOffersRequest; import bisq.proto.grpc.GetOfferRequest; import bisq.proto.grpc.GetOffersRequest; import bisq.proto.grpc.GetPaymentAccountFormRequest; @@ -96,7 +98,9 @@ public class CliMain { createoffer, canceloffer, getoffer, + getmyoffer, getoffers, + getmyoffers, takeoffer, gettrade, confirmpaymentstarted, @@ -418,6 +422,19 @@ public class CliMain { reply.getOffer().getCounterCurrencyCode())); return; } + case getmyoffer: { + if (nonOptionArgs.size() < 2) + throw new IllegalArgumentException("incorrect parameter count, expecting offer id"); + + var offerId = nonOptionArgs.get(1); + var request = GetMyOfferRequest.newBuilder() + .setId(offerId) + .build(); + var reply = offersService.getMyOffer(request); + out.println(formatOfferTable(singletonList(reply.getOffer()), + reply.getOffer().getCounterCurrencyCode())); + return; + } case getoffers: { if (nonOptionArgs.size() < 3) throw new IllegalArgumentException("incorrect parameter count," @@ -440,6 +457,28 @@ public class CliMain { return; } + case getmyoffers: { + if (nonOptionArgs.size() < 3) + throw new IllegalArgumentException("incorrect parameter count," + + " expecting direction (buy|sell), currency code"); + + var direction = nonOptionArgs.get(1); + var currencyCode = nonOptionArgs.get(2); + + var request = GetMyOffersRequest.newBuilder() + .setDirection(direction) + .setCurrencyCode(currencyCode) + .build(); + var reply = offersService.getMyOffers(request); + + List offers = reply.getOffersList(); + if (offers.isEmpty()) + out.printf("no %s %s offers found%n", direction, currencyCode); + else + out.println(formatOfferTable(reply.getOffersList(), currencyCode)); + + return; + } case takeoffer: { if (nonOptionArgs.size() < 3) throw new IllegalArgumentException("incorrect parameter count, " + @@ -727,11 +766,11 @@ public class CliMain { stream.println(); parser.printHelpOn(stream); stream.println(); - String rowFormat = "%-22s%-50s%s%n"; + String rowFormat = "%-24s%-52s%s%n"; stream.format(rowFormat, "Method", "Params", "Description"); stream.format(rowFormat, "------", "------", "------------"); stream.format(rowFormat, "getversion", "", "Get server version"); - stream.format(rowFormat, "getbalance [,currency code = bsq|btc]", "", "Get server wallet balances"); + stream.format(rowFormat, "getbalance", "[currency code = bsq|btc]", "Get server wallet balances"); stream.format(rowFormat, "getaddressbalance", "address", "Get server wallet address balance"); stream.format(rowFormat, "getfundingaddresses", "", "Get BTC funding addresses"); stream.format(rowFormat, "getunusedbsqaddress", "", "Get unused BSQ address"); @@ -747,8 +786,10 @@ public class CliMain { stream.format(rowFormat, "", "[,maker fee currency code = bsq|btc]", ""); stream.format(rowFormat, "canceloffer", "offer id", "Cancel offer with id"); stream.format(rowFormat, "getoffer", "offer id", "Get current offer with id"); + stream.format(rowFormat, "getmyoffer", "offer id", "Get my current offer with id"); stream.format(rowFormat, "getoffers", "buy | sell, currency code", "Get current offers"); - stream.format(rowFormat, "takeoffer", "offer id, [,taker fee currency code = bsq|btc]", "Take offer with id"); + stream.format(rowFormat, "getmyoffers", "buy | sell, currency code", "Get my current offers"); + stream.format(rowFormat, "takeoffer", "offer id [,taker fee currency code = bsq|btc]", "Take offer with id"); stream.format(rowFormat, "gettrade", "trade id [,showcontract = true|false]", "Get trade summary or full contract"); stream.format(rowFormat, "confirmpaymentstarted", "trade id", "Confirm payment started"); stream.format(rowFormat, "confirmpaymentreceived", "trade id", "Confirm payment received"); diff --git a/common/src/main/java/bisq/common/app/AsciiLogo.java b/common/src/main/java/bisq/common/app/AsciiLogo.java index f1433cd6c1..1bac8fdb10 100644 --- a/common/src/main/java/bisq/common/app/AsciiLogo.java +++ b/common/src/main/java/bisq/common/app/AsciiLogo.java @@ -22,25 +22,26 @@ import lombok.extern.slf4j.Slf4j; @Slf4j public class AsciiLogo { public static void showAsciiLogo() { - log.info("\n\n" + - " ........ ...... \n" + - " .............. ...... \n" + - " ................. ...... \n" + - " ...... .......... .. ...... \n" + - " ...... ...... ...... ............... ..... ......... .......... \n" + - " ....... ........ .................. ..... ............. ............... \n" + - " ...... ........ .......... ....... ..... ...... ... ........ ....... \n" + - " ...... ..... ....... ..... ..... ..... ..... ...... \n" + - " ...... ... ... ...... ...... ..... ........... ...... ...... \n" + - " ...... ..... .... ...... ...... ..... ............ ..... ...... \n" + - " ...... ..... ...... ..... ........ ...... ...... \n" + - " ...... .... ... ...... ...... ..... .. ...... ...... ........ \n" + - " ........ .. ....... ................. ..... .............. ................... \n" + - " .......... ......... ............. ..... ............ ................. \n" + - " ...................... ..... .... .... ...... \n" + - " ................ ...... \n" + - " .... ...... \n" + - " ...... \n" + - "\n\n"); + String ls = System.lineSeparator(); + log.info(ls + ls + + " ........ ...... " + ls + + " .............. ...... " + ls + + " ................. ...... " + ls + + " ...... .......... .. ...... " + ls + + " ...... ...... ...... ............... ..... ......... .......... " + ls + + " ....... ........ .................. ..... ............. ............... " + ls + + " ...... ........ .......... ....... ..... ...... ... ........ ....... " + ls + + " ...... ..... ....... ..... ..... ..... ..... ...... " + ls + + " ...... ... ... ...... ...... ..... ........... ...... ...... " + ls + + " ...... ..... .... ...... ...... ..... ............ ..... ...... " + ls + + " ...... ..... ...... ..... ........ ...... ...... " + ls + + " ...... .... ... ...... ...... ..... .. ...... ...... ........ " + ls + + " ........ .. ....... ................. ..... .............. ................... " + ls + + " .......... ......... ............. ..... ............ ................. " + ls + + " ...................... ..... .... .... ...... " + ls + + " ................ ...... " + ls + + " .... ...... " + ls + + " ...... " + ls + + ls + ls); } } diff --git a/common/src/main/java/bisq/common/app/Version.java b/common/src/main/java/bisq/common/app/Version.java index 4acaab88eb..8b4e9c465b 100644 --- a/common/src/main/java/bisq/common/app/Version.java +++ b/common/src/main/java/bisq/common/app/Version.java @@ -30,14 +30,14 @@ public class Version { // VERSION = 0.5.0 introduces proto buffer for the P2P network and local DB and is a not backward compatible update // Therefore all sub versions start again with 1 // We use semantic versioning with major, minor and patch - public static final String VERSION = "1.5.1"; + public static final String VERSION = "1.5.4"; /** * Holds a list of the tagged resource files for optimizing the getData requests. * This must not contain each version but only those where we add new version-tagged resource files for * historical data stores. */ - public static final List HISTORICAL_RESOURCE_FILE_VERSION_TAGS = Arrays.asList("1.4.0", "1.5.0"); + public static final List HISTORICAL_RESOURCE_FILE_VERSION_TAGS = Arrays.asList("1.4.0", "1.5.0", "1.5.2"); public static int getMajorVersion(String version) { return getSubVersion(version, 0); diff --git a/common/src/main/java/bisq/common/config/Config.java b/common/src/main/java/bisq/common/config/Config.java index 08445a746e..3f58f4bb93 100644 --- a/common/src/main/java/bisq/common/config/Config.java +++ b/common/src/main/java/bisq/common/config/Config.java @@ -119,6 +119,7 @@ public class Config { public static final String ALLOW_FAULTY_DELAYED_TXS = "allowFaultyDelayedTxs"; public static final String API_PASSWORD = "apiPassword"; public static final String API_PORT = "apiPort"; + public static final String PREVENT_PERIODIC_SHUTDOWN_AT_SEED_NODE = "preventPeriodicShutdownAtSeedNode"; // Default values for certain options public static final int UNSPECIFIED_PORT = -1; @@ -205,6 +206,7 @@ public class Config { public final boolean allowFaultyDelayedTxs; public final String apiPassword; public final int apiPort; + public final boolean preventPeriodicShutdownAtSeedNode; // Properties derived from options but not exposed as options themselves public final File torDir; @@ -639,6 +641,13 @@ public class Config { .ofType(Integer.class) .defaultsTo(9998); + ArgumentAcceptingOptionSpec preventPeriodicShutdownAtSeedNodeOpt = + parser.accepts(PREVENT_PERIODIC_SHUTDOWN_AT_SEED_NODE, + "Prevents periodic shutdown at seed nodes") + .withRequiredArg() + .ofType(boolean.class) + .defaultsTo(false); + try { CompositeOptionSet options = new CompositeOptionSet(); @@ -754,6 +763,7 @@ public class Config { this.allowFaultyDelayedTxs = options.valueOf(allowFaultyDelayedTxsOpt); this.apiPassword = options.valueOf(apiPasswordOpt); this.apiPort = options.valueOf(apiPortOpt); + this.preventPeriodicShutdownAtSeedNode = options.valueOf(preventPeriodicShutdownAtSeedNodeOpt); } catch (OptionException ex) { throw new ConfigException("problem parsing option '%s': %s", ex.options().get(0), diff --git a/common/src/main/java/bisq/common/proto/ProtoUtil.java b/common/src/main/java/bisq/common/proto/ProtoUtil.java index e8471a4d82..d7450e9d50 100644 --- a/common/src/main/java/bisq/common/proto/ProtoUtil.java +++ b/common/src/main/java/bisq/common/proto/ProtoUtil.java @@ -28,6 +28,7 @@ import com.google.common.base.Enums; import java.util.ArrayList; import java.util.Collection; +import java.util.HashSet; import java.util.List; import java.util.Objects; import java.util.Set; @@ -105,4 +106,7 @@ public class ProtoUtil { return CollectionUtils.isEmpty(protocolStringList) ? new ArrayList<>() : new ArrayList<>(protocolStringList); } + public static Set protocolStringListToSet(ProtocolStringList protocolStringList) { + return CollectionUtils.isEmpty(protocolStringList) ? new HashSet<>() : new HashSet<>(protocolStringList); + } } diff --git a/core/src/main/java/bisq/core/account/sign/SignedWitnessService.java b/core/src/main/java/bisq/core/account/sign/SignedWitnessService.java index 69a7d49feb..f33dd7d234 100644 --- a/core/src/main/java/bisq/core/account/sign/SignedWitnessService.java +++ b/core/src/main/java/bisq/core/account/sign/SignedWitnessService.java @@ -73,6 +73,7 @@ public class SignedWitnessService { private final KeyRing keyRing; private final P2PService p2PService; private final ArbitratorManager arbitratorManager; + private final SignedWitnessStorageService signedWitnessStorageService; private final User user; private final FilterManager filterManager; @@ -82,6 +83,17 @@ public class SignedWitnessService { // This avoids iterations over the signedWitnessMap for getting the set of such SignedWitnesses. private final Map> signedWitnessSetByAccountAgeWitnessHash = new HashMap<>(); + // Iterating over all SignedWitnesses and do a byte array comparison is a bit expensive and + // it is called at filtering the offer book many times, so we use a lookup map for fast + // access to the set of SignedWitness which match the ownerPubKey. + private final Map> signedWitnessSetByOwnerPubKey = new HashMap<>(); + + // The signature verification calls are rather expensive and called at filtering the offer book many times, + // so we cache the results using the hash as key. The hash is created from the accountAgeWitnessHash and the + // signature. + private final Map verifySignatureWithDSAKeyResultCache = new HashMap<>(); + private final Map verifySignatureWithECKeyResultCache = new HashMap<>(); + /////////////////////////////////////////////////////////////////////////////////////////// // Constructor @@ -98,6 +110,7 @@ public class SignedWitnessService { this.keyRing = keyRing; this.p2PService = p2PService; this.arbitratorManager = arbitratorManager; + this.signedWitnessStorageService = signedWitnessStorageService; this.user = user; this.filterManager = filterManager; @@ -117,7 +130,7 @@ public class SignedWitnessService { }); // At startup the P2PDataStorage initializes earlier, otherwise we get the listener called. - p2PService.getP2PDataStorage().getAppendOnlyDataStoreMap().values().forEach(e -> { + signedWitnessStorageService.getMap().values().forEach(e -> { if (e instanceof SignedWitness) addToMap((SignedWitness) e); }); @@ -322,32 +335,45 @@ public class SignedWitnessService { } private boolean verifySignatureWithECKey(SignedWitness signedWitness) { + P2PDataStorage.ByteArray hash = new P2PDataStorage.ByteArray(signedWitness.getHash()); + if (verifySignatureWithECKeyResultCache.containsKey(hash)) { + return verifySignatureWithECKeyResultCache.get(hash); + } try { String message = Utilities.encodeToHex(signedWitness.getAccountAgeWitnessHash()); String signatureBase64 = new String(signedWitness.getSignature(), Charsets.UTF_8); ECKey key = ECKey.fromPublicOnly(signedWitness.getSignerPubKey()); if (arbitratorManager.isPublicKeyInList(Utilities.encodeToHex(key.getPubKey()))) { key.verifyMessage(message, signatureBase64); + verifySignatureWithECKeyResultCache.put(hash, true); return true; } else { log.warn("Provided EC key is not in list of valid arbitrators."); + verifySignatureWithECKeyResultCache.put(hash, false); return false; } } catch (SignatureException e) { log.warn("verifySignature signedWitness failed. signedWitness={}", signedWitness); log.warn("Caused by ", e); + verifySignatureWithECKeyResultCache.put(hash, false); return false; } } private boolean verifySignatureWithDSAKey(SignedWitness signedWitness) { + P2PDataStorage.ByteArray hash = new P2PDataStorage.ByteArray(signedWitness.getHash()); + if (verifySignatureWithDSAKeyResultCache.containsKey(hash)) { + return verifySignatureWithDSAKeyResultCache.get(hash); + } try { PublicKey signaturePubKey = Sig.getPublicKeyFromBytes(signedWitness.getSignerPubKey()); Sig.verify(signaturePubKey, signedWitness.getAccountAgeWitnessHash(), signedWitness.getSignature()); + verifySignatureWithDSAKeyResultCache.put(hash, true); return true; } catch (CryptoException e) { log.warn("verifySignature signedWitness failed. signedWitness={}", signedWitness); log.warn("Caused by ", e); + verifySignatureWithDSAKeyResultCache.put(hash, false); return false; } } @@ -393,10 +419,15 @@ public class SignedWitnessService { // witnessOwnerPubKey private Set getSignedWitnessSetByOwnerPubKey(byte[] ownerPubKey, Stack excluded) { - return getSignedWitnessMapValues().stream() - .filter(e -> Arrays.equals(e.getWitnessOwnerPubKey(), ownerPubKey)) - .filter(e -> !excluded.contains(new P2PDataStorage.ByteArray(e.getSignerPubKey()))) - .collect(Collectors.toSet()); + P2PDataStorage.ByteArray key = new P2PDataStorage.ByteArray(ownerPubKey); + if (signedWitnessSetByOwnerPubKey.containsKey(key)) { + return signedWitnessSetByOwnerPubKey.get(key).stream() + .filter(e -> !excluded.contains(new P2PDataStorage.ByteArray(e.getSignerPubKey()))) + .collect(Collectors.toSet()); + + } else { + return new HashSet<>(); + } } public boolean isSignedAccountAgeWitness(AccountAgeWitness accountAgeWitness) { @@ -498,6 +529,10 @@ public class SignedWitnessService { P2PDataStorage.ByteArray accountAgeWitnessHash = new P2PDataStorage.ByteArray(signedWitness.getAccountAgeWitnessHash()); signedWitnessSetByAccountAgeWitnessHash.putIfAbsent(accountAgeWitnessHash, new HashSet<>()); signedWitnessSetByAccountAgeWitnessHash.get(accountAgeWitnessHash).add(signedWitness); + + P2PDataStorage.ByteArray ownerPubKey = new P2PDataStorage.ByteArray(signedWitness.getWitnessOwnerPubKey()); + signedWitnessSetByOwnerPubKey.putIfAbsent(ownerPubKey, new HashSet<>()); + signedWitnessSetByOwnerPubKey.get(ownerPubKey).add(signedWitness); } private void publishSignedWitness(SignedWitness signedWitness) { @@ -526,6 +561,15 @@ public class SignedWitnessService { signedWitnessSetByAccountAgeWitnessHash.remove(accountAgeWitnessHash); } } + + P2PDataStorage.ByteArray ownerPubKey = new P2PDataStorage.ByteArray(signedWitness.getWitnessOwnerPubKey()); + if (signedWitnessSetByOwnerPubKey.containsKey(ownerPubKey)) { + Set set = signedWitnessSetByOwnerPubKey.get(ownerPubKey); + set.remove(signedWitness); + if (set.isEmpty()) { + signedWitnessSetByOwnerPubKey.remove(ownerPubKey); + } + } } // Remove SignedWitnesses that are signed by TRADE that also have an ARBITRATOR signature diff --git a/core/src/main/java/bisq/core/account/witness/AccountAgeWitnessService.java b/core/src/main/java/bisq/core/account/witness/AccountAgeWitnessService.java index b712f44450..b634f01a8d 100644 --- a/core/src/main/java/bisq/core/account/witness/AccountAgeWitnessService.java +++ b/core/src/main/java/bisq/core/account/witness/AccountAgeWitnessService.java @@ -64,6 +64,8 @@ import com.google.common.annotations.VisibleForTesting; import java.security.PublicKey; +import java.time.Clock; + import java.util.Arrays; import java.util.Date; import java.util.GregorianCalendar; @@ -136,6 +138,8 @@ public class AccountAgeWitnessService { private final User user; private final SignedWitnessService signedWitnessService; private final ChargeBackRisk chargeBackRisk; + private final AccountAgeWitnessStorageService accountAgeWitnessStorageService; + private final Clock clock; private final FilterManager filterManager; @Getter private final AccountAgeWitnessUtils accountAgeWitnessUtils; @@ -161,12 +165,15 @@ public class AccountAgeWitnessService { ChargeBackRisk chargeBackRisk, AccountAgeWitnessStorageService accountAgeWitnessStorageService, AppendOnlyDataStoreService appendOnlyDataStoreService, + Clock clock, FilterManager filterManager) { this.keyRing = keyRing; this.p2PService = p2PService; this.user = user; this.signedWitnessService = signedWitnessService; this.chargeBackRisk = chargeBackRisk; + this.accountAgeWitnessStorageService = accountAgeWitnessStorageService; + this.clock = clock; this.filterManager = filterManager; accountAgeWitnessUtils = new AccountAgeWitnessUtils( @@ -190,10 +197,10 @@ public class AccountAgeWitnessService { }); // At startup the P2PDataStorage initializes earlier, otherwise we get the listener called. - p2PService.getP2PDataStorage().getAppendOnlyDataStoreMap().values().forEach(e -> { - if (e instanceof AccountAgeWitness) - addToMap((AccountAgeWitness) e); - }); + accountAgeWitnessStorageService.getMapOfAllData().values().stream() + .filter(e -> e instanceof AccountAgeWitness) + .map(e -> (AccountAgeWitness) e) + .forEach(this::addToMap); if (p2PService.isBootstrapped()) { onBootStrapped(); @@ -217,13 +224,18 @@ public class AccountAgeWitnessService { private void republishAllFiatAccounts() { if (user.getPaymentAccounts() != null) user.getPaymentAccounts().stream() - .filter(e -> !(e instanceof AssetAccount)) - .forEach(e -> { - // We delay with a random interval of 20-60 sec to ensure to be better connected and don't - // stress the P2P network with publishing all at once at startup time. - final int delayInSec = 20 + new Random().nextInt(40); - UserThread.runAfter(() -> p2PService.addPersistableNetworkPayload(getMyWitness( - e.getPaymentAccountPayload()), true), delayInSec); + .filter(account -> !(account instanceof AssetAccount)) + .forEach(account -> { + AccountAgeWitness myWitness = getMyWitness(account.getPaymentAccountPayload()); + // We only publish if the date of our witness is inside the date tolerance. + // It would be rejected otherwise from the peers. + if (myWitness.isDateInTolerance(clock)) { + // We delay with a random interval of 20-60 sec to ensure to be better connected and don't + // stress the P2P network with publishing all at once at startup time. + int delayInSec = 20 + new Random().nextInt(40); + UserThread.runAfter(() -> + p2PService.addPersistableNetworkPayload(myWitness, true), delayInSec); + } }); } diff --git a/core/src/main/java/bisq/core/api/CoreApi.java b/core/src/main/java/bisq/core/api/CoreApi.java index 4dffaee976..6c57f20c7f 100644 --- a/core/src/main/java/bisq/core/api/CoreApi.java +++ b/core/src/main/java/bisq/core/api/CoreApi.java @@ -108,10 +108,18 @@ public class CoreApi { return coreOffersService.getOffer(id); } + public Offer getMyOffer(String id) { + return coreOffersService.getMyOffer(id); + } + public List getOffers(String direction, String currencyCode) { return coreOffersService.getOffers(direction, currencyCode); } + public List getMyOffers(String direction, String currencyCode) { + return coreOffersService.getMyOffers(direction, currencyCode); + } + public void createAnPlaceOffer(String currencyCode, String directionAsString, String priceAsString, diff --git a/core/src/main/java/bisq/core/api/CoreOffersService.java b/core/src/main/java/bisq/core/api/CoreOffersService.java index bca9dc7cbf..cba594362d 100644 --- a/core/src/main/java/bisq/core/api/CoreOffersService.java +++ b/core/src/main/java/bisq/core/api/CoreOffersService.java @@ -27,6 +27,8 @@ import bisq.core.offer.OpenOfferManager; import bisq.core.payment.PaymentAccount; import bisq.core.user.User; +import bisq.common.crypto.KeyRing; + import org.bitcoinj.core.Coin; import org.bitcoinj.core.Transaction; import org.bitcoinj.utils.Fiat; @@ -38,6 +40,7 @@ import java.math.BigDecimal; import java.util.Comparator; import java.util.List; import java.util.function.Consumer; +import java.util.function.Supplier; import java.util.stream.Collectors; import lombok.extern.slf4j.Slf4j; @@ -49,10 +52,15 @@ import static bisq.core.locale.CurrencyUtil.isCryptoCurrency; import static bisq.core.offer.OfferPayload.Direction; import static bisq.core.offer.OfferPayload.Direction.BUY; import static java.lang.String.format; +import static java.util.Comparator.comparing; @Slf4j class CoreOffersService { + private final Supplier> priceComparator = () -> comparing(Offer::getPrice); + private final Supplier> reversePriceComparator = () -> comparing(Offer::getPrice).reversed(); + + private final KeyRing keyRing; private final CreateOfferService createOfferService; private final OfferBookService offerBookService; private final OpenOfferManager openOfferManager; @@ -60,11 +68,13 @@ class CoreOffersService { private final User user; @Inject - public CoreOffersService(CreateOfferService createOfferService, + public CoreOffersService(KeyRing keyRing, + CreateOfferService createOfferService, OfferBookService offerBookService, OpenOfferManager openOfferManager, OfferUtil offerUtil, User user) { + this.keyRing = keyRing; this.createOfferService = createOfferService; this.offerBookService = offerBookService; this.openOfferManager = openOfferManager; @@ -79,24 +89,27 @@ class CoreOffersService { new IllegalStateException(format("offer with id '%s' not found", id))); } + Offer getMyOffer(String id) { + return offerBookService.getOffers().stream() + .filter(o -> o.getId().equals(id)) + .filter(o -> o.isMyOffer(keyRing)) + .findAny().orElseThrow(() -> + new IllegalStateException(format("offer with id '%s' not found", id))); + } + List getOffers(String direction, String currencyCode) { - List offers = offerBookService.getOffers().stream() - .filter(o -> { - var offerOfWantedDirection = o.getDirection().name().equalsIgnoreCase(direction); - var offerInWantedCurrency = o.getOfferPayload().getCounterCurrencyCode() - .equalsIgnoreCase(currencyCode); - return offerOfWantedDirection && offerInWantedCurrency; - }) + return offerBookService.getOffers().stream() + .filter(o -> offerMatchesDirectionAndCurrency(o, direction, currencyCode)) + .sorted(priceComparator(direction)) .collect(Collectors.toList()); + } - // A buyer probably wants to see sell orders in price ascending order. - // A seller probably wants to see buy orders in price descending order. - if (direction.equalsIgnoreCase(BUY.name())) - offers.sort(Comparator.comparing(Offer::getPrice).reversed()); - else - offers.sort(Comparator.comparing(Offer::getPrice)); - - return offers; + List getMyOffers(String direction, String currencyCode) { + return offerBookService.getOffers().stream() + .filter(o -> o.isMyOffer(keyRing)) + .filter(o -> offerMatchesDirectionAndCurrency(o, direction, currencyCode)) + .sorted(priceComparator(direction)) + .collect(Collectors.toList()); } // Create and place new offer. @@ -182,9 +195,11 @@ class CoreOffersService { double buyerSecurityDeposit, boolean useSavingsWallet, Consumer resultHandler) { + // TODO add support for triggerPrice parameter. If value is 0 it is interpreted as not used. Its an optional value openOfferManager.placeOffer(offer, buyerSecurityDeposit, useSavingsWallet, + 0, resultHandler::accept, log::error); @@ -192,6 +207,23 @@ class CoreOffersService { throw new IllegalStateException(offer.getErrorMessage()); } + private boolean offerMatchesDirectionAndCurrency(Offer offer, + String direction, + String currencyCode) { + var offerOfWantedDirection = offer.getDirection().name().equalsIgnoreCase(direction); + var offerInWantedCurrency = offer.getOfferPayload().getCounterCurrencyCode() + .equalsIgnoreCase(currencyCode); + return offerOfWantedDirection && offerInWantedCurrency; + } + + private Comparator priceComparator(String direction) { + // A buyer probably wants to see sell orders in price ascending order. + // A seller probably wants to see buy orders in price descending order. + return direction.equalsIgnoreCase(BUY.name()) + ? reversePriceComparator.get() + : priceComparator.get(); + } + private long priceStringToLong(String priceAsString, String currencyCode) { int precision = isCryptoCurrency(currencyCode) ? Altcoin.SMALLEST_UNIT_EXPONENT : Fiat.SMALLEST_UNIT_EXPONENT; double priceAsDouble = new BigDecimal(priceAsString).doubleValue(); diff --git a/core/src/main/java/bisq/core/api/CorePaymentAccountsService.java b/core/src/main/java/bisq/core/api/CorePaymentAccountsService.java index dacb79567f..d3084363de 100644 --- a/core/src/main/java/bisq/core/api/CorePaymentAccountsService.java +++ b/core/src/main/java/bisq/core/api/CorePaymentAccountsService.java @@ -73,6 +73,7 @@ class CorePaymentAccountsService { String getPaymentAccountFormAsString(String paymentMethodId) { File jsonForm = getPaymentAccountForm(paymentMethodId); + jsonForm.deleteOnExit(); // If just asking for a string, delete the form file. return paymentAccountForm.toJsonString(jsonForm); } diff --git a/core/src/main/java/bisq/core/api/CoreTradesService.java b/core/src/main/java/bisq/core/api/CoreTradesService.java index 10d21d6415..b15ad6f48b 100644 --- a/core/src/main/java/bisq/core/api/CoreTradesService.java +++ b/core/src/main/java/bisq/core/api/CoreTradesService.java @@ -108,6 +108,7 @@ class CoreTradesService { offer, paymentAccountId, useSavingsWallet, + true, resultHandler::accept, errorMessage -> { log.error(errorMessage); diff --git a/core/src/main/java/bisq/core/app/BisqSetup.java b/core/src/main/java/bisq/core/app/BisqSetup.java index 9b2d230030..677b4e7678 100644 --- a/core/src/main/java/bisq/core/app/BisqSetup.java +++ b/core/src/main/java/bisq/core/app/BisqSetup.java @@ -18,6 +18,7 @@ package bisq.core.app; import bisq.core.account.sign.SignedWitness; +import bisq.core.account.sign.SignedWitnessStorageService; import bisq.core.account.witness.AccountAgeWitnessService; import bisq.core.alert.Alert; import bisq.core.alert.AlertManager; @@ -51,6 +52,7 @@ import bisq.common.UserThread; import bisq.common.app.DevEnv; import bisq.common.app.Log; import bisq.common.app.Version; +import bisq.common.config.BaseCurrencyNetwork; import bisq.common.config.Config; import bisq.common.util.InvalidVersionException; import bisq.common.util.Utilities; @@ -123,6 +125,7 @@ public class BisqSetup { private final WalletsSetup walletsSetup; private final BtcWalletService btcWalletService; private final P2PService p2PService; + private final SignedWitnessStorageService signedWitnessStorageService; private final TradeManager tradeManager; private final OpenOfferManager openOfferManager; private final Preferences preferences; @@ -204,6 +207,7 @@ public class BisqSetup { WalletsSetup walletsSetup, BtcWalletService btcWalletService, P2PService p2PService, + SignedWitnessStorageService signedWitnessStorageService, TradeManager tradeManager, OpenOfferManager openOfferManager, Preferences preferences, @@ -224,6 +228,7 @@ public class BisqSetup { this.walletsSetup = walletsSetup; this.btcWalletService = btcWalletService; this.p2PService = p2PService; + this.signedWitnessStorageService = signedWitnessStorageService; this.tradeManager = tradeManager; this.openOfferManager = openOfferManager; this.preferences = preferences; @@ -273,7 +278,8 @@ public class BisqSetup { public void start() { // If user tried to downgrade we require a shutdown - if (hasDowngraded(downGradePreventionHandler)) { + if (Config.baseCurrencyNetwork() == BaseCurrencyNetwork.BTC_MAINNET && + hasDowngraded(downGradePreventionHandler)) { return; } @@ -650,7 +656,7 @@ public class BisqSetup { private void checkSigningState(AccountAgeWitnessService.SignState state, String key, Consumer displayHandler) { - boolean signingStateFound = p2PService.getP2PDataStorage().getAppendOnlyDataStoreMap().values().stream() + boolean signingStateFound = signedWitnessStorageService.getMap().values().stream() .anyMatch(payload -> isSignedWitnessOfMineWithState(payload, state)); maybeTriggerDisplayHandler(key, displayHandler, signingStateFound); diff --git a/core/src/main/java/bisq/core/app/CoreModule.java b/core/src/main/java/bisq/core/app/CoreModule.java index 8f30070532..4984a84aae 100644 --- a/core/src/main/java/bisq/core/app/CoreModule.java +++ b/core/src/main/java/bisq/core/app/CoreModule.java @@ -21,6 +21,7 @@ import bisq.core.alert.AlertModule; import bisq.core.btc.BitcoinModule; import bisq.core.dao.DaoModule; import bisq.core.filter.FilterModule; +import bisq.core.network.CoreNetworkFilter; import bisq.core.network.p2p.seed.DefaultSeedNodeRepository; import bisq.core.offer.OfferModule; import bisq.core.presentation.CorePresentationModule; @@ -35,6 +36,7 @@ import bisq.core.util.coin.ImmutableCoinFormatter; import bisq.network.crypto.EncryptionServiceModule; import bisq.network.p2p.P2PModule; import bisq.network.p2p.network.BridgeAddressProvider; +import bisq.network.p2p.network.NetworkFilter; import bisq.network.p2p.seed.SeedNodeRepository; import bisq.common.app.AppModule; @@ -44,6 +46,8 @@ import bisq.common.crypto.PubKeyRingProvider; import bisq.common.proto.network.NetworkProtoResolver; import bisq.common.proto.persistable.PersistenceProtoResolver; +import com.google.inject.Singleton; + import java.io.File; import static bisq.common.config.Config.*; @@ -62,6 +66,7 @@ public class CoreModule extends AppModule { bind(BridgeAddressProvider.class).to(Preferences.class); bind(SeedNodeRepository.class).to(DefaultSeedNodeRepository.class); + bind(NetworkFilter.class).to(CoreNetworkFilter.class).in(Singleton.class); bind(File.class).annotatedWith(named(STORAGE_DIR)).toInstance(config.storageDir); diff --git a/core/src/main/java/bisq/core/app/DomainInitialisation.java b/core/src/main/java/bisq/core/app/DomainInitialisation.java index 754ba3f187..5843500dd6 100644 --- a/core/src/main/java/bisq/core/app/DomainInitialisation.java +++ b/core/src/main/java/bisq/core/app/DomainInitialisation.java @@ -34,6 +34,7 @@ import bisq.core.notifications.alerts.TradeEvents; import bisq.core.notifications.alerts.market.MarketAlerts; import bisq.core.notifications.alerts.price.PriceAlert; import bisq.core.offer.OpenOfferManager; +import bisq.core.offer.TriggerPriceService; import bisq.core.payment.RevolutAccount; import bisq.core.payment.TradeLimits; import bisq.core.provider.fee.FeeService; @@ -106,6 +107,7 @@ public class DomainInitialisation { private final MarketAlerts marketAlerts; private final User user; private final DaoStateSnapshotService daoStateSnapshotService; + private final TriggerPriceService triggerPriceService; @Inject public DomainInitialisation(ClockWatcher clockWatcher, @@ -141,7 +143,8 @@ public class DomainInitialisation { PriceAlert priceAlert, MarketAlerts marketAlerts, User user, - DaoStateSnapshotService daoStateSnapshotService) { + DaoStateSnapshotService daoStateSnapshotService, + TriggerPriceService triggerPriceService) { this.clockWatcher = clockWatcher; this.tradeLimits = tradeLimits; this.arbitrationManager = arbitrationManager; @@ -176,6 +179,7 @@ public class DomainInitialisation { this.marketAlerts = marketAlerts; this.user = user; this.daoStateSnapshotService = daoStateSnapshotService; + this.triggerPriceService = triggerPriceService; } public void initDomainServices(Consumer rejectedTxErrorMessageHandler, @@ -254,6 +258,7 @@ public class DomainInitialisation { disputeMsgEvents.onAllServicesInitialized(); priceAlert.onAllServicesInitialized(); marketAlerts.onAllServicesInitialized(); + triggerPriceService.onAllServicesInitialized(); if (revolutAccountsUpdateHandler != null) { revolutAccountsUpdateHandler.accept(user.getPaymentAccountsAsObservable().stream() diff --git a/core/src/main/java/bisq/core/app/WalletAppSetup.java b/core/src/main/java/bisq/core/app/WalletAppSetup.java index ab66bd23ce..b8967597a6 100644 --- a/core/src/main/java/bisq/core/app/WalletAppSetup.java +++ b/core/src/main/java/bisq/core/app/WalletAppSetup.java @@ -107,7 +107,7 @@ public class WalletAppSetup { Runnable downloadCompleteHandler, Runnable walletInitializedHandler) { log.info("Initialize WalletAppSetup with BitcoinJ version {} and hash of BitcoinJ commit {}", - VersionMessage.BITCOINJ_VERSION, "dcf8af0"); + VersionMessage.BITCOINJ_VERSION, "2a80db4"); ObjectProperty walletServiceException = new SimpleObjectProperty<>(); btcInfoBinding = EasyBind.combine(walletsSetup.downloadPercentageProperty(), diff --git a/core/src/main/java/bisq/core/app/misc/ModuleForAppWithP2p.java b/core/src/main/java/bisq/core/app/misc/ModuleForAppWithP2p.java index 4ffdb7f79c..879c29ab69 100644 --- a/core/src/main/java/bisq/core/app/misc/ModuleForAppWithP2p.java +++ b/core/src/main/java/bisq/core/app/misc/ModuleForAppWithP2p.java @@ -22,6 +22,7 @@ import bisq.core.app.TorSetup; import bisq.core.btc.BitcoinModule; import bisq.core.dao.DaoModule; import bisq.core.filter.FilterModule; +import bisq.core.network.CoreNetworkFilter; import bisq.core.network.p2p.seed.DefaultSeedNodeRepository; import bisq.core.offer.OfferModule; import bisq.core.proto.network.CoreNetworkProtoResolver; @@ -33,6 +34,7 @@ import bisq.core.user.User; import bisq.network.crypto.EncryptionServiceModule; import bisq.network.p2p.P2PModule; import bisq.network.p2p.network.BridgeAddressProvider; +import bisq.network.p2p.network.NetworkFilter; import bisq.network.p2p.seed.SeedNodeRepository; import bisq.common.ClockWatcher; @@ -73,6 +75,7 @@ public class ModuleForAppWithP2p extends AppModule { bind(TorSetup.class).in(Singleton.class); bind(SeedNodeRepository.class).to(DefaultSeedNodeRepository.class).in(Singleton.class); + bind(NetworkFilter.class).to(CoreNetworkFilter.class).in(Singleton.class); bind(File.class).annotatedWith(named(STORAGE_DIR)).toInstance(config.storageDir); bind(File.class).annotatedWith(named(KEY_STORAGE_DIR)).toInstance(config.keyStorageDir); @@ -81,6 +84,7 @@ public class ModuleForAppWithP2p extends AppModule { bindConstant().annotatedWith(named(USE_DEV_MODE)).to(config.useDevMode); bindConstant().annotatedWith(named(USE_DEV_MODE_HEADER)).to(config.useDevModeHeader); bindConstant().annotatedWith(named(REFERRAL_ID)).to(config.referralId); + bindConstant().annotatedWith(named(PREVENT_PERIODIC_SHUTDOWN_AT_SEED_NODE)).to(config.preventPeriodicShutdownAtSeedNode); // ordering is used for shut down sequence install(new TradeModule(config)); diff --git a/core/src/main/java/bisq/core/btc/model/RawTransactionInput.java b/core/src/main/java/bisq/core/btc/model/RawTransactionInput.java index ef4d52116c..3a59ab07f9 100644 --- a/core/src/main/java/bisq/core/btc/model/RawTransactionInput.java +++ b/core/src/main/java/bisq/core/btc/model/RawTransactionInput.java @@ -30,11 +30,16 @@ import javax.annotation.concurrent.Immutable; @EqualsAndHashCode @Immutable public final class RawTransactionInput implements NetworkPayload, PersistablePayload { - // Payload - public final long index; - public final byte[] parentTransaction; + public final long index; // Index of spending txo + public final byte[] parentTransaction; // Spending tx (fromTx) public final long value; + /** + * Holds the relevant data for the connected output for a tx input. + * @param index the index of the parentTransaction + * @param parentTransaction the spending output tx, not the parent tx of the input + * @param value the number of satoshis being spent + */ public RawTransactionInput(long index, byte[] parentTransaction, long value) { this.index = index; this.parentTransaction = parentTransaction; diff --git a/core/src/main/java/bisq/core/btc/wallet/TradeWalletService.java b/core/src/main/java/bisq/core/btc/wallet/TradeWalletService.java index 8d03f8488d..4244e78534 100644 --- a/core/src/main/java/bisq/core/btc/wallet/TradeWalletService.java +++ b/core/src/main/java/bisq/core/btc/wallet/TradeWalletService.java @@ -1111,15 +1111,7 @@ public class TradeWalletService { byte[] buyerPubKey = ECKey.fromPublicOnly(Utils.HEX.decode(buyerPubKeyAsHex)).getPubKey(); byte[] sellerPubKey = ECKey.fromPublicOnly(Utils.HEX.decode(sellerPubKeyAsHex)).getPubKey(); Script redeemScript = get2of2MultiSigRedeemScript(buyerPubKey, sellerPubKey); - - Script hashedMultiSigOutputScript = get2of2MultiSigOutputScript(buyerPubKey, sellerPubKey, - hashedMultiSigOutputIsLegacy); - Coin msOutputValue = buyerPayoutAmount.add(sellerPayoutAmount).add(txFee); - TransactionOutput hashedMultiSigOutput = new TransactionOutput(params, null, msOutputValue, hashedMultiSigOutputScript.getProgram()); - Transaction depositTx = new Transaction(params); - depositTx.addOutput(hashedMultiSigOutput); - Transaction payoutTx = new Transaction(params); Sha256Hash spendTxHash = Sha256Hash.wrap(depositTxHex); payoutTx.addInput(new TransactionInput(params, payoutTx, new byte[]{}, new TransactionOutPoint(params, 0, spendTxHash), msOutputValue)); diff --git a/core/src/main/java/bisq/core/dao/DaoFacade.java b/core/src/main/java/bisq/core/dao/DaoFacade.java index b5d3462bff..e5e560b2f7 100644 --- a/core/src/main/java/bisq/core/dao/DaoFacade.java +++ b/core/src/main/java/bisq/core/dao/DaoFacade.java @@ -631,7 +631,7 @@ public class DaoFacade implements DaoSetupService { } public int getNumIssuanceTransactions(IssuanceType issuanceType) { - return daoStateService.getIssuanceSet(issuanceType).size(); + return daoStateService.getIssuanceSetForType(issuanceType).size(); } public Set getBurntFeeTxs() { diff --git a/core/src/main/java/bisq/core/dao/governance/blindvote/MyBlindVoteListService.java b/core/src/main/java/bisq/core/dao/governance/blindvote/MyBlindVoteListService.java index 3c09fc3d86..d0edacc099 100644 --- a/core/src/main/java/bisq/core/dao/governance/blindvote/MyBlindVoteListService.java +++ b/core/src/main/java/bisq/core/dao/governance/blindvote/MyBlindVoteListService.java @@ -286,7 +286,7 @@ public class MyBlindVoteListService implements PersistedDataHost, DaoStateListen .filter(txId -> periodService.isTxInPastCycle(txId, periodService.getChainHeight())) .collect(Collectors.toSet()); - return new MeritList(daoStateService.getIssuanceSet(IssuanceType.COMPENSATION).stream() + return new MeritList(daoStateService.getIssuanceSetForType(IssuanceType.COMPENSATION).stream() .map(issuance -> { checkArgument(issuance.getIssuanceType() == IssuanceType.COMPENSATION, "IssuanceType must be COMPENSATION for MeritList"); diff --git a/core/src/main/java/bisq/core/dao/governance/blindvote/network/RepublishGovernanceDataHandler.java b/core/src/main/java/bisq/core/dao/governance/blindvote/network/RepublishGovernanceDataHandler.java index ea73a102c2..9701159f72 100644 --- a/core/src/main/java/bisq/core/dao/governance/blindvote/network/RepublishGovernanceDataHandler.java +++ b/core/src/main/java/bisq/core/dao/governance/blindvote/network/RepublishGovernanceDataHandler.java @@ -102,7 +102,7 @@ public final class RepublishGovernanceDataHandler { connectToNextNode(); } else { log.warn("We have stopped already. We ignore that timeoutTimer.run call. " + - "Might be caused by an previous networkNode.sendMessage.onFailure."); + "Might be caused by a previous networkNode.sendMessage.onFailure."); } }, TIMEOUT); @@ -118,7 +118,7 @@ public final class RepublishGovernanceDataHandler { stop(); } else { log.trace("We have stopped already. We ignore that networkNode.sendMessage.onSuccess call." + - "Might be caused by an previous timeout."); + "Might be caused by a previous timeout."); } } @@ -133,7 +133,7 @@ public final class RepublishGovernanceDataHandler { connectToNextNode(); } else { log.trace("We have stopped already. We ignore that networkNode.sendMessage.onFailure call. " + - "Might be caused by an previous timeout."); + "Might be caused by a previous timeout."); } } }, MoreExecutors.directExecutor()); diff --git a/core/src/main/java/bisq/core/dao/governance/proposal/ProposalService.java b/core/src/main/java/bisq/core/dao/governance/proposal/ProposalService.java index e91616d9e1..a50b7e2f35 100644 --- a/core/src/main/java/bisq/core/dao/governance/proposal/ProposalService.java +++ b/core/src/main/java/bisq/core/dao/governance/proposal/ProposalService.java @@ -69,6 +69,7 @@ public class ProposalService implements HashMapChangedListener, AppendOnlyDataSt DaoStateListener, DaoSetupService { private final P2PService p2PService; private final PeriodService periodService; + private final ProposalStorageService proposalStorageService; private final DaoStateService daoStateService; private final ProposalValidatorProvider validatorProvider; @@ -100,6 +101,7 @@ public class ProposalService implements HashMapChangedListener, AppendOnlyDataSt @Named(Config.DAO_ACTIVATED) boolean daoActivated) { this.p2PService = p2PService; this.periodService = periodService; + this.proposalStorageService = proposalStorageService; this.daoStateService = daoStateService; this.validatorProvider = validatorProvider; @@ -217,7 +219,7 @@ public class ProposalService implements HashMapChangedListener, AppendOnlyDataSt } private void fillListFromAppendOnlyDataStore() { - p2PService.getP2PDataStorage().getAppendOnlyDataStoreMap().values().forEach(e -> onAppendOnlyDataAdded(e, false)); + proposalStorageService.getMap().values().forEach(e -> onAppendOnlyDataAdded(e, false)); } private void maybePublishToAppendOnlyDataStore() { diff --git a/core/src/main/java/bisq/core/dao/monitoring/DaoStateMonitoringService.java b/core/src/main/java/bisq/core/dao/monitoring/DaoStateMonitoringService.java index 34acd7c7b9..18eb1f9683 100644 --- a/core/src/main/java/bisq/core/dao/monitoring/DaoStateMonitoringService.java +++ b/core/src/main/java/bisq/core/dao/monitoring/DaoStateMonitoringService.java @@ -371,7 +371,7 @@ public class DaoStateMonitoringService implements DaoSetupService, DaoStateListe if (this.isInConflictWithSeedNode) log.warn("Conflict with seed nodes: {}", conflictMsg); else if (this.isInConflictWithNonSeedNode) - log.info("Conflict with non-seed nodes: {}", conflictMsg); + log.debug("Conflict with non-seed nodes: {}", conflictMsg); } diff --git a/core/src/main/java/bisq/core/dao/monitoring/network/RequestStateHashesHandler.java b/core/src/main/java/bisq/core/dao/monitoring/network/RequestStateHashesHandler.java index cc41c56ef6..602677121b 100644 --- a/core/src/main/java/bisq/core/dao/monitoring/network/RequestStateHashesHandler.java +++ b/core/src/main/java/bisq/core/dao/monitoring/network/RequestStateHashesHandler.java @@ -116,7 +116,7 @@ abstract class RequestStateHashesHandler genesisBlockHeight) startBlockHeight = chainHeight + 1; - log.info("Start parse blocks:\n" + + log.info("getStartBlockHeight:\n" + " Start block height={}\n" + " Genesis txId={}\n" + " Genesis block height={}\n" + @@ -223,15 +223,14 @@ public abstract class BsqNode implements DaoSetupService { // height we have no block but chainHeight is initially set to genesis height (bad design ;-( but a bit tricky // to change now as it used in many areas.) if (daoStateService.getBlockAtHeight(rawBlock.getHeight()).isPresent()) { - log.debug("We have already a block with the height of the new block. Height of new block={}", rawBlock.getHeight()); + log.info("We have already a block with the height of the new block. Height of new block={}", rawBlock.getHeight()); return Optional.empty(); } try { Block block = blockParser.parseBlock(rawBlock); - if (pendingBlocks.contains(rawBlock)) - pendingBlocks.remove(rawBlock); + pendingBlocks.remove(rawBlock); // After parsing we check if we have pending blocks we might have received earlier but which have been // not connecting from the latest height we had. The list is sorted by height diff --git a/core/src/main/java/bisq/core/dao/node/explorer/JsonTxOutputType.java b/core/src/main/java/bisq/core/dao/node/explorer/JsonTxOutputType.java index 0018f273d5..a5657bfaf8 100644 --- a/core/src/main/java/bisq/core/dao/node/explorer/JsonTxOutputType.java +++ b/core/src/main/java/bisq/core/dao/node/explorer/JsonTxOutputType.java @@ -43,7 +43,7 @@ enum JsonTxOutputType { INVALID_OUTPUT("Invalid"); @Getter - private String displayString; + private final String displayString; JsonTxOutputType(String displayString) { this.displayString = displayString; diff --git a/core/src/main/java/bisq/core/dao/node/explorer/JsonTxType.java b/core/src/main/java/bisq/core/dao/node/explorer/JsonTxType.java index d14e17f8a5..ee8ffd2527 100644 --- a/core/src/main/java/bisq/core/dao/node/explorer/JsonTxType.java +++ b/core/src/main/java/bisq/core/dao/node/explorer/JsonTxType.java @@ -40,7 +40,7 @@ enum JsonTxType { IRREGULAR("Irregular"); @Getter - private String displayString; + private final String displayString; JsonTxType(String displayString) { this.displayString = displayString; diff --git a/core/src/main/java/bisq/core/dao/node/full/network/FullNodeNetworkService.java b/core/src/main/java/bisq/core/dao/node/full/network/FullNodeNetworkService.java index 640ee94b15..3faf2b8bac 100644 --- a/core/src/main/java/bisq/core/dao/node/full/network/FullNodeNetworkService.java +++ b/core/src/main/java/bisq/core/dao/node/full/network/FullNodeNetworkService.java @@ -136,51 +136,62 @@ public class FullNodeNetworkService implements MessageListener, PeerManager.List @Override public void onMessage(NetworkEnvelope networkEnvelope, Connection connection) { if (networkEnvelope instanceof GetBlocksRequest) { - // We received a GetBlocksRequest from a liteNode - if (!stopped) { - final String uid = connection.getUid(); - if (!getBlocksRequestHandlers.containsKey(uid)) { - GetBlocksRequestHandler requestHandler = new GetBlocksRequestHandler(networkNode, - daoStateService, - new GetBlocksRequestHandler.Listener() { - @Override - public void onComplete() { - getBlocksRequestHandlers.remove(uid); - } - - @Override - public void onFault(String errorMessage, @Nullable Connection connection) { - getBlocksRequestHandlers.remove(uid); - if (!stopped) { - log.trace("GetDataRequestHandler failed.\n\tConnection={}\n\t" + - "ErrorMessage={}", connection, errorMessage); - peerManager.handleConnectionFault(connection); - } else { - log.warn("We have stopped already. We ignore that getDataRequestHandler.handle.onFault call."); - } - } - }); - getBlocksRequestHandlers.put(uid, requestHandler); - requestHandler.onGetBlocksRequest((GetBlocksRequest) networkEnvelope, connection); - } else { - log.warn("We have already a GetDataRequestHandler for that connection started. " + - "We start a cleanup timer if the handler has not closed by itself in between 2 minutes."); - - UserThread.runAfter(() -> { - if (getBlocksRequestHandlers.containsKey(uid)) { - GetBlocksRequestHandler handler = getBlocksRequestHandlers.get(uid); - handler.stop(); - getBlocksRequestHandlers.remove(uid); - } - }, CLEANUP_TIMER); - } - } else { - log.warn("We have stopped already. We ignore that onMessage call."); - } + handleGetBlocksRequest((GetBlocksRequest) networkEnvelope, connection); } else if (networkEnvelope instanceof RepublishGovernanceDataRequest) { - log.warn("We received a RepublishGovernanceDataRequest and re-published all proposalPayloads and " + - "blindVotePayloads to the P2P network."); - missingDataRequestService.reRepublishAllGovernanceData(); + handleRepublishGovernanceDataRequest(); } } + + private void handleGetBlocksRequest(GetBlocksRequest getBlocksRequest, Connection connection) { + if (stopped) { + log.warn("We have stopped already. We ignore that onMessage call."); + return; + } + + String uid = connection.getUid(); + if (getBlocksRequestHandlers.containsKey(uid)) { + log.warn("We have already a GetDataRequestHandler for that connection started. " + + "We start a cleanup timer if the handler has not closed by itself in between 2 minutes."); + + UserThread.runAfter(() -> { + if (getBlocksRequestHandlers.containsKey(uid)) { + GetBlocksRequestHandler handler = getBlocksRequestHandlers.get(uid); + handler.stop(); + getBlocksRequestHandlers.remove(uid); + } + }, CLEANUP_TIMER); + return; + } + + GetBlocksRequestHandler requestHandler = new GetBlocksRequestHandler(networkNode, + daoStateService, + new GetBlocksRequestHandler.Listener() { + @Override + public void onComplete() { + getBlocksRequestHandlers.remove(uid); + } + + @Override + public void onFault(String errorMessage, @Nullable Connection connection) { + getBlocksRequestHandlers.remove(uid); + if (!stopped) { + log.trace("GetDataRequestHandler failed.\n\tConnection={}\n\t" + + "ErrorMessage={}", connection, errorMessage); + if (connection != null) { + peerManager.handleConnectionFault(connection); + } + } else { + log.warn("We have stopped already. We ignore that getDataRequestHandler.handle.onFault call."); + } + } + }); + getBlocksRequestHandlers.put(uid, requestHandler); + requestHandler.onGetBlocksRequest(getBlocksRequest, connection); + } + + private void handleRepublishGovernanceDataRequest() { + log.warn("We received a RepublishGovernanceDataRequest and re-published all proposalPayloads and " + + "blindVotePayloads to the P2P network."); + missingDataRequestService.reRepublishAllGovernanceData(); + } } diff --git a/core/src/main/java/bisq/core/dao/node/full/network/GetBlocksRequestHandler.java b/core/src/main/java/bisq/core/dao/node/full/network/GetBlocksRequestHandler.java index b197970f1a..dd8d6e9203 100644 --- a/core/src/main/java/bisq/core/dao/node/full/network/GetBlocksRequestHandler.java +++ b/core/src/main/java/bisq/core/dao/node/full/network/GetBlocksRequestHandler.java @@ -49,7 +49,7 @@ import org.jetbrains.annotations.NotNull; */ @Slf4j class GetBlocksRequestHandler { - private static final long TIMEOUT = 120; + private static final long TIMEOUT_MIN = 3; /////////////////////////////////////////////////////////////////////////////////////////// @@ -89,22 +89,28 @@ class GetBlocksRequestHandler { // API /////////////////////////////////////////////////////////////////////////////////////////// - public void onGetBlocksRequest(GetBlocksRequest getBlocksRequest, final Connection connection) { + public void onGetBlocksRequest(GetBlocksRequest getBlocksRequest, Connection connection) { + long ts = System.currentTimeMillis(); // We limit number of blocks to 6000 which is about 1.5 month. List blocks = new LinkedList<>(daoStateService.getBlocksFromBlockHeight(getBlocksRequest.getFromBlockHeight(), 6000)); List rawBlocks = blocks.stream().map(RawBlock::fromBlock).collect(Collectors.toList()); GetBlocksResponse getBlocksResponse = new GetBlocksResponse(rawBlocks, getBlocksRequest.getNonce()); - log.info("Received GetBlocksRequest from {} for blocks from height {}", - connection.getPeersNodeAddressOptional(), getBlocksRequest.getFromBlockHeight()); - if (timeoutTimer == null) { - timeoutTimer = UserThread.runAfter(() -> { // setup before sending to avoid race conditions - String errorMessage = "A timeout occurred for getBlocksResponse.requestNonce:" + - getBlocksResponse.getRequestNonce() + - " on connection:" + connection; - handleFault(errorMessage, CloseConnectionReason.SEND_MSG_TIMEOUT, connection); - }, - TIMEOUT, TimeUnit.SECONDS); + log.info("Received GetBlocksRequest from {} for blocks from height {}. " + + "Building GetBlocksResponse with {} blocks took {} ms.", + connection.getPeersNodeAddressOptional(), getBlocksRequest.getFromBlockHeight(), + rawBlocks.size(), System.currentTimeMillis() - ts); + + if (timeoutTimer != null) { + timeoutTimer.stop(); + log.warn("Timeout was already running. We stopped it."); } + timeoutTimer = UserThread.runAfter(() -> { // setup before sending to avoid race conditions + String errorMessage = "A timeout occurred for getBlocksResponse.requestNonce:" + + getBlocksResponse.getRequestNonce() + + " on connection: " + connection; + handleFault(errorMessage, CloseConnectionReason.SEND_MSG_TIMEOUT, connection); + }, + TIMEOUT_MIN, TimeUnit.MINUTES); SettableFuture future = networkNode.sendMessage(connection, getBlocksResponse); Futures.addCallback(future, new FutureCallback<>() { @@ -145,7 +151,7 @@ class GetBlocksRequestHandler { private void handleFault(String errorMessage, CloseConnectionReason closeConnectionReason, Connection connection) { if (!stopped) { - log.debug(errorMessage + "\n\tcloseConnectionReason=" + closeConnectionReason); + log.warn("{}, closeConnectionReason={}", errorMessage, closeConnectionReason); cleanup(); listener.onFault(errorMessage, connection); } else { diff --git a/core/src/main/java/bisq/core/dao/node/lite/LiteNode.java b/core/src/main/java/bisq/core/dao/node/lite/LiteNode.java index a51c5a1123..c0c8b64980 100644 --- a/core/src/main/java/bisq/core/dao/node/lite/LiteNode.java +++ b/core/src/main/java/bisq/core/dao/node/lite/LiteNode.java @@ -17,6 +17,7 @@ package bisq.core.dao.node.lite; +import bisq.core.btc.setup.WalletsSetup; import bisq.core.btc.wallet.BsqWalletService; import bisq.core.dao.node.BsqNode; import bisq.core.dao.node.explorer.ExportJsonFilesService; @@ -37,6 +38,8 @@ import bisq.common.UserThread; import com.google.inject.Inject; +import javafx.beans.value.ChangeListener; + import java.util.ArrayList; import java.util.List; @@ -54,7 +57,9 @@ public class LiteNode extends BsqNode { private final LiteNodeNetworkService liteNodeNetworkService; private final BsqWalletService bsqWalletService; + private final WalletsSetup walletsSetup; private Timer checkForBlockReceivedTimer; + private final ChangeListener blockDownloadListener; /////////////////////////////////////////////////////////////////////////////////////////// @@ -69,11 +74,19 @@ public class LiteNode extends BsqNode { P2PService p2PService, LiteNodeNetworkService liteNodeNetworkService, BsqWalletService bsqWalletService, + WalletsSetup walletsSetup, ExportJsonFilesService exportJsonFilesService) { super(blockParser, daoStateService, daoStateSnapshotService, p2PService, exportJsonFilesService); this.liteNodeNetworkService = liteNodeNetworkService; this.bsqWalletService = bsqWalletService; + this.walletsSetup = walletsSetup; + + blockDownloadListener = (observable, oldValue, newValue) -> { + if ((double) newValue == 1) { + setupWalletBestBlockListener(); + } + }; } @@ -87,7 +100,18 @@ public class LiteNode extends BsqNode { liteNodeNetworkService.start(); - bsqWalletService.addNewBestBlockListener(block -> { + // We wait until the wallet is synced before using it for triggering requests + if (walletsSetup.isDownloadComplete()) { + setupWalletBestBlockListener(); + } else { + walletsSetup.downloadPercentageProperty().addListener(blockDownloadListener); + } + } + + private void setupWalletBestBlockListener() { + walletsSetup.downloadPercentageProperty().removeListener(blockDownloadListener); + + bsqWalletService.addNewBestBlockListener(blockFromWallet -> { // Check if we are done with parsing if (!daoStateService.isParseBlockChainComplete()) return; @@ -97,18 +121,18 @@ public class LiteNode extends BsqNode { checkForBlockReceivedTimer.stop(); } - int height = block.getHeight(); - log.info("New block at height {} from bsqWalletService", height); + int walletBlockHeight = blockFromWallet.getHeight(); + log.info("New block at height {} from bsqWalletService", walletBlockHeight); // We expect to receive the new BSQ block from the network shortly after BitcoinJ has been aware of it. // If we don't receive it we request it manually from seed nodes checkForBlockReceivedTimer = UserThread.runAfter(() -> { - int chainHeight = daoStateService.getChainHeight(); - if (chainHeight < height) { - log.warn("We did not receive a block from the network {} seconds after we saw the new block in BicoinJ. " + + int daoChainHeight = daoStateService.getChainHeight(); + if (daoChainHeight < walletBlockHeight) { + log.warn("We did not receive a block from the network {} seconds after we saw the new block in BitcoinJ. " + "We request from our seed nodes missing blocks from block height {}.", - CHECK_FOR_BLOCK_RECEIVED_DELAY_SEC, chainHeight + 1); - liteNodeNetworkService.requestBlocks(chainHeight + 1); + CHECK_FOR_BLOCK_RECEIVED_DELAY_SEC, daoChainHeight + 1); + liteNodeNetworkService.requestBlocks(daoChainHeight + 1); } }, CHECK_FOR_BLOCK_RECEIVED_DELAY_SEC); }); @@ -157,7 +181,6 @@ public class LiteNode extends BsqNode { // First we request the blocks from a full node @Override protected void startParseBlocks() { - log.info("startParseBlocks"); liteNodeNetworkService.requestBlocks(getStartBlockHeight()); } @@ -199,8 +222,12 @@ public class LiteNode extends BsqNode { runDelayedBatchProcessing(new ArrayList<>(blockList), () -> { - log.debug("Parsing {} blocks took {} seconds.", blockList.size(), (System.currentTimeMillis() - ts) / 1000d); - if (daoStateService.getChainHeight() < bsqWalletService.getBestChainHeight()) { + log.info("runDelayedBatchProcessing Parsing {} blocks took {} seconds.", blockList.size(), + (System.currentTimeMillis() - ts) / 1000d); + // We only request again if wallet is synced, otherwise we would get repeated calls we want to avoid. + // We deal with that case at the setupWalletBestBlockListener method above. + if (walletsSetup.isDownloadComplete() && + daoStateService.getChainHeight() < bsqWalletService.getBestChainHeight()) { liteNodeNetworkService.requestBlocks(getStartBlockHeight()); } else { onParsingComplete.run(); @@ -229,11 +256,13 @@ public class LiteNode extends BsqNode { // We received a new block private void onNewBlockReceived(RawBlock block) { int blockHeight = block.getHeight(); - log.debug("onNewBlockReceived: block at height {}, hash={}", blockHeight, block.getHash()); + log.info("onNewBlockReceived: block at height {}, hash={}. Our DAO chainHeight={}", + blockHeight, block.getHash(), chainTipHeight); // We only update chainTipHeight if we get a newer block - if (blockHeight > chainTipHeight) + if (blockHeight > chainTipHeight) { chainTipHeight = blockHeight; + } try { doParseBlock(block); diff --git a/core/src/main/java/bisq/core/dao/node/lite/network/LiteNodeNetworkService.java b/core/src/main/java/bisq/core/dao/node/lite/network/LiteNodeNetworkService.java index 0b40e80b96..f13d99aa8b 100644 --- a/core/src/main/java/bisq/core/dao/node/lite/network/LiteNodeNetworkService.java +++ b/core/src/main/java/bisq/core/dao/node/lite/network/LiteNodeNetworkService.java @@ -99,7 +99,7 @@ public class LiteNodeNetworkService implements MessageListener, ConnectionListen private final Map, RequestBlocksHandler> requestBlocksHandlerMap = new HashMap<>(); private Timer retryTimer; private boolean stopped; - private Set receivedBlocks = new HashSet<>(); + private final Set receivedBlocks = new HashSet<>(); /////////////////////////////////////////////////////////////////////////////////////////// @@ -129,7 +129,6 @@ public class LiteNodeNetworkService implements MessageListener, ConnectionListen peerManager.addListener(this); } - @SuppressWarnings("Duplicates") public void shutDown() { stopped = true; stopRetryTimer(); @@ -152,19 +151,21 @@ public class LiteNodeNetworkService implements MessageListener, ConnectionListen Optional connectionToSeedNodeOptional = networkNode.getConfirmedConnections().stream() .filter(peerManager::isSeedNode) .findAny(); - if (connectionToSeedNodeOptional.isPresent() && - connectionToSeedNodeOptional.get().getPeersNodeAddressOptional().isPresent()) { - requestBlocks(connectionToSeedNodeOptional.get().getPeersNodeAddressOptional().get(), startBlockHeight); - } else { - tryWithNewSeedNode(startBlockHeight); - } + + connectionToSeedNodeOptional.flatMap(Connection::getPeersNodeAddressOptional) + .ifPresentOrElse(candidate -> { + seedNodeAddresses.remove(candidate); + requestBlocks(candidate, startBlockHeight); + }, () -> { + tryWithNewSeedNode(startBlockHeight); + }); } public void reset() { lastRequestedBlockHeight = 0; lastReceivedBlockHeight = 0; retryCounter = 0; - requestBlocksHandlerMap.values().forEach(RequestBlocksHandler::cancel); + requestBlocksHandlerMap.values().forEach(RequestBlocksHandler::terminate); } @@ -202,7 +203,6 @@ public class LiteNodeNetworkService implements MessageListener, ConnectionListen closeAllHandlers(); stopRetryTimer(); stopped = true; - tryWithNewSeedNode(lastRequestedBlockHeight); } @@ -218,8 +218,7 @@ public class LiteNodeNetworkService implements MessageListener, ConnectionListen log.info("onAwakeFromStandby"); closeAllHandlers(); stopped = false; - if (!networkNode.getAllConnections().isEmpty()) - tryWithNewSeedNode(lastRequestedBlockHeight); + tryWithNewSeedNode(lastRequestedBlockHeight); } @@ -232,17 +231,20 @@ public class LiteNodeNetworkService implements MessageListener, ConnectionListen if (networkEnvelope instanceof NewBlockBroadcastMessage) { NewBlockBroadcastMessage newBlockBroadcastMessage = (NewBlockBroadcastMessage) networkEnvelope; // We combine blockHash and txId list in case we receive blocks with different transactions. - List txIds = newBlockBroadcastMessage.getBlock().getRawTxs().stream().map(BaseTx::getId).collect(Collectors.toList()); - String extBlockId = newBlockBroadcastMessage.getBlock().getHash() + ":" + txIds; - if (!receivedBlocks.contains(extBlockId)) { - log.debug("We received a new message from peer {} and broadcast it to our peers. extBlockId={}", - connection.getPeersNodeAddressOptional().orElse(null), extBlockId); - receivedBlocks.add(extBlockId); - broadcaster.broadcast(newBlockBroadcastMessage, connection.getPeersNodeAddressOptional().orElse(null)); - listeners.forEach(listener -> listener.onNewBlockReceived(newBlockBroadcastMessage)); - } else { - log.debug("We had that message already and do not further broadcast it. extBlockId={}", extBlockId); + List txIds = newBlockBroadcastMessage.getBlock().getRawTxs().stream() + .map(BaseTx::getId) + .collect(Collectors.toList()); + String blockUid = newBlockBroadcastMessage.getBlock().getHash() + ":" + txIds; + if (receivedBlocks.contains(blockUid)) { + log.debug("We had that message already and do not further broadcast it. blockUid={}", blockUid); + return; } + + log.info("We received a NewBlockBroadcastMessage from peer {} and broadcast it to our peers. blockUid={}", + connection.getPeersNodeAddressOptional().orElse(null), blockUid); + receivedBlocks.add(blockUid); + broadcaster.broadcast(newBlockBroadcastMessage, connection.getPeersNodeAddressOptional().orElse(null)); + listeners.forEach(listener -> listener.onNewBlockReceived(newBlockBroadcastMessage)); } } @@ -252,78 +254,85 @@ public class LiteNodeNetworkService implements MessageListener, ConnectionListen /////////////////////////////////////////////////////////////////////////////////////////// private void requestBlocks(NodeAddress peersNodeAddress, int startBlockHeight) { - if (!stopped) { - final Tuple2 key = new Tuple2<>(peersNodeAddress, startBlockHeight); - if (!requestBlocksHandlerMap.containsKey(key)) { - if (startBlockHeight >= lastReceivedBlockHeight) { - RequestBlocksHandler requestBlocksHandler = new RequestBlocksHandler(networkNode, - peerManager, - peersNodeAddress, - startBlockHeight, - new RequestBlocksHandler.Listener() { - @Override - public void onComplete(GetBlocksResponse getBlocksResponse) { - log.debug("requestBlocksHandler of outbound connection complete. nodeAddress={}", - peersNodeAddress); - stopRetryTimer(); - - // need to remove before listeners are notified as they cause the update call - requestBlocksHandlerMap.remove(key); - // we only notify if our request was latest - if (startBlockHeight >= lastReceivedBlockHeight) { - lastReceivedBlockHeight = startBlockHeight; - - listeners.forEach(listener -> listener.onRequestedBlocksReceived(getBlocksResponse, - () -> { - // After we received the blocks we allow to disconnect seed nodes. - // We delay 20 seconds to allow multiple requests to finish. - UserThread.runAfter(() -> peerManager.setAllowDisconnectSeedNodes(true), 20); - })); - } else { - log.warn("We got a response which is already obsolete because we receive a " + - "response from a request with a higher block height. " + - "This could theoretically happen, but is very unlikely."); - } - } - - @Override - public void onFault(String errorMessage, @Nullable Connection connection) { - log.warn("requestBlocksHandler with outbound connection failed.\n\tnodeAddress={}\n\t" + - "ErrorMessage={}", peersNodeAddress, errorMessage); - - peerManager.handleConnectionFault(peersNodeAddress); - requestBlocksHandlerMap.remove(key); - - listeners.forEach(listener -> listener.onFault(errorMessage, connection)); - - tryWithNewSeedNode(startBlockHeight); - } - }); - requestBlocksHandlerMap.put(key, requestBlocksHandler); - log.info("requestBlocks with startBlockHeight={} from peer {}", startBlockHeight, peersNodeAddress); - requestBlocksHandler.requestBlocks(); - } else { - log.warn("startBlockHeight must not be smaller than lastReceivedBlockHeight. That should never happen." + - "startBlockHeight={},lastReceivedBlockHeight={}", startBlockHeight, lastReceivedBlockHeight); - DevEnv.logErrorAndThrowIfDevMode("startBlockHeight must be larger than lastReceivedBlockHeight. startBlockHeight=" + - startBlockHeight + " / lastReceivedBlockHeight=" + lastReceivedBlockHeight); - } - } else { - log.warn("We have started already a requestDataHandshake for startBlockHeight {} to peer. nodeAddress={}\n" + - "We start a cleanup timer if the handler has not closed by itself in between 2 minutes.", - peersNodeAddress, startBlockHeight); - - UserThread.runAfter(() -> { - if (requestBlocksHandlerMap.containsKey(key)) { - RequestBlocksHandler handler = requestBlocksHandlerMap.get(key); - handler.stop(); - requestBlocksHandlerMap.remove(key); - } - }, CLEANUP_TIMER); - } - } else { + if (stopped) { log.warn("We have stopped already. We ignore that requestData call."); + return; } + + Tuple2 key = new Tuple2<>(peersNodeAddress, startBlockHeight); + if (requestBlocksHandlerMap.containsKey(key)) { + log.warn("We have started already a requestDataHandshake for startBlockHeight {} to peer. nodeAddress={}\n" + + "We start a cleanup timer if the handler has not closed by itself in between 2 minutes.", + peersNodeAddress, startBlockHeight); + + UserThread.runAfter(() -> { + if (requestBlocksHandlerMap.containsKey(key)) { + RequestBlocksHandler handler = requestBlocksHandlerMap.get(key); + handler.terminate(); + requestBlocksHandlerMap.remove(key); + } + }, CLEANUP_TIMER); + return; + } + + if (startBlockHeight < lastReceivedBlockHeight) { + log.warn("startBlockHeight must not be smaller than lastReceivedBlockHeight. That should never happen." + + "startBlockHeight={},lastReceivedBlockHeight={}", startBlockHeight, lastReceivedBlockHeight); + DevEnv.logErrorAndThrowIfDevMode("startBlockHeight must be larger than lastReceivedBlockHeight. startBlockHeight=" + + startBlockHeight + " / lastReceivedBlockHeight=" + lastReceivedBlockHeight); + return; + } + + // In case we would have had an earlier request and had set allowDisconnectSeedNodes to true we un-do that + // if we get a repeated request. + peerManager.setAllowDisconnectSeedNodes(false); + RequestBlocksHandler requestBlocksHandler = new RequestBlocksHandler(networkNode, + peerManager, + peersNodeAddress, + startBlockHeight, + new RequestBlocksHandler.Listener() { + @Override + public void onComplete(GetBlocksResponse getBlocksResponse) { + log.info("requestBlocksHandler to {} completed", peersNodeAddress); + stopRetryTimer(); + + // need to remove before listeners are notified as they cause the update call + requestBlocksHandlerMap.remove(key); + // we only notify if our request was latest + if (startBlockHeight >= lastReceivedBlockHeight) { + lastReceivedBlockHeight = startBlockHeight; + + listeners.forEach(listener -> listener.onRequestedBlocksReceived(getBlocksResponse, + () -> { + // After we received the blocks we allow to disconnect seed nodes. + // We delay 20 seconds to allow multiple requests to finish. + UserThread.runAfter(() -> peerManager.setAllowDisconnectSeedNodes(true), 20); + })); + } else { + log.warn("We got a response which is already obsolete because we received a " + + "response from a request with a higher block height. " + + "This could theoretically happen, but is very unlikely."); + } + } + + @Override + public void onFault(String errorMessage, @Nullable Connection connection) { + log.warn("requestBlocksHandler with outbound connection failed.\n\tnodeAddress={}\n\t" + + "ErrorMessage={}", peersNodeAddress, errorMessage); + + peerManager.handleConnectionFault(peersNodeAddress); + requestBlocksHandlerMap.remove(key); + + listeners.forEach(listener -> listener.onFault(errorMessage, connection)); + + // We allow now to disconnect from that seed. + peerManager.setAllowDisconnectSeedNodes(true); + + tryWithNewSeedNode(startBlockHeight); + } + }); + requestBlocksHandlerMap.put(key, requestBlocksHandler); + requestBlocksHandler.requestBlocks(); } @@ -332,37 +341,52 @@ public class LiteNodeNetworkService implements MessageListener, ConnectionListen /////////////////////////////////////////////////////////////////////////////////////////// private void tryWithNewSeedNode(int startBlockHeight) { - if (retryTimer == null) { - retryCounter++; - if (retryCounter <= MAX_RETRY) { - retryTimer = UserThread.runAfter(() -> { - stopped = false; - - stopRetryTimer(); - - List list = seedNodeAddresses.stream() - .filter(e -> peerManager.isSeedNode(e) && !peerManager.isSelf(e)) - .collect(Collectors.toList()); - Collections.shuffle(list); - - if (!list.isEmpty()) { - NodeAddress nextCandidate = list.get(0); - seedNodeAddresses.remove(nextCandidate); - log.info("We try requestBlocks with {}", nextCandidate); - requestBlocks(nextCandidate, startBlockHeight); - } else { - log.warn("No more seed nodes available we could try."); - listeners.forEach(Listener::onNoSeedNodeAvailable); - } - }, - RETRY_DELAY_SEC); - } else { - log.warn("We tried {} times but could not connect to a seed node.", retryCounter); - listeners.forEach(Listener::onNoSeedNodeAvailable); - } - } else { - log.warn("We have a retry timer already running."); + if (networkNode.getAllConnections().isEmpty()) { + return; } + + if (lastRequestedBlockHeight == 0) { + return; + } + + if (stopped) { + return; + } + + if (retryTimer != null) { + log.warn("We have a retry timer already running."); + return; + } + + retryCounter++; + + if (retryCounter > MAX_RETRY) { + log.warn("We tried {} times but could not connect to a seed node.", retryCounter); + listeners.forEach(Listener::onNoSeedNodeAvailable); + return; + } + + retryTimer = UserThread.runAfter(() -> { + stopped = false; + + stopRetryTimer(); + + List list = seedNodeAddresses.stream() + .filter(e -> peerManager.isSeedNode(e) && !peerManager.isSelf(e)) + .collect(Collectors.toList()); + Collections.shuffle(list); + + if (!list.isEmpty()) { + NodeAddress nextCandidate = list.get(0); + seedNodeAddresses.remove(nextCandidate); + log.info("We try requestBlocks from {} with startBlockHeight={}", nextCandidate, startBlockHeight); + requestBlocks(nextCandidate, startBlockHeight); + } else { + log.warn("No more seed nodes available we could try."); + listeners.forEach(Listener::onNoSeedNodeAvailable); + } + }, + RETRY_DELAY_SEC); } private void stopRetryTimer() { @@ -386,17 +410,14 @@ public class LiteNodeNetworkService implements MessageListener, ConnectionListen requestBlocksHandlerMap.entrySet().stream() .filter(e -> e.getKey().first.equals(nodeAddress)) .findAny() - .map(Map.Entry::getValue) - .ifPresent(handler -> { - final Tuple2 key = new Tuple2<>(handler.getNodeAddress(), handler.getStartBlockHeight()); - requestBlocksHandlerMap.get(key).cancel(); - requestBlocksHandlerMap.remove(key); + .ifPresent(e -> { + e.getValue().terminate(); + requestBlocksHandlerMap.remove(e.getKey()); }); } - private void closeAllHandlers() { - requestBlocksHandlerMap.values().forEach(RequestBlocksHandler::cancel); + requestBlocksHandlerMap.values().forEach(RequestBlocksHandler::terminate); requestBlocksHandlerMap.clear(); } } diff --git a/core/src/main/java/bisq/core/dao/node/lite/network/RequestBlocksHandler.java b/core/src/main/java/bisq/core/dao/node/lite/network/RequestBlocksHandler.java index 60374ffd7d..752e4829f8 100644 --- a/core/src/main/java/bisq/core/dao/node/lite/network/RequestBlocksHandler.java +++ b/core/src/main/java/bisq/core/dao/node/lite/network/RequestBlocksHandler.java @@ -36,7 +36,9 @@ import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.MoreExecutors; import com.google.common.util.concurrent.SettableFuture; +import java.util.Optional; import java.util.Random; +import java.util.concurrent.TimeUnit; import lombok.Getter; import lombok.extern.slf4j.Slf4j; @@ -44,14 +46,12 @@ import lombok.extern.slf4j.Slf4j; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import static com.google.common.base.Preconditions.checkArgument; - /** * Sends a GetBlocksRequest to a full node and listens on corresponding GetBlocksResponse from the full node. */ @Slf4j public class RequestBlocksHandler implements MessageListener { - private static final long TIMEOUT = 120; + private static final long TIMEOUT_MIN = 3; /////////////////////////////////////////////////////////////////////////////////////////// @@ -98,66 +98,61 @@ public class RequestBlocksHandler implements MessageListener { this.listener = listener; } - public void cancel() { - cleanup(); - } - /////////////////////////////////////////////////////////////////////////////////////////// // API /////////////////////////////////////////////////////////////////////////////////////////// public void requestBlocks() { - if (!stopped) { - GetBlocksRequest getBlocksRequest = new GetBlocksRequest(startBlockHeight, nonce, networkNode.getNodeAddress()); - log.debug("getBlocksRequest " + getBlocksRequest); - if (timeoutTimer == null) { - timeoutTimer = UserThread.runAfter(() -> { // setup before sending to avoid race conditions - if (!stopped) { - String errorMessage = "A timeout occurred when sending getBlocksRequest:" + getBlocksRequest + - " on peersNodeAddress:" + nodeAddress; - log.debug(errorMessage + " / RequestDataHandler=" + RequestBlocksHandler.this); - handleFault(errorMessage, nodeAddress, CloseConnectionReason.SEND_MSG_TIMEOUT); - } else { - log.trace("We have stopped already. We ignore that timeoutTimer.run call. " + - "Might be caused by an previous networkNode.sendMessage.onFailure."); - } - }, - TIMEOUT); + if (stopped) { + log.warn("We have stopped already. We ignore that requestData call."); + return; + } + + GetBlocksRequest getBlocksRequest = new GetBlocksRequest(startBlockHeight, nonce, networkNode.getNodeAddress()); + + if (timeoutTimer != null) { + log.warn("We had a timer already running and stop it."); + timeoutTimer.stop(); + } + timeoutTimer = UserThread.runAfter(() -> { // setup before sending to avoid race conditions + if (!stopped) { + String errorMessage = "A timeout occurred when sending getBlocksRequest:" + getBlocksRequest + + " on peersNodeAddress:" + nodeAddress; + log.debug("{} / RequestDataHandler={}", errorMessage, RequestBlocksHandler.this); + handleFault(errorMessage, nodeAddress, CloseConnectionReason.SEND_MSG_TIMEOUT); + } else { + log.warn("We have stopped already. We ignore that timeoutTimer.run call. " + + "Might be caused by a previous networkNode.sendMessage.onFailure."); + } + }, + TIMEOUT_MIN, TimeUnit.MINUTES); + + log.info("We request blocks from peer {} from block height {}.", nodeAddress, getBlocksRequest.getFromBlockHeight()); + + networkNode.addMessageListener(this); + + SettableFuture future = networkNode.sendMessage(nodeAddress, getBlocksRequest); + Futures.addCallback(future, new FutureCallback<>() { + @Override + public void onSuccess(Connection connection) { + log.info("Sending of GetBlocksRequest message to peer {} succeeded.", nodeAddress.getFullAddress()); } - log.info("We request blocks from peer {} from block height {}.", nodeAddress, getBlocksRequest.getFromBlockHeight()); - networkNode.addMessageListener(this); - SettableFuture future = networkNode.sendMessage(nodeAddress, getBlocksRequest); - Futures.addCallback(future, new FutureCallback<>() { - @Override - public void onSuccess(Connection connection) { - if (!stopped) { - log.info("Sending of GetBlocksRequest message to peer {} succeeded.", nodeAddress.getFullAddress()); - } else { - log.trace("We have stopped already. We ignore that networkNode.sendMessage.onSuccess call." + - "Might be caused by a previous timeout."); - } + @Override + public void onFailure(@NotNull Throwable throwable) { + if (!stopped) { + String errorMessage = "Sending getBlocksRequest to " + nodeAddress + + " failed. That is expected if the peer is offline.\n\t" + + "getBlocksRequest=" + getBlocksRequest + "." + + "\n\tException=" + throwable.getMessage(); + log.error(errorMessage); + handleFault(errorMessage, nodeAddress, CloseConnectionReason.SEND_MSG_FAILURE); + } else { + log.warn("We have stopped already. We ignore that networkNode.sendMessage.onFailure call."); } - - @Override - public void onFailure(@NotNull Throwable throwable) { - if (!stopped) { - String errorMessage = "Sending getBlocksRequest to " + nodeAddress + - " failed. That is expected if the peer is offline.\n\t" + - "getBlocksRequest=" + getBlocksRequest + "." + - "\n\tException=" + throwable.getMessage(); - log.error(errorMessage); - handleFault(errorMessage, nodeAddress, CloseConnectionReason.SEND_MSG_FAILURE); - } else { - log.trace("We have stopped already. We ignore that networkNode.sendMessage.onFailure call. " + - "Might be caused by a previous timeout."); - } - } - }, MoreExecutors.directExecutor()); - } else { - log.warn("We have stopped already. We ignore that requestData call."); - } + } + }, MoreExecutors.directExecutor()); } @@ -168,56 +163,60 @@ public class RequestBlocksHandler implements MessageListener { @Override public void onMessage(NetworkEnvelope networkEnvelope, Connection connection) { if (networkEnvelope instanceof GetBlocksResponse) { - if (connection.getPeersNodeAddressOptional().isPresent() && connection.getPeersNodeAddressOptional().get().equals(nodeAddress)) { - if (!stopped) { - GetBlocksResponse getBlocksResponse = (GetBlocksResponse) networkEnvelope; - if (getBlocksResponse.getRequestNonce() == nonce) { - stopTimeoutTimer(); - checkArgument(connection.getPeersNodeAddressOptional().isPresent(), - "RequestDataHandler.onMessage: connection.getPeersNodeAddressOptional() must be present " + - "at that moment"); - cleanup(); - log.info("We received from peer {} a BlocksResponse with {} blocks", - nodeAddress.getFullAddress(), getBlocksResponse.getBlocks().size()); - listener.onComplete(getBlocksResponse); - } else { - log.warn("Nonce not matching. That can happen rarely if we get a response after a canceled " + - "handshake (timeout causes connection close but peer might have sent a msg before " + - "connection was closed).\n\t" + - "We drop that message. nonce={} / requestNonce={}", - nonce, getBlocksResponse.getRequestNonce()); - } - } else { - log.warn("We have stopped already. We ignore that onDataRequest call."); - } - } else { - log.warn("We got a message from ourselves. That should never happen."); + if (stopped) { + log.warn("We have stopped already. We ignore that onDataRequest call."); + return; } + + Optional optionalNodeAddress = connection.getPeersNodeAddressOptional(); + if (!optionalNodeAddress.isPresent()) { + log.warn("Peers node address is not present, that is not expected."); + // We do not return here as in case the connection has been created from the peers side we might not + // have the address set. As we check the nonce later we do not care that much for the check if the + // connection address is the same as the one we used. + } else if (!optionalNodeAddress.get().equals(nodeAddress)) { + log.warn("Peers node address is not the same we used for the request. This is not expected. We ignore that message."); + return; + } + + GetBlocksResponse getBlocksResponse = (GetBlocksResponse) networkEnvelope; + if (getBlocksResponse.getRequestNonce() != nonce) { + log.warn("Nonce not matching. That can happen rarely if we get a response after a canceled " + + "handshake (timeout causes connection close but peer might have sent a msg before " + + "connection was closed).\n\t" + + "We drop that message. nonce={} / requestNonce={}", + nonce, getBlocksResponse.getRequestNonce()); + return; + } + + terminate(); + log.info("We received from peer {} a BlocksResponse with {} blocks", + nodeAddress.getFullAddress(), getBlocksResponse.getBlocks().size()); + listener.onComplete(getBlocksResponse); } } - public void stop() { - cleanup(); + public void terminate() { + stopped = true; + networkNode.removeMessageListener(this); + stopTimeoutTimer(); } + /////////////////////////////////////////////////////////////////////////////////////////// // Private /////////////////////////////////////////////////////////////////////////////////////////// @SuppressWarnings("UnusedParameters") - private void handleFault(String errorMessage, NodeAddress nodeAddress, CloseConnectionReason closeConnectionReason) { - cleanup(); + private void handleFault(String errorMessage, + NodeAddress nodeAddress, + CloseConnectionReason closeConnectionReason) { + terminate(); peerManager.handleConnectionFault(nodeAddress); listener.onFault(errorMessage, null); } - private void cleanup() { - stopped = true; - networkNode.removeMessageListener(this); - stopTimeoutTimer(); - } - private void stopTimeoutTimer() { if (timeoutTimer != null) { timeoutTimer.stop(); diff --git a/core/src/main/java/bisq/core/dao/node/parser/TempTx.java b/core/src/main/java/bisq/core/dao/node/parser/TempTx.java index e7bac4d2e3..b98d2f4579 100644 --- a/core/src/main/java/bisq/core/dao/node/parser/TempTx.java +++ b/core/src/main/java/bisq/core/dao/node/parser/TempTx.java @@ -27,7 +27,8 @@ import com.google.common.collect.ImmutableList; import java.util.Objects; import java.util.stream.Collectors; -import lombok.Data; +import lombok.Getter; +import lombok.Setter; import javax.annotation.Nullable; @@ -36,7 +37,8 @@ import javax.annotation.Nullable; * After parsing it will get cloned to the immutable Tx. * We don't need to implement the ProtoBuffer methods as it is not persisted or sent over the wire. */ -@Data +@Getter +@Setter public class TempTx extends BaseTx { static TempTx fromRawTx(RawTx rawTx) { return new TempTx(rawTx.getTxVersion(), diff --git a/core/src/main/java/bisq/core/dao/node/parser/TempTxOutput.java b/core/src/main/java/bisq/core/dao/node/parser/TempTxOutput.java index 0109dc656f..8aa78c2b08 100644 --- a/core/src/main/java/bisq/core/dao/node/parser/TempTxOutput.java +++ b/core/src/main/java/bisq/core/dao/node/parser/TempTxOutput.java @@ -24,7 +24,8 @@ import bisq.core.dao.state.model.blockchain.TxOutputType; import java.util.Objects; -import lombok.Data; +import lombok.Getter; +import lombok.Setter; import javax.annotation.Nullable; @@ -32,7 +33,8 @@ import javax.annotation.Nullable; * Contains mutable BSQ specific data (TxOutputType) and used only during tx parsing. * Will get converted to immutable TxOutput after tx parsing is completed. */ -@Data +@Getter +@Setter public class TempTxOutput extends BaseTxOutput { static TempTxOutput fromRawTxOutput(RawTxOutput txOutput) { return new TempTxOutput(txOutput.getIndex(), @@ -78,6 +80,10 @@ public class TempTxOutput extends BaseTxOutput { this.unlockBlockHeight = unlockBlockHeight; } + public boolean isOpReturnOutput() { + // We do not check for pubKeyScript.scriptType.NULL_DATA because that is only set if dumpBlockchainData is true + return getOpReturnData() != null; + } @Override public String toString() { @@ -88,12 +94,6 @@ public class TempTxOutput extends BaseTxOutput { "\n} " + super.toString(); } - public boolean isOpReturnOutput() { - // We do not check for pubKeyScript.scriptType.NULL_DATA because that is only set if dumpBlockchainData is true - return getOpReturnData() != null; - } - - // Enums must not be used directly for hashCode or equals as it delivers the Object.hashCode (internal address)! // The equals and hashCode methods cannot be overwritten in Enums. @Override diff --git a/core/src/main/java/bisq/core/dao/node/parser/TxOutputParser.java b/core/src/main/java/bisq/core/dao/node/parser/TxOutputParser.java index cf6815d528..7f311d6406 100644 --- a/core/src/main/java/bisq/core/dao/node/parser/TxOutputParser.java +++ b/core/src/main/java/bisq/core/dao/node/parser/TxOutputParser.java @@ -87,9 +87,9 @@ import static com.google.common.base.Preconditions.checkNotNull; */ @Slf4j class TxOutputParser { - private static int ACTIVATE_HARD_FORK_1_HEIGHT_MAINNET = 605000; - private static int ACTIVATE_HARD_FORK_1_HEIGHT_TESTNET = 1583054; - private static int ACTIVATE_HARD_FORK_1_HEIGHT_REGTEST = 1; + private static final int ACTIVATE_HARD_FORK_1_HEIGHT_MAINNET = 605000; + private static final int ACTIVATE_HARD_FORK_1_HEIGHT_TESTNET = 1583054; + private static final int ACTIVATE_HARD_FORK_1_HEIGHT_REGTEST = 1; private final DaoStateService daoStateService; // Setters diff --git a/core/src/main/java/bisq/core/dao/node/parser/exceptions/BlockHashNotConnectingException.java b/core/src/main/java/bisq/core/dao/node/parser/exceptions/BlockHashNotConnectingException.java index 41635a5a17..c97ee28e11 100644 --- a/core/src/main/java/bisq/core/dao/node/parser/exceptions/BlockHashNotConnectingException.java +++ b/core/src/main/java/bisq/core/dao/node/parser/exceptions/BlockHashNotConnectingException.java @@ -24,7 +24,7 @@ import lombok.Getter; @Getter public class BlockHashNotConnectingException extends Exception { - private RawBlock rawBlock; + private final RawBlock rawBlock; public BlockHashNotConnectingException(RawBlock rawBlock) { this.rawBlock = rawBlock; diff --git a/core/src/main/java/bisq/core/dao/node/parser/exceptions/BlockHeightNotConnectingException.java b/core/src/main/java/bisq/core/dao/node/parser/exceptions/BlockHeightNotConnectingException.java index 875c5b256b..09b39be647 100644 --- a/core/src/main/java/bisq/core/dao/node/parser/exceptions/BlockHeightNotConnectingException.java +++ b/core/src/main/java/bisq/core/dao/node/parser/exceptions/BlockHeightNotConnectingException.java @@ -24,7 +24,7 @@ import lombok.Getter; @Getter public class BlockHeightNotConnectingException extends Exception { - private RawBlock rawBlock; + private final RawBlock rawBlock; public BlockHeightNotConnectingException(RawBlock rawBlock) { this.rawBlock = rawBlock; diff --git a/core/src/main/java/bisq/core/dao/node/parser/exceptions/RequiredReorgFromSnapshotException.java b/core/src/main/java/bisq/core/dao/node/parser/exceptions/RequiredReorgFromSnapshotException.java index 59a36c6693..184676078c 100644 --- a/core/src/main/java/bisq/core/dao/node/parser/exceptions/RequiredReorgFromSnapshotException.java +++ b/core/src/main/java/bisq/core/dao/node/parser/exceptions/RequiredReorgFromSnapshotException.java @@ -24,7 +24,7 @@ import lombok.Getter; @Getter public class RequiredReorgFromSnapshotException extends Exception { - private RawBlock rawBlock; + private final RawBlock rawBlock; public RequiredReorgFromSnapshotException(RawBlock rawBlock) { this.rawBlock = rawBlock; diff --git a/core/src/main/java/bisq/core/dao/state/DaoStateService.java b/core/src/main/java/bisq/core/dao/state/DaoStateService.java index 620415a12c..219f286285 100644 --- a/core/src/main/java/bisq/core/dao/state/DaoStateService.java +++ b/core/src/main/java/bisq/core/dao/state/DaoStateService.java @@ -597,23 +597,18 @@ public class DaoStateService implements DaoSetupService { daoState.getIssuanceMap().put(issuance.getTxId(), issuance); } - public Set getIssuanceSet(IssuanceType issuanceType) { + public Set getIssuanceSetForType(IssuanceType issuanceType) { return daoState.getIssuanceMap().values().stream() .filter(issuance -> issuance.getIssuanceType() == issuanceType) .collect(Collectors.toSet()); } public Optional getIssuance(String txId, IssuanceType issuanceType) { - return daoState.getIssuanceMap().values().stream() - .filter(issuance -> issuance.getTxId().equals(txId)) - .filter(issuance -> issuance.getIssuanceType() == issuanceType) - .findAny(); + return getIssuance(txId).filter(issuance -> issuance.getIssuanceType() == issuanceType); } public Optional getIssuance(String txId) { - return daoState.getIssuanceMap().values().stream() - .filter(issuance -> issuance.getTxId().equals(txId)) - .findAny(); + return Optional.ofNullable(daoState.getIssuanceMap().get(txId)); } public boolean isIssuanceTx(String txId) { diff --git a/core/src/main/java/bisq/core/dao/state/model/DaoState.java b/core/src/main/java/bisq/core/dao/state/model/DaoState.java index c18338b033..bb65f7b30d 100644 --- a/core/src/main/java/bisq/core/dao/state/model/DaoState.java +++ b/core/src/main/java/bisq/core/dao/state/model/DaoState.java @@ -81,6 +81,8 @@ public class DaoState implements PersistablePayload { private final LinkedList cycles; // These maps represent mutual data which can get changed at parsing a transaction + // We use TreeMaps instead of HashMaps because we need deterministic sorting of the maps for the hashChains + // used for the DAO monitor. @Getter private final TreeMap unspentTxOutputMap; @Getter diff --git a/core/src/main/java/bisq/core/dao/state/model/blockchain/Tx.java b/core/src/main/java/bisq/core/dao/state/model/blockchain/Tx.java index 48c1d4979e..a90db56048 100644 --- a/core/src/main/java/bisq/core/dao/state/model/blockchain/Tx.java +++ b/core/src/main/java/bisq/core/dao/state/model/blockchain/Tx.java @@ -29,7 +29,7 @@ import java.util.Objects; import java.util.Optional; import java.util.stream.Collectors; -import lombok.Value; +import lombok.Getter; import javax.annotation.Nullable; import javax.annotation.concurrent.Immutable; @@ -39,7 +39,7 @@ import javax.annotation.concurrent.Immutable; * Gets persisted. */ @Immutable -@Value +@Getter public final class Tx extends BaseTx implements PersistablePayload, ImmutableDaoStateModel { // Created after parsing of a tx is completed. We store only the immutable tx in the block. public static Tx fromTempTx(TempTx tempTx) { diff --git a/core/src/main/java/bisq/core/dao/state/model/blockchain/TxOutput.java b/core/src/main/java/bisq/core/dao/state/model/blockchain/TxOutput.java index 4cdc953661..566216314e 100644 --- a/core/src/main/java/bisq/core/dao/state/model/blockchain/TxOutput.java +++ b/core/src/main/java/bisq/core/dao/state/model/blockchain/TxOutput.java @@ -24,7 +24,7 @@ import bisq.common.proto.persistable.PersistablePayload; import java.util.Objects; -import lombok.Data; +import lombok.Getter; import javax.annotation.Nullable; import javax.annotation.concurrent.Immutable; @@ -36,7 +36,7 @@ import javax.annotation.concurrent.Immutable; * Gets persisted. */ @Immutable -@Data +@Getter public class TxOutput extends BaseTxOutput implements PersistablePayload, ImmutableDaoStateModel { public static TxOutput fromTempOutput(TempTxOutput tempTxOutput) { return new TxOutput(tempTxOutput.getIndex(), diff --git a/core/src/main/java/bisq/core/dao/state/model/governance/ChangeParamProposal.java b/core/src/main/java/bisq/core/dao/state/model/governance/ChangeParamProposal.java index 243ec18f71..d39fc72604 100644 --- a/core/src/main/java/bisq/core/dao/state/model/governance/ChangeParamProposal.java +++ b/core/src/main/java/bisq/core/dao/state/model/governance/ChangeParamProposal.java @@ -29,14 +29,14 @@ import java.util.Date; import java.util.Map; import java.util.Objects; -import lombok.Value; +import lombok.Getter; import lombok.extern.slf4j.Slf4j; import javax.annotation.concurrent.Immutable; @Immutable @Slf4j -@Value +@Getter public final class ChangeParamProposal extends Proposal implements ImmutableDaoStateModel { private final Param param; private final String paramValue; diff --git a/core/src/main/java/bisq/core/filter/Filter.java b/core/src/main/java/bisq/core/filter/Filter.java index a642c9511c..b433de9476 100644 --- a/core/src/main/java/bisq/core/filter/Filter.java +++ b/core/src/main/java/bisq/core/filter/Filter.java @@ -35,6 +35,7 @@ import java.security.PublicKey; import java.util.List; import java.util.Map; import java.util.Optional; +import java.util.Set; import java.util.concurrent.TimeUnit; import java.util.stream.Collectors; @@ -47,7 +48,7 @@ import javax.annotation.Nullable; @Value public final class Filter implements ProtectedStoragePayload, ExpirablePayload { private final List bannedOfferIds; - private final List bannedNodeAddress; + private final List nodeAddressesBannedFromTrading; private final List bannedAutoConfExplorers; private final List bannedPaymentAccounts; private final List bannedCurrencies; @@ -91,10 +92,14 @@ public final class Filter implements ProtectedStoragePayload, ExpirablePayload { // added at v1.3.8 private final boolean disableAutoConf; + // added at v1.5.5 + private final Set nodeAddressesBannedFromNetwork; + private final boolean disableApi; + // After we have created the signature from the filter data we clone it and apply the signature static Filter cloneWithSig(Filter filter, String signatureAsBase64) { return new Filter(filter.getBannedOfferIds(), - filter.getBannedNodeAddress(), + filter.getNodeAddressesBannedFromTrading(), filter.getBannedPaymentAccounts(), filter.getBannedCurrencies(), filter.getBannedPaymentMethods(), @@ -117,13 +122,15 @@ public final class Filter implements ProtectedStoragePayload, ExpirablePayload { filter.getSignerPubKeyAsHex(), filter.getBannedPrivilegedDevPubKeys(), filter.isDisableAutoConf(), - filter.getBannedAutoConfExplorers()); + filter.getBannedAutoConfExplorers(), + filter.getNodeAddressesBannedFromNetwork(), + filter.isDisableApi()); } // Used for signature verification as we created the sig without the signatureAsBase64 field we set it to null again static Filter cloneWithoutSig(Filter filter) { return new Filter(filter.getBannedOfferIds(), - filter.getBannedNodeAddress(), + filter.getNodeAddressesBannedFromTrading(), filter.getBannedPaymentAccounts(), filter.getBannedCurrencies(), filter.getBannedPaymentMethods(), @@ -146,11 +153,13 @@ public final class Filter implements ProtectedStoragePayload, ExpirablePayload { filter.getSignerPubKeyAsHex(), filter.getBannedPrivilegedDevPubKeys(), filter.isDisableAutoConf(), - filter.getBannedAutoConfExplorers()); + filter.getBannedAutoConfExplorers(), + filter.getNodeAddressesBannedFromNetwork(), + filter.isDisableApi()); } public Filter(List bannedOfferIds, - List bannedNodeAddress, + List nodeAddressesBannedFromTrading, List bannedPaymentAccounts, List bannedCurrencies, List bannedPaymentMethods, @@ -170,9 +179,11 @@ public final class Filter implements ProtectedStoragePayload, ExpirablePayload { String signerPubKeyAsHex, List bannedPrivilegedDevPubKeys, boolean disableAutoConf, - List bannedAutoConfExplorers) { + List bannedAutoConfExplorers, + Set nodeAddressesBannedFromNetwork, + boolean disableApi) { this(bannedOfferIds, - bannedNodeAddress, + nodeAddressesBannedFromTrading, bannedPaymentAccounts, bannedCurrencies, bannedPaymentMethods, @@ -195,7 +206,9 @@ public final class Filter implements ProtectedStoragePayload, ExpirablePayload { signerPubKeyAsHex, bannedPrivilegedDevPubKeys, disableAutoConf, - bannedAutoConfExplorers); + bannedAutoConfExplorers, + nodeAddressesBannedFromNetwork, + disableApi); } @@ -205,7 +218,7 @@ public final class Filter implements ProtectedStoragePayload, ExpirablePayload { @VisibleForTesting public Filter(List bannedOfferIds, - List bannedNodeAddress, + List nodeAddressesBannedFromTrading, List bannedPaymentAccounts, List bannedCurrencies, List bannedPaymentMethods, @@ -228,9 +241,11 @@ public final class Filter implements ProtectedStoragePayload, ExpirablePayload { String signerPubKeyAsHex, List bannedPrivilegedDevPubKeys, boolean disableAutoConf, - List bannedAutoConfExplorers) { + List bannedAutoConfExplorers, + Set nodeAddressesBannedFromNetwork, + boolean disableApi) { this.bannedOfferIds = bannedOfferIds; - this.bannedNodeAddress = bannedNodeAddress; + this.nodeAddressesBannedFromTrading = nodeAddressesBannedFromTrading; this.bannedPaymentAccounts = bannedPaymentAccounts; this.bannedCurrencies = bannedCurrencies; this.bannedPaymentMethods = bannedPaymentMethods; @@ -254,6 +269,8 @@ public final class Filter implements ProtectedStoragePayload, ExpirablePayload { this.bannedPrivilegedDevPubKeys = bannedPrivilegedDevPubKeys; this.disableAutoConf = disableAutoConf; this.bannedAutoConfExplorers = bannedAutoConfExplorers; + this.nodeAddressesBannedFromNetwork = nodeAddressesBannedFromNetwork; + this.disableApi = disableApi; // ownerPubKeyBytes can be null when called from tests if (ownerPubKeyBytes != null) { @@ -270,7 +287,7 @@ public final class Filter implements ProtectedStoragePayload, ExpirablePayload { .collect(Collectors.toList()); protobuf.Filter.Builder builder = protobuf.Filter.newBuilder().addAllBannedOfferIds(bannedOfferIds) - .addAllBannedNodeAddress(bannedNodeAddress) + .addAllNodeAddressesBannedFromTrading(nodeAddressesBannedFromTrading) .addAllBannedPaymentAccounts(paymentAccountFilterList) .addAllBannedCurrencies(bannedCurrencies) .addAllBannedPaymentMethods(bannedPaymentMethods) @@ -291,7 +308,9 @@ public final class Filter implements ProtectedStoragePayload, ExpirablePayload { .setCreationDate(creationDate) .addAllBannedPrivilegedDevPubKeys(bannedPrivilegedDevPubKeys) .setDisableAutoConf(disableAutoConf) - .addAllBannedAutoConfExplorers(bannedAutoConfExplorers); + .addAllBannedAutoConfExplorers(bannedAutoConfExplorers) + .addAllNodeAddressesBannedFromNetwork(nodeAddressesBannedFromNetwork) + .setDisableApi(disableApi); Optional.ofNullable(signatureAsBase64).ifPresent(builder::setSignatureAsBase64); Optional.ofNullable(extraDataMap).ifPresent(builder::putAllExtraData); @@ -306,7 +325,7 @@ public final class Filter implements ProtectedStoragePayload, ExpirablePayload { return new Filter(ProtoUtil.protocolStringListToList(proto.getBannedOfferIdsList()), - ProtoUtil.protocolStringListToList(proto.getBannedNodeAddressList()), + ProtoUtil.protocolStringListToList(proto.getNodeAddressesBannedFromTradingList()), bannedPaymentAccountsList, ProtoUtil.protocolStringListToList(proto.getBannedCurrenciesList()), ProtoUtil.protocolStringListToList(proto.getBannedPaymentMethodsList()), @@ -329,7 +348,9 @@ public final class Filter implements ProtectedStoragePayload, ExpirablePayload { proto.getSignerPubKeyAsHex(), ProtoUtil.protocolStringListToList(proto.getBannedPrivilegedDevPubKeysList()), proto.getDisableAutoConf(), - ProtoUtil.protocolStringListToList(proto.getBannedAutoConfExplorersList()) + ProtoUtil.protocolStringListToList(proto.getBannedAutoConfExplorersList()), + ProtoUtil.protocolStringListToSet(proto.getNodeAddressesBannedFromNetworkList()), + proto.getDisableApi() ); } @@ -347,7 +368,7 @@ public final class Filter implements ProtectedStoragePayload, ExpirablePayload { public String toString() { return "Filter{" + "\n bannedOfferIds=" + bannedOfferIds + - ",\n bannedNodeAddress=" + bannedNodeAddress + + ",\n nodeAddressesBannedFromTrading=" + nodeAddressesBannedFromTrading + ",\n bannedAutoConfExplorers=" + bannedAutoConfExplorers + ",\n bannedPaymentAccounts=" + bannedPaymentAccounts + ",\n bannedCurrencies=" + bannedCurrencies + @@ -372,6 +393,8 @@ public final class Filter implements ProtectedStoragePayload, ExpirablePayload { ",\n extraDataMap=" + extraDataMap + ",\n ownerPubKey=" + ownerPubKey + ",\n disableAutoConf=" + disableAutoConf + + ",\n nodeAddressesBannedFromNetwork=" + nodeAddressesBannedFromNetwork + + ",\n disableApi=" + disableApi + "\n}"; } } diff --git a/core/src/main/java/bisq/core/filter/FilterManager.java b/core/src/main/java/bisq/core/filter/FilterManager.java index 19cfded31f..0dd35518c2 100644 --- a/core/src/main/java/bisq/core/filter/FilterManager.java +++ b/core/src/main/java/bisq/core/filter/FilterManager.java @@ -28,6 +28,7 @@ import bisq.core.user.User; import bisq.network.p2p.NodeAddress; import bisq.network.p2p.P2PService; import bisq.network.p2p.P2PServiceListener; +import bisq.network.p2p.network.NetworkFilter; import bisq.network.p2p.storage.HashMapChangedListener; import bisq.network.p2p.storage.payload.ProtectedStorageEntry; @@ -115,6 +116,7 @@ public class FilterManager { Preferences preferences, Config config, ProvidersRepository providersRepository, + NetworkFilter networkFilter, @Named(Config.IGNORE_DEV_MSG) boolean ignoreDevMsg, @Named(Config.USE_DEV_PRIVILEGE_KEYS) boolean useDevPrivilegeKeys) { this.p2PService = p2PService; @@ -131,6 +133,7 @@ public class FilterManager { "029340c3e7d4bb0f9e651b5f590b434fecb6175aeaa57145c7804ff05d210e534f", "034dc7530bf66ffd9580aa98031ea9a18ac2d269f7c56c0e71eca06105b9ed69f9"); + networkFilter.setBannedNodeFunction(this::isNodeAddressBannedFromNetwork); } @@ -394,7 +397,13 @@ public class FilterManager { public boolean isNodeAddressBanned(NodeAddress nodeAddress) { return getFilter() != null && - getFilter().getBannedNodeAddress().stream() + getFilter().getNodeAddressesBannedFromTrading().stream() + .anyMatch(e -> e.equals(nodeAddress.getFullAddress())); + } + + public boolean isNodeAddressBannedFromNetwork(NodeAddress nodeAddress) { + return getFilter() != null && + getFilter().getNodeAddressesBannedFromNetwork().stream() .anyMatch(e -> e.equals(nodeAddress.getFullAddress())); } @@ -466,7 +475,11 @@ public class FilterManager { Filter currentFilter = getFilter(); if (!isFilterPublicKeyInList(newFilter)) { - log.warn("isFilterPublicKeyInList failed. Filter.getSignerPubKeyAsHex={}", newFilter.getSignerPubKeyAsHex()); + if (newFilter.getSignerPubKeyAsHex() != null && !newFilter.getSignerPubKeyAsHex().isEmpty()) { + log.warn("isFilterPublicKeyInList failed. Filter.getSignerPubKeyAsHex={}", newFilter.getSignerPubKeyAsHex()); + } else { + log.info("isFilterPublicKeyInList failed. Filter.getSignerPubKeyAsHex not set (expected case for pre v1.3.9 filter)"); + } return; } if (!isSignatureValid(newFilter)) { @@ -593,7 +606,7 @@ public class FilterManager { private boolean isFilterPublicKeyInList(Filter filter) { String signerPubKeyAsHex = filter.getSignerPubKeyAsHex(); if (!isPublicKeyInList(signerPubKeyAsHex)) { - log.warn("Invalid filter (expected case for pre v1.3.9 filter as we still keep that in the network " + + log.info("Invalid filter (expected case for pre v1.3.9 filter as we still keep that in the network " + "but the new version does not recognize it as valid filter): " + "signerPubKeyAsHex from filter is not part of our pub key list. " + "signerPubKeyAsHex={}, publicKeys={}, filterCreationDate={}", @@ -606,7 +619,7 @@ public class FilterManager { private boolean isPublicKeyInList(String pubKeyAsHex) { boolean isPublicKeyInList = publicKeys.contains(pubKeyAsHex); if (!isPublicKeyInList) { - log.warn("pubKeyAsHex is not part of our pub key list. pubKeyAsHex={}, publicKeys={}", pubKeyAsHex, publicKeys); + log.info("pubKeyAsHex is not part of our pub key list (expected case for pre v1.3.9 filter). pubKeyAsHex={}, publicKeys={}", pubKeyAsHex, publicKeys); } return isPublicKeyInList; } diff --git a/core/src/main/java/bisq/core/locale/CurrencyUtil.java b/core/src/main/java/bisq/core/locale/CurrencyUtil.java index c23eb21318..e94127cef1 100644 --- a/core/src/main/java/bisq/core/locale/CurrencyUtil.java +++ b/core/src/main/java/bisq/core/locale/CurrencyUtil.java @@ -301,7 +301,6 @@ public class CurrencyUtil { new FiatCurrency("MAD"), new FiatCurrency("NPR"), new FiatCurrency("NZD"), - new FiatCurrency("NGN"), new FiatCurrency("NOK"), new FiatCurrency("PKR"), new FiatCurrency("PEN"), diff --git a/core/src/main/java/bisq/core/network/CoreNetworkFilter.java b/core/src/main/java/bisq/core/network/CoreNetworkFilter.java new file mode 100644 index 0000000000..b261d42153 --- /dev/null +++ b/core/src/main/java/bisq/core/network/CoreNetworkFilter.java @@ -0,0 +1,58 @@ +/* + * This file is part of Bisq. + * + * Bisq is free software: you can redistribute it and/or modify it + * under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or (at + * your option) any later version. + * + * Bisq is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public + * License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with Bisq. If not, see . + */ + +package bisq.core.network; + +import bisq.network.p2p.NodeAddress; +import bisq.network.p2p.network.NetworkFilter; + +import bisq.common.config.Config; + +import javax.inject.Inject; +import javax.inject.Named; + +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import java.util.function.Function; + +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class CoreNetworkFilter implements NetworkFilter { + private final Set bannedPeersFromOptions = new HashSet<>(); + private Function bannedNodeFunction; + + /** + * @param banList List of banned peers from program argument + */ + @Inject + public CoreNetworkFilter(@Named(Config.BAN_LIST) List banList) { + banList.stream().map(NodeAddress::new).forEach(bannedPeersFromOptions::add); + } + + @Override + public void setBannedNodeFunction(Function bannedNodeFunction) { + this.bannedNodeFunction = bannedNodeFunction; + } + + @Override + public boolean isPeerBanned(NodeAddress nodeAddress) { + return bannedPeersFromOptions.contains(nodeAddress) || + bannedNodeFunction != null && bannedNodeFunction.apply(nodeAddress); + } +} diff --git a/core/src/main/java/bisq/core/network/p2p/inventory/messages/GetInventoryRequest.java b/core/src/main/java/bisq/core/network/p2p/inventory/messages/GetInventoryRequest.java index fee7f82704..7b46d04fec 100644 --- a/core/src/main/java/bisq/core/network/p2p/inventory/messages/GetInventoryRequest.java +++ b/core/src/main/java/bisq/core/network/p2p/inventory/messages/GetInventoryRequest.java @@ -21,9 +21,13 @@ package bisq.core.network.p2p.inventory.messages; import bisq.common.app.Version; import bisq.common.proto.network.NetworkEnvelope; -import lombok.Value; +import lombok.EqualsAndHashCode; +import lombok.Getter; +import lombok.ToString; -@Value +@Getter +@EqualsAndHashCode(callSuper = false) +@ToString public class GetInventoryRequest extends NetworkEnvelope { private final String version; diff --git a/core/src/main/java/bisq/core/network/p2p/inventory/messages/GetInventoryResponse.java b/core/src/main/java/bisq/core/network/p2p/inventory/messages/GetInventoryResponse.java index b9c5cf9ce3..2dd79bfc1d 100644 --- a/core/src/main/java/bisq/core/network/p2p/inventory/messages/GetInventoryResponse.java +++ b/core/src/main/java/bisq/core/network/p2p/inventory/messages/GetInventoryResponse.java @@ -28,9 +28,13 @@ import com.google.common.base.Optional; import java.util.HashMap; import java.util.Map; -import lombok.Value; +import lombok.EqualsAndHashCode; +import lombok.Getter; +import lombok.ToString; -@Value +@Getter +@EqualsAndHashCode(callSuper = false) +@ToString public class GetInventoryResponse extends NetworkEnvelope { private final Map inventory; diff --git a/core/src/main/java/bisq/core/network/p2p/inventory/model/InventoryItem.java b/core/src/main/java/bisq/core/network/p2p/inventory/model/InventoryItem.java index bcdd0d2b4f..4f91a2023b 100644 --- a/core/src/main/java/bisq/core/network/p2p/inventory/model/InventoryItem.java +++ b/core/src/main/java/bisq/core/network/p2p/inventory/model/InventoryItem.java @@ -32,7 +32,7 @@ public enum InventoryItem { // Percentage deviation OfferPayload("OfferPayload", true, - new DeviationByPercentage(0.8, 1.2, 0.9, 1.1), 5), + new DeviationByPercentage(0.5, 1.5, 0.75, 1.25), 10), MailboxStoragePayload("MailboxStoragePayload", true, new DeviationByPercentage(0.9, 1.1, 0.95, 1.05), 2), diff --git a/core/src/main/java/bisq/core/network/p2p/inventory/model/RequestInfo.java b/core/src/main/java/bisq/core/network/p2p/inventory/model/RequestInfo.java index 5bccb8998f..b86e9e5e45 100644 --- a/core/src/main/java/bisq/core/network/p2p/inventory/model/RequestInfo.java +++ b/core/src/main/java/bisq/core/network/p2p/inventory/model/RequestInfo.java @@ -29,7 +29,7 @@ import org.jetbrains.annotations.Nullable; @Getter public class RequestInfo { // Carries latest commit hash of feature changes (not latest commit as that is then the commit for editing that field) - public static final String COMMIT_HASH = "7f83d1b3"; + public static final String COMMIT_HASH = "1c50cb6c"; private final long requestStartTime; @Setter diff --git a/core/src/main/java/bisq/core/notifications/alerts/MyOfferTakenEvents.java b/core/src/main/java/bisq/core/notifications/alerts/MyOfferTakenEvents.java index 842dbadacc..4b208250dd 100644 --- a/core/src/main/java/bisq/core/notifications/alerts/MyOfferTakenEvents.java +++ b/core/src/main/java/bisq/core/notifications/alerts/MyOfferTakenEvents.java @@ -55,8 +55,9 @@ public class MyOfferTakenEvents { } private void onOpenOfferRemoved(OpenOffer openOffer) { - log.info("We got a offer removed. id={}, state={}", openOffer.getId(), openOffer.getState()); - if (openOffer.getState() == OpenOffer.State.RESERVED) { + OpenOffer.State state = openOffer.getState(); + if (state == OpenOffer.State.RESERVED) { + log.info("We got a offer removed. id={}, state={}", openOffer.getId(), state); String shortId = openOffer.getShortId(); MobileMessage message = new MobileMessage(Res.get("account.notifications.offer.message.title"), Res.get("account.notifications.offer.message.msg", shortId), diff --git a/core/src/main/java/bisq/core/offer/AvailabilityResult.java b/core/src/main/java/bisq/core/offer/AvailabilityResult.java index 2d3d749ff2..18e877c830 100644 --- a/core/src/main/java/bisq/core/offer/AvailabilityResult.java +++ b/core/src/main/java/bisq/core/offer/AvailabilityResult.java @@ -27,5 +27,7 @@ public enum AvailabilityResult { NO_MEDIATORS, USER_IGNORED, MISSING_MANDATORY_CAPABILITY, - NO_REFUND_AGENTS + NO_REFUND_AGENTS, + UNCONF_TX_LIMIT_HIT, + MAKER_DENIED_API_USER } diff --git a/core/src/main/java/bisq/core/offer/CreateOfferService.java b/core/src/main/java/bisq/core/offer/CreateOfferService.java index 51a3847eb9..089169bdbe 100644 --- a/core/src/main/java/bisq/core/offer/CreateOfferService.java +++ b/core/src/main/java/bisq/core/offer/CreateOfferService.java @@ -110,7 +110,7 @@ public class CreateOfferService { double buyerSecurityDepositAsDouble, PaymentAccount paymentAccount) { - log.info("offerId={}, \n" + + log.info("create and get offer with offerId={}, \n" + "currencyCode={}, \n" + "direction={}, \n" + "price={}, \n" + @@ -118,14 +118,21 @@ public class CreateOfferService { "marketPriceMargin={}, \n" + "amount={}, \n" + "minAmount={}, \n" + - "buyerSecurityDeposit={}, \n" + - offerId, currencyCode, direction, price.getValue(), useMarketBasedPrice, marketPriceMargin, - amount.value, minAmount.value, buyerSecurityDepositAsDouble); + "buyerSecurityDeposit={}", + offerId, + currencyCode, + direction, + price.getValue(), + useMarketBasedPrice, + marketPriceMargin, + amount.value, + minAmount.value, + buyerSecurityDepositAsDouble); - // prints our param list for dev testing api - log.info("{} " + - "{} " + - "{} " + + // Log an approximate api CLI 'createoffer' dev/test param list. + log.info("cli's createoffer positional option names: paymentAccountId direction currencyCode amount minAmount" + + " useMarketBasedPrice fixedPrice|marketPriceMargin buyerSecurityDeposit"); + log.info("cli's createoffer positional option values: {} " + "{} " + "{} " + "{} " + @@ -133,8 +140,14 @@ public class CreateOfferService { "{} " + "{} " + "{}", - offerId, currencyCode, direction.name(), price.getValue(), useMarketBasedPrice, marketPriceMargin, - amount.value, minAmount.value, buyerSecurityDepositAsDouble, paymentAccount.getId()); + paymentAccount.getId(), + direction.name(), + currencyCode, + amount.value, + minAmount.value, + useMarketBasedPrice, + (useMarketBasedPrice ? marketPriceMargin : price.getValue()), + buyerSecurityDepositAsDouble); long creationTime = new Date().getTime(); NodeAddress makerAddress = p2PService.getAddress(); diff --git a/core/src/main/java/bisq/core/offer/OfferFilter.java b/core/src/main/java/bisq/core/offer/OfferFilter.java new file mode 100644 index 0000000000..c22231de5b --- /dev/null +++ b/core/src/main/java/bisq/core/offer/OfferFilter.java @@ -0,0 +1,209 @@ +/* + * This file is part of Bisq. + * + * Bisq is free software: you can redistribute it and/or modify it + * under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or (at + * your option) any later version. + * + * Bisq is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public + * License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with Bisq. If not, see . + */ + +package bisq.core.offer; + +import bisq.core.account.witness.AccountAgeWitnessService; +import bisq.core.filter.FilterManager; +import bisq.core.locale.CurrencyUtil; +import bisq.core.payment.PaymentAccount; +import bisq.core.payment.PaymentAccountUtil; +import bisq.core.user.Preferences; +import bisq.core.user.User; + +import bisq.common.app.Version; + +import org.bitcoinj.core.Coin; + +import javax.inject.Inject; +import javax.inject.Singleton; + +import javafx.collections.SetChangeListener; + +import java.util.HashMap; +import java.util.Map; +import java.util.Optional; + +import lombok.Getter; +import lombok.extern.slf4j.Slf4j; + +@Slf4j +@Singleton +public class OfferFilter { + private final User user; + private final Preferences preferences; + private final FilterManager filterManager; + private final AccountAgeWitnessService accountAgeWitnessService; + private final Map insufficientCounterpartyTradeLimitCache = new HashMap<>(); + private final Map myInsufficientTradeLimitCache = new HashMap<>(); + + @Inject + public OfferFilter(User user, + Preferences preferences, + FilterManager filterManager, + AccountAgeWitnessService accountAgeWitnessService) { + this.user = user; + this.preferences = preferences; + this.filterManager = filterManager; + this.accountAgeWitnessService = accountAgeWitnessService; + + if (user != null) { + // If our accounts have changed we reset our myInsufficientTradeLimitCache as it depends on account data + user.getPaymentAccountsAsObservable().addListener((SetChangeListener) c -> + myInsufficientTradeLimitCache.clear()); + } + } + + public enum Result { + VALID(true), + API_DISABLED, + HAS_NO_PAYMENT_ACCOUNT_VALID_FOR_OFFER, + HAS_NOT_SAME_PROTOCOL_VERSION, + IS_IGNORED, + IS_OFFER_BANNED, + IS_CURRENCY_BANNED, + IS_PAYMENT_METHOD_BANNED, + IS_NODE_ADDRESS_BANNED, + REQUIRE_UPDATE_TO_NEW_VERSION, + IS_INSUFFICIENT_COUNTERPARTY_TRADE_LIMIT, + IS_MY_INSUFFICIENT_TRADE_LIMIT; + + @Getter + private final boolean isValid; + + Result(boolean isValid) { + this.isValid = isValid; + } + + Result() { + this(false); + } + } + + public Result canTakeOffer(Offer offer, boolean isTakerApiUser) { + if (isTakerApiUser && filterManager.getFilter() != null && filterManager.getFilter().isDisableApi()) { + return Result.API_DISABLED; + } + if (!isAnyPaymentAccountValidForOffer(offer)) { + return Result.HAS_NO_PAYMENT_ACCOUNT_VALID_FOR_OFFER; + } + if (!hasSameProtocolVersion(offer)) { + return Result.HAS_NOT_SAME_PROTOCOL_VERSION; + } + if (isIgnored(offer)) { + return Result.IS_IGNORED; + } + if (isOfferBanned(offer)) { + return Result.IS_OFFER_BANNED; + } + if (isCurrencyBanned(offer)) { + return Result.IS_CURRENCY_BANNED; + } + if (isPaymentMethodBanned(offer)) { + return Result.IS_PAYMENT_METHOD_BANNED; + } + if (isNodeAddressBanned(offer)) { + return Result.IS_NODE_ADDRESS_BANNED; + } + if (requireUpdateToNewVersion()) { + return Result.REQUIRE_UPDATE_TO_NEW_VERSION; + } + if (isInsufficientCounterpartyTradeLimit(offer)) { + return Result.IS_INSUFFICIENT_COUNTERPARTY_TRADE_LIMIT; + } + if (isMyInsufficientTradeLimit(offer)) { + return Result.IS_MY_INSUFFICIENT_TRADE_LIMIT; + } + + return Result.VALID; + } + + public boolean isAnyPaymentAccountValidForOffer(Offer offer) { + return user.getPaymentAccounts() != null && + PaymentAccountUtil.isAnyTakerPaymentAccountValidForOffer(offer, user.getPaymentAccounts()); + } + + public boolean hasSameProtocolVersion(Offer offer) { + return offer.getProtocolVersion() == Version.TRADE_PROTOCOL_VERSION; + } + + public boolean isIgnored(Offer offer) { + return preferences.getIgnoreTradersList().stream() + .anyMatch(i -> i.equals(offer.getMakerNodeAddress().getFullAddress())); + } + + public boolean isOfferBanned(Offer offer) { + return filterManager.isOfferIdBanned(offer.getId()); + } + + public boolean isCurrencyBanned(Offer offer) { + return filterManager.isCurrencyBanned(offer.getCurrencyCode()); + } + + public boolean isPaymentMethodBanned(Offer offer) { + return filterManager.isPaymentMethodBanned(offer.getPaymentMethod()); + } + + public boolean isNodeAddressBanned(Offer offer) { + return filterManager.isNodeAddressBanned(offer.getMakerNodeAddress()); + } + + public boolean requireUpdateToNewVersion() { + return filterManager.requireUpdateToNewVersionForTrading(); + } + + // This call is a bit expensive so we cache results + public boolean isInsufficientCounterpartyTradeLimit(Offer offer) { + String offerId = offer.getId(); + if (insufficientCounterpartyTradeLimitCache.containsKey(offerId)) { + return insufficientCounterpartyTradeLimitCache.get(offerId); + } + + boolean result = CurrencyUtil.isFiatCurrency(offer.getCurrencyCode()) && + !accountAgeWitnessService.verifyPeersTradeAmount(offer, offer.getAmount(), + errorMessage -> { + }); + insufficientCounterpartyTradeLimitCache.put(offerId, result); + return result; + } + + // This call is a bit expensive so we cache results + public boolean isMyInsufficientTradeLimit(Offer offer) { + String offerId = offer.getId(); + if (myInsufficientTradeLimitCache.containsKey(offerId)) { + return myInsufficientTradeLimitCache.get(offerId); + } + + Optional accountOptional = PaymentAccountUtil.getMostMaturePaymentAccountForOffer(offer, + user.getPaymentAccounts(), + accountAgeWitnessService); + long myTradeLimit = accountOptional + .map(paymentAccount -> accountAgeWitnessService.getMyTradeLimit(paymentAccount, + offer.getCurrencyCode(), offer.getMirroredDirection())) + .orElse(0L); + long offerMinAmount = offer.getMinAmount().value; + log.debug("isInsufficientTradeLimit accountOptional={}, myTradeLimit={}, offerMinAmount={}, ", + accountOptional.isPresent() ? accountOptional.get().getAccountName() : "null", + Coin.valueOf(myTradeLimit).toFriendlyString(), + Coin.valueOf(offerMinAmount).toFriendlyString()); + boolean result = CurrencyUtil.isFiatCurrency(offer.getCurrencyCode()) && + accountOptional.isPresent() && + myTradeLimit < offerMinAmount; + myInsufficientTradeLimitCache.put(offerId, result); + return result; + } +} diff --git a/core/src/main/java/bisq/core/offer/OpenOffer.java b/core/src/main/java/bisq/core/offer/OpenOffer.java index 5d9cfb4794..61ae2f2ad0 100644 --- a/core/src/main/java/bisq/core/offer/OpenOffer.java +++ b/core/src/main/java/bisq/core/offer/OpenOffer.java @@ -69,9 +69,18 @@ public final class OpenOffer implements Tradable { @Nullable private NodeAddress refundAgentNodeAddress; + // Added in v1.5.3. + // If market price reaches that trigger price the offer gets deactivated + @Getter + private final long triggerPrice; public OpenOffer(Offer offer) { + this(offer, 0); + } + + public OpenOffer(Offer offer, long triggerPrice) { this.offer = offer; + this.triggerPrice = triggerPrice; state = State.AVAILABLE; } @@ -83,12 +92,14 @@ public final class OpenOffer implements Tradable { State state, @Nullable NodeAddress arbitratorNodeAddress, @Nullable NodeAddress mediatorNodeAddress, - @Nullable NodeAddress refundAgentNodeAddress) { + @Nullable NodeAddress refundAgentNodeAddress, + long triggerPrice) { this.offer = offer; this.state = state; this.arbitratorNodeAddress = arbitratorNodeAddress; this.mediatorNodeAddress = mediatorNodeAddress; this.refundAgentNodeAddress = refundAgentNodeAddress; + this.triggerPrice = triggerPrice; if (this.state == State.RESERVED) setState(State.AVAILABLE); @@ -98,6 +109,7 @@ public final class OpenOffer implements Tradable { public protobuf.Tradable toProtoMessage() { protobuf.OpenOffer.Builder builder = protobuf.OpenOffer.newBuilder() .setOffer(offer.toProtoMessage()) + .setTriggerPrice(triggerPrice) .setState(protobuf.OpenOffer.State.valueOf(state.name())); Optional.ofNullable(arbitratorNodeAddress).ifPresent(nodeAddress -> builder.setArbitratorNodeAddress(nodeAddress.toProtoMessage())); @@ -112,7 +124,8 @@ public final class OpenOffer implements Tradable { ProtoUtil.enumFromProto(OpenOffer.State.class, proto.getState().name()), proto.hasArbitratorNodeAddress() ? NodeAddress.fromProto(proto.getArbitratorNodeAddress()) : null, proto.hasMediatorNodeAddress() ? NodeAddress.fromProto(proto.getMediatorNodeAddress()) : null, - proto.hasRefundAgentNodeAddress() ? NodeAddress.fromProto(proto.getRefundAgentNodeAddress()) : null); + proto.hasRefundAgentNodeAddress() ? NodeAddress.fromProto(proto.getRefundAgentNodeAddress()) : null, + proto.getTriggerPrice()); } @@ -178,6 +191,7 @@ public final class OpenOffer implements Tradable { ",\n arbitratorNodeAddress=" + arbitratorNodeAddress + ",\n mediatorNodeAddress=" + mediatorNodeAddress + ",\n refundAgentNodeAddress=" + refundAgentNodeAddress + + ",\n triggerPrice=" + triggerPrice + "\n}"; } } diff --git a/core/src/main/java/bisq/core/offer/OpenOfferManager.java b/core/src/main/java/bisq/core/offer/OpenOfferManager.java index 496a0ac2f2..3f07eaa1f4 100644 --- a/core/src/main/java/bisq/core/offer/OpenOfferManager.java +++ b/core/src/main/java/bisq/core/offer/OpenOfferManager.java @@ -49,6 +49,7 @@ import bisq.network.p2p.DecryptedMessageWithPubKey; import bisq.network.p2p.NodeAddress; import bisq.network.p2p.P2PService; import bisq.network.p2p.SendDirectMessageListener; +import bisq.network.p2p.peers.Broadcaster; import bisq.network.p2p.peers.PeerManager; import bisq.common.Timer; @@ -117,6 +118,7 @@ public class OpenOfferManager implements PeerManager.Listener, DecryptedDirectMe private final RefundAgentManager refundAgentManager; private final DaoFacade daoFacade; private final FilterManager filterManager; + private final Broadcaster broadcaster; private final PersistenceManager> persistenceManager; private final Map offersToBeEdited = new HashMap<>(); private final TradableList openOffers = new TradableList<>(); @@ -148,6 +150,7 @@ public class OpenOfferManager implements PeerManager.Listener, DecryptedDirectMe RefundAgentManager refundAgentManager, DaoFacade daoFacade, FilterManager filterManager, + Broadcaster broadcaster, PersistenceManager> persistenceManager) { this.createOfferService = createOfferService; this.keyRing = keyRing; @@ -166,6 +169,7 @@ public class OpenOfferManager implements PeerManager.Listener, DecryptedDirectMe this.refundAgentManager = refundAgentManager; this.daoFacade = daoFacade; this.filterManager = filterManager; + this.broadcaster = broadcaster; this.persistenceManager = persistenceManager; this.persistenceManager.initialize(openOffers, "OpenOffers", PersistenceManager.Source.PRIVATE); @@ -214,10 +218,6 @@ public class OpenOfferManager implements PeerManager.Listener, DecryptedDirectMe }); } - private void shutDown() { - shutDown(null); - } - public void shutDown(@Nullable Runnable completeHandler) { stopped = true; p2PService.getPeerManager().removeListener(this); @@ -235,6 +235,11 @@ public class OpenOfferManager implements PeerManager.Listener, DecryptedDirectMe UserThread.execute(() -> openOffers.forEach( openOffer -> offerBookService.removeOfferAtShutDown(openOffer.getOffer().getOfferPayload()) )); + + // Force broadcaster to send out immediately, otherwise we could have a 2 sec delay until the + // bundled messages sent out. + broadcaster.flush(); + if (completeHandler != null) { // For typical number of offers we are tolerant with delay to give enough time to broadcast. // If number of offers is very high we limit to 3 sec. to not delay other shutdown routines. @@ -358,6 +363,7 @@ public class OpenOfferManager implements PeerManager.Listener, DecryptedDirectMe public void placeOffer(Offer offer, double buyerSecurityDeposit, boolean useSavingsWallet, + long triggerPrice, TransactionResultHandler resultHandler, ErrorMessageHandler errorMessageHandler) { checkNotNull(offer.getMakerFee(), "makerFee must not be null"); @@ -382,7 +388,7 @@ public class OpenOfferManager implements PeerManager.Listener, DecryptedDirectMe PlaceOfferProtocol placeOfferProtocol = new PlaceOfferProtocol( model, transaction -> { - OpenOffer openOffer = new OpenOffer(offer); + OpenOffer openOffer = new OpenOffer(offer, triggerPrice); openOffers.add(openOffer); requestPersistence(); resultHandler.handleResult(transaction); @@ -486,6 +492,7 @@ public class OpenOfferManager implements PeerManager.Listener, DecryptedDirectMe } public void editOpenOfferPublish(Offer editedOffer, + long triggerPrice, OpenOffer.State originalState, ResultHandler resultHandler, ErrorMessageHandler errorMessageHandler) { @@ -498,7 +505,7 @@ public class OpenOfferManager implements PeerManager.Listener, DecryptedDirectMe openOffer.setState(OpenOffer.State.CANCELED); openOffers.remove(openOffer); - OpenOffer editedOpenOffer = new OpenOffer(editedOffer); + OpenOffer editedOpenOffer = new OpenOffer(editedOffer, triggerPrice); editedOpenOffer.setState(originalState); openOffers.add(editedOpenOffer); @@ -627,47 +634,50 @@ public class OpenOfferManager implements PeerManager.Listener, DecryptedDirectMe NodeAddress refundAgentNodeAddress = null; if (openOfferOptional.isPresent()) { OpenOffer openOffer = openOfferOptional.get(); - if (openOffer.getState() == OpenOffer.State.AVAILABLE) { - Offer offer = openOffer.getOffer(); - if (preferences.getIgnoreTradersList().stream().noneMatch(fullAddress -> fullAddress.equals(peer.getFullAddress()))) { - availabilityResult = AvailabilityResult.AVAILABLE; + if (!apiUserDeniedByOffer(request)) { + if (openOffer.getState() == OpenOffer.State.AVAILABLE) { + Offer offer = openOffer.getOffer(); + if (preferences.getIgnoreTradersList().stream().noneMatch(fullAddress -> fullAddress.equals(peer.getFullAddress()))) { + mediatorNodeAddress = DisputeAgentSelection.getLeastUsedMediator(tradeStatisticsManager, mediatorManager).getNodeAddress(); + openOffer.setMediatorNodeAddress(mediatorNodeAddress); - mediatorNodeAddress = DisputeAgentSelection.getLeastUsedMediator(tradeStatisticsManager, mediatorManager).getNodeAddress(); - openOffer.setMediatorNodeAddress(mediatorNodeAddress); + refundAgentNodeAddress = DisputeAgentSelection.getLeastUsedRefundAgent(tradeStatisticsManager, refundAgentManager).getNodeAddress(); + openOffer.setRefundAgentNodeAddress(refundAgentNodeAddress); - refundAgentNodeAddress = DisputeAgentSelection.getLeastUsedRefundAgent(tradeStatisticsManager, refundAgentManager).getNodeAddress(); - openOffer.setRefundAgentNodeAddress(refundAgentNodeAddress); - - try { - // Check also tradePrice to avoid failures after taker fee is paid caused by a too big difference - // in trade price between the peers. Also here poor connectivity might cause market price API connection - // losses and therefore an outdated market price. - offer.checkTradePriceTolerance(request.getTakersTradePrice()); - } catch (TradePriceOutOfToleranceException e) { - log.warn("Trade price check failed because takers price is outside out tolerance."); - availabilityResult = AvailabilityResult.PRICE_OUT_OF_TOLERANCE; - } catch (MarketPriceNotAvailableException e) { - log.warn(e.getMessage()); - availabilityResult = AvailabilityResult.MARKET_PRICE_NOT_AVAILABLE; - } catch (Throwable e) { - log.warn("Trade price check failed. " + e.getMessage()); - availabilityResult = AvailabilityResult.UNKNOWN_FAILURE; + try { + // Check also tradePrice to avoid failures after taker fee is paid caused by a too big difference + // in trade price between the peers. Also here poor connectivity might cause market price API connection + // losses and therefore an outdated market price. + offer.checkTradePriceTolerance(request.getTakersTradePrice()); + availabilityResult = AvailabilityResult.AVAILABLE; + } catch (TradePriceOutOfToleranceException e) { + log.warn("Trade price check failed because takers price is outside out tolerance."); + availabilityResult = AvailabilityResult.PRICE_OUT_OF_TOLERANCE; + } catch (MarketPriceNotAvailableException e) { + log.warn(e.getMessage()); + availabilityResult = AvailabilityResult.MARKET_PRICE_NOT_AVAILABLE; + } catch (Throwable e) { + log.warn("Trade price check failed. " + e.getMessage()); + availabilityResult = AvailabilityResult.UNKNOWN_FAILURE; + } + } else { + availabilityResult = AvailabilityResult.USER_IGNORED; } } else { - availabilityResult = AvailabilityResult.USER_IGNORED; + availabilityResult = AvailabilityResult.OFFER_TAKEN; } } else { - availabilityResult = AvailabilityResult.OFFER_TAKEN; + availabilityResult = AvailabilityResult.MAKER_DENIED_API_USER; } } else { - log.warn("handleOfferAvailabilityRequest: openOffer not found. That should never happen."); + log.warn("handleOfferAvailabilityRequest: openOffer not found."); availabilityResult = AvailabilityResult.OFFER_TAKEN; } if (btcWalletService.isUnconfirmedTransactionsLimitHit() || bsqWalletService.isUnconfirmedTransactionsLimitHit()) { errorMessage = Res.get("shared.unconfirmedTransactionsLimitReached"); log.warn(errorMessage); - availabilityResult = AvailabilityResult.UNKNOWN_FAILURE; + availabilityResult = AvailabilityResult.UNCONF_TX_LIMIT_HIT; } OfferAvailabilityResponse offerAvailabilityResponse = new OfferAvailabilityResponse(request.offerId, @@ -709,6 +719,10 @@ public class OpenOfferManager implements PeerManager.Listener, DecryptedDirectMe } } + private boolean apiUserDeniedByOffer(OfferAvailabilityRequest request) { + return preferences.isDenyApiTaker() && request.isTakerApiUser(); + } + private void sendAckMessage(OfferAvailabilityRequest message, NodeAddress sender, boolean result, @@ -855,7 +869,7 @@ public class OpenOfferManager implements PeerManager.Listener, DecryptedDirectMe updatedOffer.setPriceFeedService(priceFeedService); updatedOffer.setState(originalOfferState); - OpenOffer updatedOpenOffer = new OpenOffer(updatedOffer); + OpenOffer updatedOpenOffer = new OpenOffer(updatedOffer, originalOpenOffer.getTriggerPrice()); updatedOpenOffer.setState(originalOpenOfferState); openOffers.add(updatedOpenOffer); requestPersistence(); @@ -871,41 +885,53 @@ public class OpenOfferManager implements PeerManager.Listener, DecryptedDirectMe /////////////////////////////////////////////////////////////////////////////////////////// private void republishOffers() { - int size = openOffers.size(); - final ArrayList openOffersList = new ArrayList<>(openOffers.getList()); - if (!stopped) { - stopPeriodicRefreshOffersTimer(); - for (int i = 0; i < size; i++) { - // we delay to avoid reaching throttle limits + if (stopped) { + return; + } - long delay = 700; - final long minDelay = (i + 1) * delay; - final long maxDelay = (i + 2) * delay; - final OpenOffer openOffer = openOffersList.get(i); - UserThread.runAfterRandomDelay(() -> { - if (openOffers.contains(openOffer)) { - String id = openOffer.getId(); - if (id != null && !openOffer.isDeactivated()) - republishOffer(openOffer); - } + stopPeriodicRefreshOffersTimer(); - }, minDelay, maxDelay, TimeUnit.MILLISECONDS); - } + List openOffersList = new ArrayList<>(openOffers.getList()); + processListForRepublishOffers(openOffersList); + } + + private void processListForRepublishOffers(List list) { + if (list.isEmpty()) { + return; + } + + OpenOffer openOffer = list.remove(0); + if (openOffers.contains(openOffer) && !openOffer.isDeactivated()) { + // TODO It is not clear yet if it is better for the node and the network to send out all add offer + // messages in one go or to spread it over a delay. With power users who have 100-200 offers that can have + // some significant impact to user experience and the network + republishOffer(openOffer, () -> processListForRepublishOffers(list)); + + /* republishOffer(openOffer, + () -> UserThread.runAfter(() -> processListForRepublishOffers(list), + 30, TimeUnit.MILLISECONDS));*/ } else { - log.debug("We have stopped already. We ignore that republishOffers call."); + // If the offer was removed in the meantime or if its deactivated we skip and call + // processListForRepublishOffers again with the list where we removed the offer already. + processListForRepublishOffers(list); } } private void republishOffer(OpenOffer openOffer) { + republishOffer(openOffer, null); + } + + private void republishOffer(OpenOffer openOffer, @Nullable Runnable completeHandler) { offerBookService.addOffer(openOffer.getOffer(), () -> { if (!stopped) { - log.debug("Successfully added offer to P2P network."); // Refresh means we send only the data needed to refresh the TTL (hash, signature and sequence no.) - if (periodicRefreshOffersTimer == null) + if (periodicRefreshOffersTimer == null) { startPeriodicRefreshOffersTimer(); - } else { - log.debug("We have stopped already. We ignore that offerBookService.republishOffers.onSuccess call."); + } + if (completeHandler != null) { + completeHandler.run(); + } } }, errorMessage -> { @@ -914,26 +940,25 @@ public class OpenOfferManager implements PeerManager.Listener, DecryptedDirectMe stopRetryRepublishOffersTimer(); retryRepublishOffersTimer = UserThread.runAfter(OpenOfferManager.this::republishOffers, RETRY_REPUBLISH_DELAY_SEC); - } else { - log.debug("We have stopped already. We ignore that offerBookService.republishOffers.onFault call."); + + if (completeHandler != null) { + completeHandler.run(); + } } }); } private void startPeriodicRepublishOffersTimer() { stopped = false; - if (periodicRepublishOffersTimer == null) + if (periodicRepublishOffersTimer == null) { periodicRepublishOffersTimer = UserThread.runPeriodically(() -> { if (!stopped) { republishOffers(); - } else { - log.debug("We have stopped already. We ignore that periodicRepublishOffersTimer.run call."); } }, REPUBLISH_INTERVAL_MS, TimeUnit.MILLISECONDS); - else - log.trace("periodicRepublishOffersTimer already stated"); + } } private void startPeriodicRefreshOffersTimer() { diff --git a/core/src/main/java/bisq/core/offer/TriggerPriceService.java b/core/src/main/java/bisq/core/offer/TriggerPriceService.java new file mode 100644 index 0000000000..da82858f09 --- /dev/null +++ b/core/src/main/java/bisq/core/offer/TriggerPriceService.java @@ -0,0 +1,163 @@ +/* + * This file is part of Bisq. + * + * Bisq is free software: you can redistribute it and/or modify it + * under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or (at + * your option) any later version. + * + * Bisq is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public + * License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with Bisq. If not, see . + */ + +package bisq.core.offer; + +import bisq.core.locale.CurrencyUtil; +import bisq.core.monetary.Altcoin; +import bisq.core.monetary.Price; +import bisq.core.provider.price.MarketPrice; +import bisq.core.provider.price.PriceFeedService; + +import bisq.common.util.MathUtils; + +import org.bitcoinj.utils.Fiat; + +import javax.inject.Inject; +import javax.inject.Singleton; + +import javafx.collections.ListChangeListener; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Set; + +import lombok.extern.slf4j.Slf4j; + +import static bisq.common.util.MathUtils.roundDoubleToLong; +import static bisq.common.util.MathUtils.scaleUpByPowerOf10; + +@Slf4j +@Singleton +public class TriggerPriceService { + private final OpenOfferManager openOfferManager; + private final PriceFeedService priceFeedService; + private final Map> openOffersByCurrency = new HashMap<>(); + + @Inject + public TriggerPriceService(OpenOfferManager openOfferManager, PriceFeedService priceFeedService) { + this.openOfferManager = openOfferManager; + this.priceFeedService = priceFeedService; + } + + public void onAllServicesInitialized() { + openOfferManager.getObservableList().addListener((ListChangeListener) c -> { + c.next(); + if (c.wasAdded()) { + onAddedOpenOffers(c.getAddedSubList()); + } + if (c.wasRemoved()) { + onRemovedOpenOffers(c.getRemoved()); + } + }); + onAddedOpenOffers(openOfferManager.getObservableList()); + + priceFeedService.updateCounterProperty().addListener((observable, oldValue, newValue) -> onPriceFeedChanged()); + onPriceFeedChanged(); + } + + private void onPriceFeedChanged() { + openOffersByCurrency.keySet().stream() + .map(priceFeedService::getMarketPrice) + .filter(Objects::nonNull) + .filter(marketPrice -> openOffersByCurrency.containsKey(marketPrice.getCurrencyCode())) + .forEach(marketPrice -> { + openOffersByCurrency.get(marketPrice.getCurrencyCode()).stream() + .filter(openOffer -> !openOffer.isDeactivated()) + .forEach(openOffer -> checkPriceThreshold(marketPrice, openOffer)); + }); + } + + public static boolean wasTriggered(MarketPrice marketPrice, OpenOffer openOffer) { + Price price = openOffer.getOffer().getPrice(); + if (price == null) { + return false; + } + + String currencyCode = openOffer.getOffer().getCurrencyCode(); + boolean cryptoCurrency = CurrencyUtil.isCryptoCurrency(currencyCode); + int smallestUnitExponent = cryptoCurrency ? + Altcoin.SMALLEST_UNIT_EXPONENT : + Fiat.SMALLEST_UNIT_EXPONENT; + long marketPriceAsLong = roundDoubleToLong( + scaleUpByPowerOf10(marketPrice.getPrice(), smallestUnitExponent)); + long triggerPrice = openOffer.getTriggerPrice(); + if (triggerPrice <= 0) { + return false; + } + + OfferPayload.Direction direction = openOffer.getOffer().getDirection(); + boolean isSellOffer = direction == OfferPayload.Direction.SELL; + boolean condition = isSellOffer && !cryptoCurrency || !isSellOffer && cryptoCurrency; + return condition ? + marketPriceAsLong < triggerPrice : + marketPriceAsLong > triggerPrice; + } + + private void checkPriceThreshold(MarketPrice marketPrice, OpenOffer openOffer) { + if (wasTriggered(marketPrice, openOffer)) { + String currencyCode = openOffer.getOffer().getCurrencyCode(); + int smallestUnitExponent = CurrencyUtil.isCryptoCurrency(currencyCode) ? + Altcoin.SMALLEST_UNIT_EXPONENT : + Fiat.SMALLEST_UNIT_EXPONENT; + long triggerPrice = openOffer.getTriggerPrice(); + + log.info("Market price exceeded the trigger price of the open offer.\n" + + "We deactivate the open offer with ID {}.\nCurrency: {};\nOffer direction: {};\n" + + "Market price: {};\nTrigger price: {}", + openOffer.getOffer().getShortId(), + currencyCode, + openOffer.getOffer().getDirection(), + marketPrice.getPrice(), + MathUtils.scaleDownByPowerOf10(triggerPrice, smallestUnitExponent) + ); + + openOfferManager.deactivateOpenOffer(openOffer, () -> { + }, errorMessage -> { + }); + } + } + + private void onAddedOpenOffers(List openOffers) { + openOffers.forEach(openOffer -> { + String currencyCode = openOffer.getOffer().getCurrencyCode(); + openOffersByCurrency.putIfAbsent(currencyCode, new HashSet<>()); + openOffersByCurrency.get(currencyCode).add(openOffer); + + MarketPrice marketPrice = priceFeedService.getMarketPrice(openOffer.getOffer().getCurrencyCode()); + if (marketPrice != null) { + checkPriceThreshold(marketPrice, openOffer); + } + }); + } + + private void onRemovedOpenOffers(List openOffers) { + openOffers.forEach(openOffer -> { + String currencyCode = openOffer.getOffer().getCurrencyCode(); + if (openOffersByCurrency.containsKey(currencyCode)) { + Set set = openOffersByCurrency.get(currencyCode); + set.remove(openOffer); + if (set.isEmpty()) { + openOffersByCurrency.remove(currencyCode); + } + } + }); + } +} diff --git a/core/src/main/java/bisq/core/offer/availability/OfferAvailabilityModel.java b/core/src/main/java/bisq/core/offer/availability/OfferAvailabilityModel.java index 8d183d4085..c1559cec8d 100644 --- a/core/src/main/java/bisq/core/offer/availability/OfferAvailabilityModel.java +++ b/core/src/main/java/bisq/core/offer/availability/OfferAvailabilityModel.java @@ -66,19 +66,24 @@ public class OfferAvailabilityModel implements Model { @Getter private NodeAddress selectedRefundAgent; + // Added in v1.5.5 + @Getter + private final boolean isTakerApiUser; public OfferAvailabilityModel(Offer offer, PubKeyRing pubKeyRing, P2PService p2PService, User user, MediatorManager mediatorManager, - TradeStatisticsManager tradeStatisticsManager) { + TradeStatisticsManager tradeStatisticsManager, + boolean isTakerApiUser) { this.offer = offer; this.pubKeyRing = pubKeyRing; this.p2PService = p2PService; this.user = user; this.mediatorManager = mediatorManager; this.tradeStatisticsManager = tradeStatisticsManager; + this.isTakerApiUser = isTakerApiUser; } public NodeAddress getPeerNodeAddress() { diff --git a/core/src/main/java/bisq/core/offer/availability/tasks/SendOfferAvailabilityRequest.java b/core/src/main/java/bisq/core/offer/availability/tasks/SendOfferAvailabilityRequest.java index 3ee88536c6..0dbc8e69ea 100644 --- a/core/src/main/java/bisq/core/offer/availability/tasks/SendOfferAvailabilityRequest.java +++ b/core/src/main/java/bisq/core/offer/availability/tasks/SendOfferAvailabilityRequest.java @@ -39,7 +39,8 @@ public class SendOfferAvailabilityRequest extends Task { try { runInterceptHook(); - OfferAvailabilityRequest message = new OfferAvailabilityRequest(model.getOffer().getId(), model.getPubKeyRing(), model.getTakersTradePrice()); + OfferAvailabilityRequest message = new OfferAvailabilityRequest(model.getOffer().getId(), + model.getPubKeyRing(), model.getTakersTradePrice(), model.isTakerApiUser()); log.info("Send {} with offerId {} and uid {} to peer {}", message.getClass().getSimpleName(), message.getOfferId(), message.getUid(), model.getPeerNodeAddress()); diff --git a/core/src/main/java/bisq/core/offer/messages/OfferAvailabilityRequest.java b/core/src/main/java/bisq/core/offer/messages/OfferAvailabilityRequest.java index a3cbd1c9d0..6d9d14eaf6 100644 --- a/core/src/main/java/bisq/core/offer/messages/OfferAvailabilityRequest.java +++ b/core/src/main/java/bisq/core/offer/messages/OfferAvailabilityRequest.java @@ -42,13 +42,16 @@ public final class OfferAvailabilityRequest extends OfferMessage implements Supp private final long takersTradePrice; @Nullable private final Capabilities supportedCapabilities; + private final boolean isTakerApiUser; public OfferAvailabilityRequest(String offerId, PubKeyRing pubKeyRing, - long takersTradePrice) { + long takersTradePrice, + boolean isTakerApiUser) { this(offerId, pubKeyRing, takersTradePrice, + isTakerApiUser, Capabilities.app, Version.getP2PMessageVersion(), UUID.randomUUID().toString()); @@ -62,12 +65,14 @@ public final class OfferAvailabilityRequest extends OfferMessage implements Supp private OfferAvailabilityRequest(String offerId, PubKeyRing pubKeyRing, long takersTradePrice, + boolean isTakerApiUser, @Nullable Capabilities supportedCapabilities, int messageVersion, @Nullable String uid) { super(messageVersion, offerId, uid); this.pubKeyRing = pubKeyRing; this.takersTradePrice = takersTradePrice; + this.isTakerApiUser = isTakerApiUser; this.supportedCapabilities = supportedCapabilities; } @@ -76,7 +81,8 @@ public final class OfferAvailabilityRequest extends OfferMessage implements Supp final protobuf.OfferAvailabilityRequest.Builder builder = protobuf.OfferAvailabilityRequest.newBuilder() .setOfferId(offerId) .setPubKeyRing(pubKeyRing.toProtoMessage()) - .setTakersTradePrice(takersTradePrice); + .setTakersTradePrice(takersTradePrice) + .setIsTakerApiUser(isTakerApiUser); Optional.ofNullable(supportedCapabilities).ifPresent(e -> builder.addAllSupportedCapabilities(Capabilities.toIntList(supportedCapabilities))); Optional.ofNullable(uid).ifPresent(e -> builder.setUid(uid)); @@ -90,6 +96,7 @@ public final class OfferAvailabilityRequest extends OfferMessage implements Supp return new OfferAvailabilityRequest(proto.getOfferId(), PubKeyRing.fromProto(proto.getPubKeyRing()), proto.getTakersTradePrice(), + proto.getIsTakerApiUser(), Capabilities.fromIntList(proto.getSupportedCapabilitiesList()), messageVersion, proto.getUid().isEmpty() ? null : proto.getUid()); diff --git a/core/src/main/java/bisq/core/payment/PaymentAccount.java b/core/src/main/java/bisq/core/payment/PaymentAccount.java index b61b86d482..a540641319 100644 --- a/core/src/main/java/bisq/core/payment/PaymentAccount.java +++ b/core/src/main/java/bisq/core/payment/PaymentAccount.java @@ -97,12 +97,25 @@ public abstract class PaymentAccount implements PersistablePayload { } public static PaymentAccount fromProto(protobuf.PaymentAccount proto, CoreProtoResolver coreProtoResolver) { - PaymentAccount account = PaymentAccountFactory.getPaymentAccount(PaymentMethod.getPaymentMethodById(proto.getPaymentMethod().getId())); + String paymentMethodId = proto.getPaymentMethod().getId(); + List tradeCurrencies = proto.getTradeCurrenciesList().stream() + .map(TradeCurrency::fromProto) + .collect(Collectors.toList()); + + // We need to remove NGN for Transferwise + Optional ngnTwOptional = tradeCurrencies.stream() + .filter(e -> paymentMethodId.equals(PaymentMethod.TRANSFERWISE_ID)) + .filter(e -> e.getCode().equals("NGN")) + .findAny(); + // We cannot remove it in the stream as it would cause a concurrentModificationException + ngnTwOptional.ifPresent(tradeCurrencies::remove); + + PaymentAccount account = PaymentAccountFactory.getPaymentAccount(PaymentMethod.getPaymentMethodById(paymentMethodId)); account.getTradeCurrencies().clear(); account.setId(proto.getId()); account.setCreationDate(proto.getCreationDate()); account.setAccountName(proto.getAccountName()); - account.getTradeCurrencies().addAll(proto.getTradeCurrenciesList().stream().map(TradeCurrency::fromProto).collect(Collectors.toList())); + account.getTradeCurrencies().addAll(tradeCurrencies); account.setPaymentAccountPayload(coreProtoResolver.fromProto(proto.getPaymentAccountPayload())); if (proto.hasSelectedTradeCurrency()) diff --git a/core/src/main/java/bisq/core/payment/payload/PaymentMethod.java b/core/src/main/java/bisq/core/payment/payload/PaymentMethod.java index 543ae4a71b..879a2ace13 100644 --- a/core/src/main/java/bisq/core/payment/payload/PaymentMethod.java +++ b/core/src/main/java/bisq/core/payment/payload/PaymentMethod.java @@ -185,7 +185,7 @@ public final class PaymentMethod implements PersistablePayload, Comparable. + */ + +package bisq.core.support.dispute.agent; + +import bisq.core.locale.Res; + +import lombok.extern.slf4j.Slf4j; + +import javax.annotation.Nullable; + +@Slf4j +public class DisputeAgentLookupMap { + + // See also: https://bisq.wiki/Finding_your_mediator + @Nullable + public static String getKeyBaseUserName(String fullAddress) { + switch (fullAddress) { + case "sjlho4zwp3gecspf.onion:9999": + return "leo816"; + case "wizbisqzd7ku25di7p2ztsajioabihlnyp5lq5av66tmu7do2dke2tid.onion:9999": + return "wiz"; + case "apbp7ubuyezav4hy.onion:9999": + return "bisq_knight"; + case "a56olqlmmpxrn5q34itq5g5tb5d3fg7vxekpbceq7xqvfl3cieocgsyd.onion:9999": + return "leo816"; + case "3z5jnirlccgxzoxc6zwkcgwj66bugvqplzf6z2iyd5oxifiaorhnanqd.onion:9999": + return "refundagent2"; + default: + log.warn("No user name for dispute agent with address {} found.", fullAddress); + return Res.get("shared.na"); + } + } +} diff --git a/core/src/main/java/bisq/core/trade/TradeManager.java b/core/src/main/java/bisq/core/trade/TradeManager.java index dc87d4a98c..6707fde8ea 100644 --- a/core/src/main/java/bisq/core/trade/TradeManager.java +++ b/core/src/main/java/bisq/core/trade/TradeManager.java @@ -373,6 +373,7 @@ public class TradeManager implements PersistedDataHost, DecryptedDirectMessageLi /////////////////////////////////////////////////////////////////////////////////////////// public void checkOfferAvailability(Offer offer, + boolean isTakerApiUser, ResultHandler resultHandler, ErrorMessageHandler errorMessageHandler) { if (btcWalletService.isUnconfirmedTransactionsLimitHit() || @@ -383,7 +384,7 @@ public class TradeManager implements PersistedDataHost, DecryptedDirectMessageLi return; } - offer.checkOfferAvailability(getOfferAvailabilityModel(offer), resultHandler, errorMessageHandler); + offer.checkOfferAvailability(getOfferAvailabilityModel(offer, isTakerApiUser), resultHandler, errorMessageHandler); } // First we check if offer is still available then we create the trade with the protocol @@ -396,12 +397,13 @@ public class TradeManager implements PersistedDataHost, DecryptedDirectMessageLi Offer offer, String paymentAccountId, boolean useSavingsWallet, + boolean isTakerApiUser, TradeResultHandler tradeResultHandler, ErrorMessageHandler errorMessageHandler) { checkArgument(!wasOfferAlreadyUsedInTrade(offer.getId())); - OfferAvailabilityModel model = getOfferAvailabilityModel(offer); + OfferAvailabilityModel model = getOfferAvailabilityModel(offer, isTakerApiUser); offer.checkOfferAvailability(model, () -> { if (offer.getState() == Offer.State.AVAILABLE) { @@ -464,14 +466,15 @@ public class TradeManager implements PersistedDataHost, DecryptedDirectMessageLi processModelServiceProvider.getKeyRing().getPubKeyRing()); } - private OfferAvailabilityModel getOfferAvailabilityModel(Offer offer) { + private OfferAvailabilityModel getOfferAvailabilityModel(Offer offer, boolean isTakerApiUser) { return new OfferAvailabilityModel( offer, keyRing.getPubKeyRing(), p2PService, user, mediatorManager, - tradeStatisticsManager); + tradeStatisticsManager, + isTakerApiUser); } diff --git a/core/src/main/java/bisq/core/trade/protocol/FluentProtocol.java b/core/src/main/java/bisq/core/trade/protocol/FluentProtocol.java index 53815bfc07..2d79f9ed7e 100644 --- a/core/src/main/java/bisq/core/trade/protocol/FluentProtocol.java +++ b/core/src/main/java/bisq/core/trade/protocol/FluentProtocol.java @@ -286,8 +286,10 @@ public class FluentProtocol { log.info(info); return Result.VALID.info(info); } else { - String info = MessageFormat.format("We received a {0} but we are are not in the expected phase. " + - "Expected phases={1}, Trade phase={2}, Trade state= {3}, tradeId={4}", + String info = MessageFormat.format("We received a {0} but we are are not in the expected phase.\n" + + "This can be an expected case if we get a repeated CounterCurrencyTransferStartedMessage " + + "after we have already received one as the peer re-sends that message at each startup.\n" + + "Expected phases={1},\nTrade phase={2},\nTrade state= {3},\ntradeId={4}", trigger, expectedPhases, trade.getPhase(), diff --git a/core/src/main/java/bisq/core/trade/protocol/TradeProtocol.java b/core/src/main/java/bisq/core/trade/protocol/TradeProtocol.java index 56fa61edb0..934ad56c50 100644 --- a/core/src/main/java/bisq/core/trade/protocol/TradeProtocol.java +++ b/core/src/main/java/bisq/core/trade/protocol/TradeProtocol.java @@ -196,7 +196,7 @@ public abstract class TradeProtocol implements DecryptedDirectMessageListener, D .condition(condition) .resultHandler(result -> { if (!result.isValid()) { - log.error(result.getInfo()); + log.warn(result.getInfo()); handleTaskRunnerFault(null, result.name(), result.getInfo()); diff --git a/core/src/main/java/bisq/core/trade/txproof/xmr/XmrTxProofService.java b/core/src/main/java/bisq/core/trade/txproof/xmr/XmrTxProofService.java index 9e9ca4c908..469b1b4fc4 100644 --- a/core/src/main/java/bisq/core/trade/txproof/xmr/XmrTxProofService.java +++ b/core/src/main/java/bisq/core/trade/txproof/xmr/XmrTxProofService.java @@ -132,11 +132,8 @@ public class XmrTxProofService implements AssetTxProofService { onP2pNetworkAndWalletReady(); } else { p2pNetworkAndWalletReady = EasyBind.combine(isP2pBootstrapped, hasSufficientBtcPeers, isBtcBlockDownloadComplete, - (bootstrapped, sufficientPeers, downloadComplete) -> { - log.info("isP2pBootstrapped={}, hasSufficientBtcPeers={} isBtcBlockDownloadComplete={}", - bootstrapped, sufficientPeers, downloadComplete); - return bootstrapped && sufficientPeers && downloadComplete; - }); + (bootstrapped, sufficientPeers, downloadComplete) -> + bootstrapped && sufficientPeers && downloadComplete); p2pNetworkAndWalletReadyListener = (observable, oldValue, newValue) -> { if (newValue) { diff --git a/core/src/main/java/bisq/core/user/Cookie.java b/core/src/main/java/bisq/core/user/Cookie.java new file mode 100644 index 0000000000..bc73d6bbd0 --- /dev/null +++ b/core/src/main/java/bisq/core/user/Cookie.java @@ -0,0 +1,63 @@ +/* + * This file is part of Bisq. + * + * Bisq is free software: you can redistribute it and/or modify it + * under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or (at + * your option) any later version. + * + * Bisq is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public + * License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with Bisq. If not, see . + */ + +package bisq.core.user; + +import bisq.common.proto.ProtoUtil; + +import java.util.HashMap; +import java.util.Map; +import java.util.Optional; + +import javax.annotation.Nullable; + +/** + * Serves as flexible container for persisting UI states, layout,... + * Should not be over-used for domain specific data where type safety and data integrity is important. + */ +public class Cookie extends HashMap { + + public void putAsDouble(CookieKey key, double value) { + put(key, String.valueOf(value)); + } + + public Optional getAsOptionalDouble(CookieKey key) { + try { + return containsKey(key) ? + Optional.of(Double.parseDouble(get(key))) : + Optional.empty(); + } catch (Throwable t) { + return Optional.empty(); + } + } + + public Map toProtoMessage() { + Map protoMap = new HashMap<>(); + this.forEach((key, value) -> protoMap.put(key.name(), value)); + return protoMap; + } + + public static Cookie fromProto(@Nullable Map protoMap) { + Cookie cookie = new Cookie(); + if (protoMap != null) { + protoMap.forEach((key, value) -> cookie.put(ProtoUtil.enumFromProto(CookieKey.class, key), value)); + } + return cookie; + } + + +} diff --git a/core/src/main/java/bisq/core/user/CookieKey.java b/core/src/main/java/bisq/core/user/CookieKey.java new file mode 100644 index 0000000000..c8653e54bb --- /dev/null +++ b/core/src/main/java/bisq/core/user/CookieKey.java @@ -0,0 +1,26 @@ +/* + * This file is part of Bisq. + * + * Bisq is free software: you can redistribute it and/or modify it + * under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or (at + * your option) any later version. + * + * Bisq is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public + * License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with Bisq. If not, see . + */ + +package bisq.core.user; + +// Used for persistence of Cookie. Entries must not be changes or removed. Only adding entries is permitted. +public enum CookieKey { + STAGE_X, + STAGE_Y, + STAGE_W, + STAGE_H +} diff --git a/core/src/main/java/bisq/core/user/Preferences.java b/core/src/main/java/bisq/core/user/Preferences.java index 4dd43b85d2..ee276d0ef0 100644 --- a/core/src/main/java/bisq/core/user/Preferences.java +++ b/core/src/main/java/bisq/core/user/Preferences.java @@ -487,6 +487,11 @@ public final class Preferences implements PersistedDataHost, BridgeAddressProvid }); } + public void setHideNonAccountPaymentMethods(boolean hideNonAccountPaymentMethods) { + prefPayload.setHideNonAccountPaymentMethods(hideNonAccountPaymentMethods); + requestPersistence(); + } + private void requestPersistence() { if (initialReadDone) persistenceManager.requestPersistence(); @@ -767,6 +772,16 @@ public final class Preferences implements PersistedDataHost, BridgeAddressProvid requestPersistence(); } + public void setShowOffersMatchingMyAccounts(boolean value) { + prefPayload.setShowOffersMatchingMyAccounts(value); + requestPersistence(); + } + + public void setDenyApiTaker(boolean value) { + prefPayload.setDenyApiTaker(value); + requestPersistence(); + } + /////////////////////////////////////////////////////////////////////////////////////////// // Getter @@ -1074,5 +1089,11 @@ public final class Preferences implements PersistedDataHost, BridgeAddressProvid void setBsqAverageTrimThreshold(double bsqAverageTrimThreshold); void setAutoConfirmSettings(AutoConfirmSettings autoConfirmSettings); + + void setHideNonAccountPaymentMethods(boolean hideNonAccountPaymentMethods); + + void setShowOffersMatchingMyAccounts(boolean value); + + void setDenyApiTaker(boolean value); } } diff --git a/core/src/main/java/bisq/core/user/PreferencesPayload.java b/core/src/main/java/bisq/core/user/PreferencesPayload.java index 0a7aede7e3..b8991f8cba 100644 --- a/core/src/main/java/bisq/core/user/PreferencesPayload.java +++ b/core/src/main/java/bisq/core/user/PreferencesPayload.java @@ -129,6 +129,10 @@ public final class PreferencesPayload implements PersistableEnvelope { // Added at 1.3.8 private List autoConfirmSettingsList = new ArrayList<>(); + // Added in 1.5.5 + private boolean hideNonAccountPaymentMethods; + private boolean showOffersMatchingMyAccounts; + private boolean denyApiTaker; /////////////////////////////////////////////////////////////////////////////////////////// // Constructor @@ -192,7 +196,10 @@ public final class PreferencesPayload implements PersistableEnvelope { .setBsqAverageTrimThreshold(bsqAverageTrimThreshold) .addAllAutoConfirmSettings(autoConfirmSettingsList.stream() .map(autoConfirmSettings -> ((protobuf.AutoConfirmSettings) autoConfirmSettings.toProtoMessage())) - .collect(Collectors.toList())); + .collect(Collectors.toList())) + .setHideNonAccountPaymentMethods(hideNonAccountPaymentMethods) + .setShowOffersMatchingMyAccounts(showOffersMatchingMyAccounts) + .setDenyApiTaker(denyApiTaker); Optional.ofNullable(backupDirectory).ifPresent(builder::setBackupDirectory); Optional.ofNullable(preferredTradeCurrency).ifPresent(e -> builder.setPreferredTradeCurrency((protobuf.TradeCurrency) e.toProtoMessage())); @@ -286,7 +293,10 @@ public final class PreferencesPayload implements PersistableEnvelope { proto.getAutoConfirmSettingsList().isEmpty() ? new ArrayList<>() : new ArrayList<>(proto.getAutoConfirmSettingsList().stream() .map(AutoConfirmSettings::fromProto) - .collect(Collectors.toList())) + .collect(Collectors.toList())), + proto.getHideNonAccountPaymentMethods(), + proto.getShowOffersMatchingMyAccounts(), + proto.getDenyApiTaker() ); } } diff --git a/core/src/main/java/bisq/core/user/User.java b/core/src/main/java/bisq/core/user/User.java index 2f8480e162..04edaf82b5 100644 --- a/core/src/main/java/bisq/core/user/User.java +++ b/core/src/main/java/bisq/core/user/User.java @@ -514,4 +514,8 @@ public class User implements PersistedDataHost { private boolean paymentAccountExists(PaymentAccount paymentAccount) { return getPaymentAccountsAsObservable().stream().anyMatch(e -> e.equals(paymentAccount)); } + + public Cookie getCookie() { + return userPayload.getCookie(); + } } diff --git a/core/src/main/java/bisq/core/user/UserPayload.java b/core/src/main/java/bisq/core/user/UserPayload.java index 212570a6f7..3f2a892f06 100644 --- a/core/src/main/java/bisq/core/user/UserPayload.java +++ b/core/src/main/java/bisq/core/user/UserPayload.java @@ -80,6 +80,11 @@ public class UserPayload implements PersistableEnvelope { @Nullable private List acceptedRefundAgents = new ArrayList<>(); + // Added at 1.5.3 + // Generic map for persisting various UI states. We keep values un-typed as string to + // provide sufficient flexibility. + private Cookie cookie = new Cookie(); + public UserPayload() { } @@ -118,6 +123,7 @@ public class UserPayload implements PersistableEnvelope { Optional.ofNullable(acceptedRefundAgents) .ifPresent(e -> builder.addAllAcceptedRefundAgents(ProtoUtil.collectionToProto(acceptedRefundAgents, message -> ((protobuf.StoragePayload) message).getRefundAgent()))); + Optional.ofNullable(cookie).ifPresent(e -> builder.putAllCookie(cookie.toProtoMessage())); return protobuf.PersistableEnvelope.newBuilder().setUserPayload(builder).build(); } @@ -147,7 +153,8 @@ public class UserPayload implements PersistableEnvelope { proto.hasRegisteredRefundAgent() ? RefundAgent.fromProto(proto.getRegisteredRefundAgent()) : null, proto.getAcceptedRefundAgentsList().isEmpty() ? new ArrayList<>() : new ArrayList<>(proto.getAcceptedRefundAgentsList().stream() .map(RefundAgent::fromProto) - .collect(Collectors.toList())) + .collect(Collectors.toList())), + Cookie.fromProto(proto.getCookieMap()) ); } } diff --git a/core/src/main/java/bisq/core/util/FormattingUtils.java b/core/src/main/java/bisq/core/util/FormattingUtils.java index c567bf1cef..70229fb75a 100644 --- a/core/src/main/java/bisq/core/util/FormattingUtils.java +++ b/core/src/main/java/bisq/core/util/FormattingUtils.java @@ -171,7 +171,7 @@ public class FormattingUtils { return formatMarketPrice(price, 8); } - private static String formatMarketPrice(double price, int precision) { + public static String formatMarketPrice(double price, int precision) { return formatRoundedDoubleWithPrecision(price, precision); } diff --git a/core/src/main/java/bisq/core/util/validation/InputValidator.java b/core/src/main/java/bisq/core/util/validation/InputValidator.java index 7fee474daa..7ce3d68a5e 100644 --- a/core/src/main/java/bisq/core/util/validation/InputValidator.java +++ b/core/src/main/java/bisq/core/util/validation/InputValidator.java @@ -21,6 +21,7 @@ import bisq.core.locale.Res; import java.math.BigInteger; +import java.util.Objects; import java.util.function.Function; public class InputValidator { @@ -65,6 +66,12 @@ public class InputValidator { '}'; } + public boolean errorMessageEquals(ValidationResult other) { + if (this == other) return true; + if (other == null) return false; + return Objects.equals(errorMessage, other.errorMessage); + } + public interface Validator extends Function { } diff --git a/core/src/main/resources/i18n/displayStrings.properties b/core/src/main/resources/i18n/displayStrings.properties index 36b6f1002c..fa72834030 100644 --- a/core/src/main/resources/i18n/displayStrings.properties +++ b/core/src/main/resources/i18n/displayStrings.properties @@ -105,7 +105,6 @@ shared.selectTradingAccount=Select trading account shared.fundFromSavingsWalletButton=Transfer funds from Bisq wallet shared.fundFromExternalWalletButton=Open your external wallet for funding shared.openDefaultWalletFailed=Failed to open a Bitcoin wallet application. Are you sure you have one installed? -shared.distanceInPercent=Distance in % from market price shared.belowInPercent=Below % from market price shared.aboveInPercent=Above % from market price shared.enterPercentageValue=Enter % value @@ -293,7 +292,8 @@ mainView.version.update=(Update available) #################################################################### market.tabs.offerBook=Offer book -market.tabs.spread=Details +market.tabs.spreadCurrency=Offers by Currency +market.tabs.spreadPayment=Offers by Payment Method market.tabs.trades=Trades # OfferBookChartView @@ -312,6 +312,7 @@ market.spread.numberOfBuyOffersColumn=Buy BTC ({0}) market.spread.numberOfSellOffersColumn=Sell BTC ({0}) market.spread.totalAmountColumn=Total BTC ({0}) market.spread.spreadColumn=Spread +market.spread.expanded=Expanded view # TradesChartsView market.trades.nrOfTrades=Trades: {0} @@ -341,6 +342,7 @@ offerbook.offerersAcceptedBankSeats=Accepted seat of bank countries (taker):\n { offerbook.availableOffers=Available offers offerbook.filterByCurrency=Filter by currency offerbook.filterByPaymentMethod=Filter by payment method +offerbook.matchingOffers=Offers matching my accounts offerbook.timeSinceSigning=Account info offerbook.timeSinceSigning.info=This account was verified and {0} offerbook.timeSinceSigning.info.arbitrator=signed by an arbitrator and can sign peer accounts @@ -455,6 +457,13 @@ createOffer.warning.buyAboveMarketPrice=You will always pay {0}% more than the c createOffer.tradeFee.descriptionBTCOnly=Trade fee createOffer.tradeFee.descriptionBSQEnabled=Select trade fee currency +createOffer.triggerPrice.prompt=Set optional trigger price +createOffer.triggerPrice.label=Deactivate offer if market price is {0} +createOffer.triggerPrice.tooltip=As protecting against drastic price movements you can set a trigger price which \ + deactivates the offer if the market price reaches that value. +createOffer.triggerPrice.invalid.tooLow=Value must be higher than {0} +createOffer.triggerPrice.invalid.tooHigh=Value must be lower than {0} + # new entries createOffer.placeOfferButton=Review: Place offer to {0} bitcoin createOffer.createOfferFundWalletInfo.headline=Fund your offer @@ -551,6 +560,11 @@ takeOffer.tac=With taking this offer I agree to the trade conditions as defined # Offerbook / Edit offer #################################################################### +openOffer.header.triggerPrice=Trigger price +openOffer.triggerPrice=Trigger price {0} +openOffer.triggered=The offer has been deactivated because the market price reached your trigger price.\n\ + Please edit the offer to define a new trigger price + editOffer.setPrice=Set price editOffer.confirmEdit=Confirm: Edit offer editOffer.publishOffer=Publishing your offer. @@ -1114,6 +1128,7 @@ support.error=Receiver could not process message. Error: {0} support.buyerAddress=BTC buyer address support.sellerAddress=BTC seller address support.role=Role +support.agent=Support agent support.state=State support.closed=Closed support.open=Open @@ -1207,6 +1222,8 @@ setting.preferences.showOwnOffers=Show my own offers in offer book setting.preferences.useAnimations=Use animations setting.preferences.useDarkMode=Use dark mode setting.preferences.sortWithNumOffers=Sort market lists with no. of offers/trades +setting.preferences.onlyShowPaymentMethodsFromAccount=Hide non-supported payment methods +setting.preferences.denyApiTaker=Deny takers using the API setting.preferences.resetAllFlags=Reset all \"Don't show again\" flags settings.preferences.languageChange=To apply the language change to all screens requires a restart. settings.preferences.supportLanguageWarning=In case of a dispute, please note that mediation is handled in {0} and arbitration in {1}. @@ -2582,7 +2599,8 @@ enterPrivKeyWindow.headline=Enter private key for registration filterWindow.headline=Edit filter list filterWindow.offers=Filtered offers (comma sep.) -filterWindow.onions=Filtered onion addresses (comma sep.) +filterWindow.onions=Banned from trading addresses (comma sep.) +filterWindow.bannedFromNetwork=Banned from network addresses (comma sep.) filterWindow.accounts=Filtered trading account data:\nFormat: comma sep. list of [payment method id | data field | value] filterWindow.bannedCurrencies=Filtered currency codes (comma sep.) filterWindow.bannedPaymentMethods=Filtered payment method IDs (comma sep.) @@ -2603,6 +2621,7 @@ filterWindow.disableTradeBelowVersion=Min. version required for trading filterWindow.add=Add filter filterWindow.remove=Remove filter filterWindow.btcFeeReceiverAddresses=BTC fee receiver addresses +filterWindow.disableApi=Disable API offerDetailsWindow.minBtcAmount=Min. BTC amount offerDetailsWindow.min=(min. {0}) @@ -3321,11 +3340,15 @@ payment.payid=PayID linked to financial institution. Like email address or mobil payment.payid.info=A PayID like a phone number, email address or an Australian Business Number (ABN), that you can securely link to your \ bank, credit union or building society account. You need to have already created a PayID with your Australian financial institution. \ Both sending and receiving financial institutions must support PayID. For more information please check [HYPERLINK:https://payid.com.au/faqs/] -payment.amazonGiftCard.info=To pay with Amazon eGift Card you need to purchase an Amazon eGift Card at your Amazon account and \ - use the BTC seller''s email or mobile nr. as receiver. Amazon sends then an email or text message to the receiver. \ - Use the trade ID for the message field.\n\n\ - Amazon eGift Cards can only be redeemed by Amazon accounts with the same currency.\n\n\ - For more information visit the Amazon eGift Card webpage. [HYPERLINK:https://www.amazon.com/Amazon-1_US_Email-eGift-Card/dp/B004LLIKVU] +payment.amazonGiftCard.info=To pay with Amazon eGift Card, you will need to send an Amazon eGift Card to the BTC seller via your Amazon account. \n\n\ + Bisq will show the BTC seller''s email address or phone number where the gift card should be sent, and you must include the trade ID in the gift \ + card''s message field. Please see the wiki [HYPERLINK:https://bisq.wiki/Amazon_eGift_card] for further details and best practices. \n\n\ + Three important notes:\n\ + - try to send gift cards with amounts of 100 USD or smaller, as Amazon is known to flag larger gift cards as fraudulent\n\ + - try to use creative, believable text for the gift card''s message (e.g., "Happy birthday Susan!") along with the trade ID (and use trader chat \ + to tell your trading peer the reference text you picked so they can verify your payment)\n\ + - Amazon eGift Cards can only be redeemed on the Amazon website they were purchased on (e.g., a gift card purchased on amazon.it can only be redeemed on amazon.it) + # We use constants from the code so we do not use our normal naming convention # dynamic values are not recognized by IntelliJ diff --git a/core/src/main/resources/i18n/displayStrings_cs.properties b/core/src/main/resources/i18n/displayStrings_cs.properties index a59af6365d..01389c6d5b 100644 --- a/core/src/main/resources/i18n/displayStrings_cs.properties +++ b/core/src/main/resources/i18n/displayStrings_cs.properties @@ -46,8 +46,8 @@ shared.buyingCurrency=nakoupit {0} (prodat BTC) shared.sellingCurrency=prodat {0} (nakoupit BTC) shared.buy=koupit shared.sell=prodat -shared.buying=koupit -shared.selling=prodat +shared.buying=kupuje +shared.selling=prodává shared.P2P=P2P shared.oneOffer=nabídka shared.multipleOffers=nabídky @@ -71,6 +71,7 @@ shared.amountWithCur=Množství v {0} shared.volumeWithCur=Objem v {0} shared.currency=Měna shared.market=Trh +shared.deviation=Odchylka shared.paymentMethod=Platební metoda shared.tradeCurrency=Obchodní měna shared.offerType=Typ nabídky @@ -103,10 +104,9 @@ shared.nextStep=Další krok shared.selectTradingAccount=Vyberte obchodní účet shared.fundFromSavingsWalletButton=Přesunout finance z Bisq peněženky shared.fundFromExternalWalletButton=Otevřít vaši externí peněženku pro financování -shared.openDefaultWalletFailed=Nepodařilo se otevřít aplikaci bitcoinové peněženky. Jste si jisti, že máte máte nějakou nainstalovanou? -shared.distanceInPercent=Vzdálenost v % z tržní ceny -shared.belowInPercent=Pod % z tržní ceny -shared.aboveInPercent=Nad % z tržní ceny +shared.openDefaultWalletFailed=Nepodařilo se otevřít aplikaci bitcoinové peněženky. Jste si jisti, že máte nějakou nainstalovanou? +shared.belowInPercent=% pod tržní cenou +shared.aboveInPercent=% nad tržní cenou shared.enterPercentageValue=Zadejte % hodnotu shared.OR=NEBO shared.notEnoughFunds=Ve své peněžence Bisq nemáte pro tuto transakci dostatek prostředků — je potřeba {0}, ale k dispozici je pouze {1}.\n\nPřidejte prostředky z externí peněženky nebo financujte svou peněženku Bisq v části Prostředky > Přijmout prostředky. @@ -123,7 +123,7 @@ shared.noDateAvailable=Žádné datum není k dispozici shared.noDetailsAvailable=Detaily nejsou k dispozici shared.notUsedYet=Ještě nepoužito shared.date=Datum -shared.sendFundsDetailsWithFee=Odesílání: {0}\nZ adresy: {1}\nNa přijímací adresu: {2}.\nPožadovaný poplatek za těžbu je: {3} ({4} satoshi/byte)\nTransakční vsize: {5} vKb\n\nPříjemce obdrží: {6}\n\nOpravdu chcete tuto částku vybrat? +shared.sendFundsDetailsWithFee=Odesílání: {0}\nZ adresy: {1}\nNa přijímací adresu: {2}.\nPožadovaný poplatek za těžbu je: {3} ({4} satoshi/vbyte)\nTransakční vsize: {5} vKb\n\nPříjemce obdrží: {6}\n\nOpravdu chcete tuto částku vybrat? # suppress inspection "TrailingSpacesInProperty" shared.sendFundsDetailsDust=Bisq zjistil, že tato transakce by vytvořila drobné mince, které jsou pod limitem drobných mincí (a není to povoleno pravidly pro bitcoinový konsenzus). Místo toho budou tyto drobné mince ({0} satoshi {1}) přidány k poplatku za těžbu.\n\n\n shared.copyToClipboard=Kopírovat do schránky @@ -149,7 +149,7 @@ shared.information=Informace shared.name=Jméno shared.id=ID shared.dashboard=Dashboard -shared.accept=Příjmout +shared.accept=Přijmout shared.balance=Zůstatek shared.save=Uložit shared.onionAddress=Onion adresa @@ -179,8 +179,8 @@ shared.messageArrived=Zpráva dorazila. shared.messageStoredInMailbox=Zpráva uložena ve schránce shared.messageSendingFailed=Odeslání zprávy selhalo. Chyba: {0} shared.unlock=Odemknout -shared.toReceive=přijmout -shared.toSpend=utratit +shared.toReceive=bude přijata +shared.toSpend=bude utracena shared.btcAmount=Částka BTC shared.yourLanguage=Vaše jazyky shared.addLanguage=Přidat jazyk @@ -191,7 +191,7 @@ shared.tradeWalletBalance=Zůstatek obchodní peněženky shared.makerTxFee=Tvůrce: {0} shared.takerTxFee=Příjemce: {0} shared.iConfirm=Potvrzuji -shared.tradingFeeInBsqInfo=odpovídá {0} použitému jako obchodní poplatek +shared.tradingFeeInBsqInfo=≈ {0} shared.openURL=Otevřené {0} shared.fiat=Fiat shared.crypto=Krypto @@ -205,7 +205,7 @@ shared.sellerUpperCase=Prodejce shared.new=NOVÝ shared.blindVoteTxId=ID transakce se slepým hlasováním shared.proposal=Návrh -shared.votes=Hlasů +shared.votes=Hlasy shared.learnMore=Zjistit více shared.dismiss=Zavřít shared.selectedArbitrator=Zvolený rozhodce @@ -214,10 +214,13 @@ shared.selectedRefundAgent=Zvolený rozhodce shared.mediator=Mediátor shared.arbitrator=Rozhodce shared.refundAgent=Rozhodce -shared.refundAgentForSupportStaff=Vrátit finance agentovi -shared.delayedPayoutTxId=ID zpožděné platební transakce -shared.delayedPayoutTxReceiverAddress=Zpožděná výplatní transakce odeslána na +shared.refundAgentForSupportStaff=Rozhodce pro vrácení peněz +shared.delayedPayoutTxId=ID odložené platební transakce +shared.delayedPayoutTxReceiverAddress=Odložená výplatní transakce odeslána na shared.unconfirmedTransactionsLimitReached=Momentálně máte příliš mnoho nepotvrzených transakcí. Prosím zkuste to znovu později. +shared.numItemsLabel=Počet položek: {0} +shared.filter=Filtr +shared.enabled=Aktivní #################################################################### @@ -248,14 +251,14 @@ mainView.balance.locked=Zamčené v obchodech mainView.balance.reserved.short=Rezervováno mainView.balance.locked.short=Zamčeno -mainView.footer.usingTor=(používá Tor) +mainView.footer.usingTor=(přes Tor) mainView.footer.localhostBitcoinNode=(localhost) -mainView.footer.btcInfo={0} {1} {2} -mainView.footer.btcFeeRate=/ Aktuální sazba poplatku: {0} sat/vB +mainView.footer.btcInfo={0} {1} +mainView.footer.btcFeeRate=/ Aktuální poplatek: {0} sat/vB mainView.footer.btcInfo.initializing=Připojování do Bitcoinové sítě mainView.footer.bsqInfo.synchronizing=/ Synchronizace DAO -mainView.footer.btcInfo.synchronizingWith=Synchronizace s -mainView.footer.btcInfo.synchronizedWith=Synchronizováno s +mainView.footer.btcInfo.synchronizingWith=Synchronizace s {0} v bloku: {1} / {2} +mainView.footer.btcInfo.synchronizedWith=Synchronizováno s {0} v bloku {1} mainView.footer.btcInfo.connectingTo=Připojování mainView.footer.btcInfo.connectionFailed=Připojení se nezdařilo mainView.footer.p2pInfo=Bitcoin síťové nody: {0} / Bisq síťové nody: {1} @@ -296,8 +299,8 @@ market.offerBook.buyAltcoin=Koupit {0} (prodat {1}) market.offerBook.sellAltcoin=Prodat {0} (koupit {1}) market.offerBook.buyWithFiat=Koupit {0} market.offerBook.sellWithFiat=Prodat {0} -market.offerBook.sellOffersHeaderLabel=prodat {0} -market.offerBook.buyOffersHeaderLabel=Buy {0} od +market.offerBook.sellOffersHeaderLabel=Prodat {0} kupujícímu +market.offerBook.buyOffersHeaderLabel=Koupit {0} od prodejce market.offerBook.buy=Chci koupit bitcoin market.offerBook.sell=Chci prodat bitcoin @@ -326,7 +329,7 @@ market.trades.tooltip.candle.date=Datum: offerbook.createOffer=Vytvořit nabídku offerbook.takeOffer=Přijmout nabídku offerbook.takeOfferToBuy=Přijmout nabídku na nákup {0} -offerbook.takeOfferToSell=Příjmout nabídku k prodeji {0} +offerbook.takeOfferToSell=Přijmout nabídku k prodeji {0} offerbook.trader=Obchodník offerbook.offerersBankId=ID banky tvůrce (BIC/SWIFT): {0} offerbook.offerersBankName=Jméno banky tvůrce: {0} @@ -336,12 +339,12 @@ offerbook.offerersAcceptedBankSeats=Přijatá sídla bank (příjemce):\n {0} offerbook.availableOffers=Dostupné nabídky offerbook.filterByCurrency=Filtrovat podle měny offerbook.filterByPaymentMethod=Filtrovat podle platební metody -offerbook.timeSinceSigning=Podepsáno od +offerbook.timeSinceSigning=Informace o účtu offerbook.timeSinceSigning.info=Tento účet byl ověřen a {0} -offerbook.timeSinceSigning.info.arbitrator=podepsan rozhodcem a může podepisovat účty partnerů -offerbook.timeSinceSigning.info.peer=podepsán partnerem, který čeká na zrušení limitů +offerbook.timeSinceSigning.info.arbitrator=podepsán rozhodcem a může podepisovat účty partnerů +offerbook.timeSinceSigning.info.peer=podepsáno partnerem, nyní čeká ještě %d dnů na zrušení limitů offerbook.timeSinceSigning.info.peerLimitLifted=podepsán partnerem a limity byly zrušeny -offerbook.timeSinceSigning.info.signer=podepsán partnerem a může podepsat účty partnera (zrušené limity) +offerbook.timeSinceSigning.info.signer=podepsán partnerem a může podepsat účty partnera (pro zrušení limitů) offerbook.timeSinceSigning.info.banned=účet byl zablokován offerbook.timeSinceSigning.daysSinceSigning={0} dní offerbook.timeSinceSigning.daysSinceSigning.long={0} od podpisu @@ -349,9 +352,12 @@ offerbook.xmrAutoConf=Je automatické potvrzení povoleno offerbook.timeSinceSigning.help=Když úspěšně dokončíte obchod s peerem, který má podepsaný platební účet, je váš platební účet podepsán.\n{0} dní později se počáteční limit {1} zruší a váš účet může podepisovat platební účty ostatních peerů. offerbook.timeSinceSigning.notSigned=Dosud nepodepsáno +offerbook.timeSinceSigning.notSigned.ageDays={0} dní offerbook.timeSinceSigning.notSigned.noNeed=N/A -shared.notSigned=Tento účet dosud nebyl podepsán -shared.notSigned.noNeed=Tento typ účtu nepoužívá podepisování +shared.notSigned=Tento účet ještě nebyl podepsán a byl vytvořen před {0} dny +shared.notSigned.noNeed=Tento typ účtu nevyžaduje podepisování +shared.notSigned.noNeedDays=Tento typ účtu nevyžaduje podepisování a byl vytvořen před {0} dny +shared.notSigned.noNeedAlts=Altcoinové účty neprocházejí kontrolou podpisu a stáří offerbook.nrOffers=Počet nabídek: {0} offerbook.volume={0} (min - max) @@ -365,7 +371,7 @@ offerbook.createOfferToSell.forFiat=Vytvořit novou nabídku k prodeji {0} za {1 offerbook.createOfferToBuy.withCrypto=Vytvořit novou nabídku k prodeji {0} (koupit {1}) offerbook.createOfferToSell.forCrypto=Vytvořit novou nabídku na nákup {0} (prodat {1}) -offerbook.takeOfferButton.tooltip=Využijte nabídku pro {0} +offerbook.takeOfferButton.tooltip=Využijte nabídku {0} offerbook.yesCreateOffer=Ano, vytvořit nabídku offerbook.setupNewAccount=Založit nový obchodní účet offerbook.removeOffer.success=Odebrání nabídky bylo úspěšné. @@ -384,7 +390,7 @@ offerbook.warning.counterpartyTradeRestrictions=Tuto nabídku nelze přijmout z offerbook.warning.newVersionAnnouncement=S touto verzí softwaru mohou obchodní partneři navzájem ověřovat a podepisovat platební účty ostatních a vytvářet tak síť důvěryhodných platebních účtů.\n\nPo úspěšném obchodování s partnerským účtem s ověřeným platebním účtem bude váš platební účet podepsán a obchodní limity budou zrušeny po určitém časovém intervalu (délka tohoto intervalu závisí na způsobu ověření).\n\nDalší informace o podepsání účtu naleznete v dokumentaci na adrese [HYPERLINK:https://docs.bisq.network/payment-methods#account-signing]. popup.warning.tradeLimitDueAccountAgeRestriction.seller=Povolená částka obchodu je omezena na {0} z důvodu bezpečnostních omezení na základě následujících kritérií:\n- Účet kupujícího nebyl podepsán rozhodcem ani obchodním partnerem\n- Doba od podpisu účtu kupujícího není alespoň 30 dní\n- Způsob platby této nabídky je považován za riskantní pro bankovní zpětné zúčtování\n\n{1} -popup.warning.tradeLimitDueAccountAgeRestriction.buyer=Povolená částka obchodu je omezena na {0} z důvodu bezpečnostních omezení na základě následujících kritérií:\n- Váš účet nebyl podepsán rozhodcem ani obxhodním partnerem\n- Čas od podpisu vašeho účtu není alespoň 30 dní\n- Způsob platby této nabídky je považován za riskantní pro bankovní zpětné zúčtování\n\n{1} +popup.warning.tradeLimitDueAccountAgeRestriction.buyer=Povolená částka obchodu je omezena na {0} z důvodu bezpečnostních omezení na základě následujících kritérií:\n- Váš účet nebyl podepsán rozhodcem ani obchodním partnerem\n- Čas od podpisu vašeho účtu není alespoň 30 dní\n- Způsob platby této nabídky je považován za riskantní pro bankovní zpětné zúčtování\n\n{1} offerbook.warning.wrongTradeProtocol=Tato nabídka vyžaduje jinou verzi protokolu než ta, která byla použita ve vaší verzi softwaru.\n\nZkontrolujte, zda máte nainstalovanou nejnovější verzi, jinak uživatel, který nabídku vytvořil, použil starší verzi.\n\nUživatelé nemohou obchodovat s nekompatibilní verzí obchodního protokolu. offerbook.warning.userIgnored=Do seznamu ignorovaných uživatelů jste přidali onion adresu tohoto uživatele. @@ -413,9 +419,9 @@ offerbook.info.roundedFiatVolume=Částka byla zaokrouhlena, aby se zvýšilo so createOffer.amount.prompt=Vložte množství v BTC createOffer.price.prompt=Zadejte cenu createOffer.volume.prompt=Vložte množství v {0} -createOffer.amountPriceBox.amountDescription=Množství BTC k {0} -createOffer.amountPriceBox.buy.volumeDescription=Částka v {0}, kterou chcete utratit -createOffer.amountPriceBox.sell.volumeDescription=Částka v {0}, kterou chcete přijmout +createOffer.amountPriceBox.amountDescription=Množství BTC, které chcete {0} +createOffer.amountPriceBox.buy.volumeDescription=Částka v {0}, kterou utratíte +createOffer.amountPriceBox.sell.volumeDescription=Částka v {0}, kterou přijmete createOffer.amountPriceBox.minAmountDescription=Minimální množství BTC createOffer.securityDeposit.prompt=Kauce createOffer.fundsBox.title=Financujte svou nabídku @@ -423,8 +429,8 @@ createOffer.fundsBox.offerFee=Obchodní poplatek createOffer.fundsBox.networkFee=Poplatek za těžbu createOffer.fundsBox.placeOfferSpinnerInfo=Probíhá publikování nabídky ... createOffer.fundsBox.paymentLabel=Bisq obchod s ID {0} -createOffer.fundsBox.fundsStructure=({0} kauce, {1} obchodní poplatek, {2} poplatek za těžbu) -createOffer.fundsBox.fundsStructure.BSQ=({0} kauce, {1} poplatek za těžbu) + {2} obchodní poplatek +createOffer.fundsBox.fundsStructure=(kauce {0}, obchodní poplatek {1}, poplatek za těžbu {2}) +createOffer.fundsBox.fundsStructure.BSQ=(kauce {0}, poplatek za těžbu {1}) + obchodní poplatek {2} createOffer.success.headline=Vaše nabídka byla publikována createOffer.success.info=Otevřené nabídky můžete spravovat na stránce \"Portfolio/Moje otevřené nabídky\". createOffer.info.sellAtMarketPrice=Vždy budete prodávat za tržní cenu, protože cena vaší nabídky bude průběžně aktualizována. @@ -435,11 +441,15 @@ createOffer.warning.sellBelowMarketPrice=Vždy získáte o {0} % méně, než je createOffer.warning.buyAboveMarketPrice=Vždy zaplatíte o {0} % více, než je aktuální tržní cena, protože cena vaší nabídky bude průběžně aktualizována. createOffer.tradeFee.descriptionBTCOnly=Obchodní poplatek createOffer.tradeFee.descriptionBSQEnabled=Zvolte měnu obchodního poplatku -createOffer.tradeFee.fiatAndPercent=≈ {0} / {1} z částky obchodu + +createOffer.triggerPrice.prompt=Nepovinná limitní cena +createOffer.triggerPrice.label=Deaktivovat nabídku, pokud tržní cena dosáhne {0} +createOffer.triggerPrice.tooltip=Abyste se ochránili před prudkými výkyvy tržních cen, můžete nastavit limitní cenu, po jejímž dosažení bude vaše nabídka stažena. +createOffer.triggerPrice.invalid.tooLow=Hodnota musí být vyšší než {0} +createOffer.triggerPrice.invalid.tooHigh=Hodnota musí být nižší než {0} # new entries createOffer.placeOfferButton=Přehled: Umístěte nabídku k {0} bitcoinu -createOffer.alreadyFunded=Tuto nabídku jste již financovali.\nVaše finanční prostředky byly přesunuty do vaší lokální peněženky Bisq a jsou k dispozici pro výběr na obrazovce \"Prostředky/Odeslat finanční prostředky\". createOffer.createOfferFundWalletInfo.headline=Financujte svou nabídku # suppress inspection "TrailingSpacesInProperty" createOffer.createOfferFundWalletInfo.tradeAmount=- Výše obchodu: {0}\n @@ -451,9 +461,9 @@ createOffer.setAmountPrice=Nastavit množství a cenu createOffer.warnCancelOffer=Tuto nabídku jste již financovali.\nPokud ji nyní zrušíte, budou vaše prostředky přesunuty do lokální peněženky Bisq a jsou k dispozici pro výběr na obrazovce \"Prostředky/Odeslat prostředky\".\nOpravdu ji chcete zrušit? createOffer.timeoutAtPublishing=Při zveřejnění nabídky došlo k vypršení časového limitu. createOffer.errorInfo=\n\nTvůrčí poplatek je již zaplacen. V nejhorším případě jste tento poplatek ztratili.\nZkuste prosím restartovat aplikaci a zkontrolovat síťové připojení, abyste zjistili, zda můžete problém vyřešit. -createOffer.tooLowSecDeposit.warning=Nastavili jstekauci na nižší hodnotu, než je doporučená výchozí hodnota {0}.\nOpravdu chcete použít nižší kauci? +createOffer.tooLowSecDeposit.warning=Nastavili jste kauci na nižší hodnotu, než je doporučená výchozí hodnota {0}.\nOpravdu chcete použít nižší kauci? createOffer.tooLowSecDeposit.makerIsSeller=Poskytuje vám to menší ochranu v případě, že obchodní partner nedodrží obchodní protokol. -createOffer.tooLowSecDeposit.makerIsBuyer=Poskytuje to menší ochranu obchodním partnerům, že dodržujete obchodní protokol, protože máte méně rizikových vkladů. Ostatní uživatelé mohou raději využít jiné nabídky než ty vaše. +createOffer.tooLowSecDeposit.makerIsBuyer=Obchodní partner bude mít menší jistotu, že dodržíte obchodní protokol, protože uložená kauce bude příliš nízká. Ostatní uživatelé mohou raději využít jiné nabídky než té vaší. createOffer.resetToDefault=Ne, restartovat na výchozí hodnotu createOffer.useLowerValue=Ano, použijte moji nižší hodnotu createOffer.priceOutSideOfDeviation=Cena, kterou jste zadali, je mimo max. povolenou odchylku od tržní ceny.\nMax. povolená odchylka je {0} a lze ji upravit v preferencích. @@ -482,24 +492,23 @@ takeOffer.validation.amountSmallerThanMinAmount=Částka nesmí být menší ne takeOffer.validation.amountLargerThanOfferAmount=Vstupní částka nesmí být vyšší než částka stanovená v nabídce. takeOffer.validation.amountLargerThanOfferAmountMinusFee=Toto vstupní množství by vytvořilo zanedbatelné drobné pro prodejce BTC. takeOffer.fundsBox.title=Financujte svůj obchod -takeOffer.fundsBox.isOfferAvailable=Zkontrolujte, zda je nabídka k dispozici ... +takeOffer.fundsBox.isOfferAvailable=Kontroluje se, zda je nabídka k dispozici ... takeOffer.fundsBox.tradeAmount=Částka k prodeji takeOffer.fundsBox.offerFee=Obchodní poplatek takeOffer.fundsBox.networkFee=Celkové poplatky za těžbu takeOffer.fundsBox.takeOfferSpinnerInfo=Probíhá využití nabídky... takeOffer.fundsBox.paymentLabel=Bisq obchod s ID {0} -takeOffer.fundsBox.fundsStructure=({0} kauce, {1} obchodní poplatek, {2} poplatek za těžbu) +takeOffer.fundsBox.fundsStructure=(kauce {0}, obchodní poplatek {1}, poplatek za těžbu {2}) takeOffer.success.headline=Úspěšně jste přijali nabídku. takeOffer.success.info=Stav vašeho obchodu můžete vidět v \"Portfolio/Otevřené obchody\". takeOffer.error.message=Při převzetí nabídky došlo k chybě.\n\n{0} # new entries -takeOffer.takeOfferButton=Přehled: Využijte nabídku na {0} bitcoin(y)\n +takeOffer.takeOfferButton=Přehled: Využijte nabídku {0} bitcoin(y) takeOffer.noPriceFeedAvailable=Tuto nabídku nemůžete vzít, protože používá procentuální cenu založenou na tržní ceně, ale není k dispozici žádný zdroj cen. -takeOffer.alreadyFunded.movedFunds=Tuto nabídku jste již financovali.\nVaše finanční prostředky byly přesunuty do vaší lokální peněženky Bisq a jsou k dispozici pro výběr na obrazovce \"Prostředky/Odeslat finanční prostředky\". takeOffer.takeOfferFundWalletInfo.headline=Financujte svůj obchod # suppress inspection "TrailingSpacesInProperty" -takeOffer.takeOfferFundWalletInfo.tradeAmount=- Výše obchodu: {0} +takeOffer.takeOfferFundWalletInfo.tradeAmount=- Výše obchodu: {0} \n takeOffer.takeOfferFundWalletInfo.msg=Abyste mohli tuto nabídku využít, musíte vložit {0}.\n\nČástka je součtem:\n{1} - Vaší kauce: {2}\n- Obchodního poplatku: {3}\n- Celkového poplatku za těžbu: {4}\n\nPři financování obchodu si můžete vybrat ze dvou možností:\n- Použijte svou peněženku Bisq (pohodlné, ale transakce mohou být propojitelné) NEBO\n- Platba z externí peněženky (potenciálně více soukromé)\n\nPo uzavření tohoto vyskakovacího okna se zobrazí všechny možnosti a podrobnosti financování. takeOffer.alreadyPaidInFunds=Pokud jste již prostředky zaplatili, můžete je vybrat na obrazovce \"Prostředky/Odeslat prostředky\". takeOffer.paymentInfo=Informace o platbě @@ -524,6 +533,10 @@ takeOffer.tac=Přijetím této nabídky souhlasím s obchodními podmínkami def # Offerbook / Edit offer #################################################################### +openOffer.header.triggerPrice=Limitní cena +openOffer.triggerPrice=Limitní cena {0} +openOffer.triggered=Nabídka byla deaktivována, protože tržní cena dosáhla vámi stanovené limitní ceny.\nProsím nastavte novou limitní cenu ve vaší nabídce + editOffer.setPrice=Nastavit cenu editOffer.confirmEdit=Potvrdit: Upravit nabídku editOffer.publishOffer=Publikování vaší nabídky. @@ -541,13 +554,15 @@ portfolio.tab.history=Historie portfolio.tab.failed=Selhalo portfolio.tab.editOpenOffer=Upravit nabídku -portfolio.pending.invalidDelayedPayoutTx=Došlo k problému s chybějící nebo neplatnou transakcí.\n\nProsím neposílejte fiat nebo altcoin platby. Požádejte vývojáře Bisq na Keybase [HYPERLINK:https://keybase.io/team/bisq] or on the forum [HYPERLINK:https://bisq.community] for further assistance\n\nChybová zpráva: {0} +portfolio.closedTrades.deviation.help=Procentuální odchylka od tržní ceny + +portfolio.pending.invalidDelayedPayoutTx=Došlo k problému s chybějící nebo neplatnou transakcí.\n\nProsím neposílejte fiat nebo altcoin platby. Požádejte o asistenci vývojáře Bisq na Keybase [HYPERLINK:https://keybase.io/team/bisq] nebo na fóru [HYPERLINK:https://bisq.community].\n\nChybová zpráva: {0} portfolio.pending.step1.waitForConf=Počkejte na potvrzení na blockchainu portfolio.pending.step2_buyer.startPayment=Zahajte platbu portfolio.pending.step2_seller.waitPaymentStarted=Počkejte, než začne platba portfolio.pending.step3_buyer.waitPaymentArrived=Počkejte, než dorazí platba -portfolio.pending.step3_seller.confirmPaymentReceived=Potvrzující platba přijata +portfolio.pending.step3_seller.confirmPaymentReceived=Potvrďte přijetí platby portfolio.pending.step5.completed=Hotovo portfolio.pending.step3_seller.autoConf.status.label=Stav automat. potvrzení @@ -598,7 +613,7 @@ portfolio.pending.step2_buyer.fees=Pokud vaše banka účtuje poplatky, musíte # suppress inspection "TrailingSpacesInProperty" portfolio.pending.step2_buyer.altcoin=Převeďte prosím z vaší externí {0} peněženky\n{1} prodejci BTC.\n\n # suppress inspection "TrailingSpacesInProperty" -portfolio.pending.step2_buyer.cash=Přejděte do banky a zaplatte {0} prodejci BTC.\n\n +portfolio.pending.step2_buyer.cash=Přejděte do banky a zaplaťte {0} prodejci BTC.\n\n portfolio.pending.step2_buyer.cash.extra=DŮLEŽITÉ POŽADAVKY:\nPo provedení platby zapište na papírový doklad: NO REFUNDS - bez náhrady.\nPoté ji roztrhněte na 2 části, vytvořte fotografii a odešlete ji na e-mailovou adresu prodejce BTC. # suppress inspection "TrailingSpacesInProperty" portfolio.pending.step2_buyer.moneyGram=Zaplaťte prosím {0} prodejci BTC pomocí MoneyGram.\n\n @@ -612,7 +627,7 @@ portfolio.pending.step2_buyer.amazonGiftCard=Kupte si na svém účtu Amazon kar # suppress inspection "TrailingSpacesInProperty" portfolio.pending.step2_buyer.postal=Zašlete prosím {0} prodejci BTC pomocí \"US Postal Money Order\".\n\n # suppress inspection "TrailingSpacesInProperty" -portfolio.pending.step2_buyer.bank=Přejděte na webovou stránku online bankovnictví a zaplatte {0} prodejci BTC.\n\n +portfolio.pending.step2_buyer.bank=Přejděte na webovou stránku online bankovnictví a zaplaťte {0} prodejci BTC.\n\n # suppress inspection "TrailingSpacesInProperty" portfolio.pending.step2_buyer.f2f=Kontaktujte prodejce BTC prostřednictvím poskytnutého kontaktu a domluvte si schůzku kde zaplatíte {0}.\n\n portfolio.pending.step2_buyer.startPaymentUsing=Zahajte platbu pomocí {0} @@ -646,7 +661,7 @@ portfolio.pending.step2_seller.warn=Kupující BTC dosud neprovedl platbu {0}.\n portfolio.pending.step2_seller.openForDispute=Kupující BTC ještě nezačal s platbou!\nMax. povolené období pro obchod vypršelo.\nMůžete počkat déle a dát obchodnímu partnerovi více času nebo požádat o pomoc mediátora. tradeChat.chatWindowTitle=Okno chatu pro obchod s ID ''{0}'' tradeChat.openChat=Otevřít chatovací okno -tradeChat.rules=Můžete komunikovat se svým obchodním partnerem a vyřešit případné problémy s tímto obchodem.\nOdpovídat v chatu není povinné.\nPokud obchodník poruší některé z níže uvedených pravidel, zahajte spor a nahlašte jej mediátorovi nebo rozhodci.\n\nPravidla chatu:\n\t● Neposílejte žádné odkazy (riziko malwaru). Můžete odeslat ID transakce a jméno block exploreru.\n\t● Neposílejte seed slova, soukromé klíče, hesla nebo jiné citlivé informace!\n\t● Nepodporujte obchodování mimo Bisq (bez zabezpečení).\n\t● Nezapojujte se do žádných forem podvodů v oblasti sociálního inženýrství.\n\t● Pokud partner nereaguje a dává přednost nekomunikovat prostřednictvím chatu, respektujte jeho rozhodnutí.\n\t● Soustřeďte konverzaci pouze na obchod. Tento chat není náhradou messengeru.\n\t● Udržujte konverzaci přátelskou a uctivou. +tradeChat.rules=Můžete komunikovat se svým obchodním partnerem a vyřešit případné problémy s tímto obchodem.\nOdpovídat v chatu není povinné.\nPokud obchodník poruší některé z níže uvedených pravidel, zahajte spor a nahlaste jej mediátorovi nebo rozhodci.\n\nPravidla chatu:\n\t● Neposílejte žádné odkazy (riziko malwaru). Můžete odeslat ID transakce a jméno block exploreru.\n\t● Neposílejte seed slova, soukromé klíče, hesla nebo jiné citlivé informace!\n\t● Nepodporujte obchodování mimo Bisq (bez zabezpečení).\n\t● Nezapojujte se do žádných forem podvodů v oblasti sociálního inženýrství.\n\t● Pokud partner nereaguje a dává přednost nekomunikovat prostřednictvím chatu, respektujte jeho rozhodnutí.\n\t● Soustřeďte konverzaci pouze na obchod. Tento chat není náhradou messengeru.\n\t● Udržujte konverzaci přátelskou a uctivou. # suppress inspection "UnusedProperty" message.state.UNDEFINED=Nedefinováno @@ -666,7 +681,7 @@ portfolio.pending.step3_buyer.wait.info=Čekání na potvrzení prodejce BTC na portfolio.pending.step3_buyer.wait.msgStateInfo.label=Stav zprávy o zahájení platby portfolio.pending.step3_buyer.warn.part1a=na {0} blockchainu portfolio.pending.step3_buyer.warn.part1b=u vašeho poskytovatele plateb (např. banky) -portfolio.pending.step3_buyer.warn.part2=Prodejce BTC vaši platbu stále nepotvrdil. Zkontrolujte {0}, zda bylo odeslání platby úspěšné. +portfolio.pending.step3_buyer.warn.part2=Prodejce BTC vaši platbu stále nepotvrdil. Zkontrolujte {0}, zda bylo odeslání platby úspěšné. portfolio.pending.step3_buyer.openForDispute=Prodejce BTC nepotvrdil vaši platbu! Max. období pro uskutečnění obchodu uplynulo. Můžete počkat déle a dát obchodnímu partnerovi více času nebo požádat o pomoc mediátora. # suppress inspection "TrailingSpacesInProperty" portfolio.pending.step3_seller.part=Váš obchodní partner potvrdil, že zahájil platbu {0}.\n\n @@ -695,7 +710,7 @@ portfolio.pending.step3_seller.xmrTxKey=Transakční klíč portfolio.pending.step3_seller.buyersAccount=Údaje o účtu kupujícího portfolio.pending.step3_seller.confirmReceipt=Potvrďte příjem platby portfolio.pending.step3_seller.buyerStartedPayment=Kupující BTC zahájil platbu {0}.\n{1} -portfolio.pending.step3_seller.buyerStartedPayment.altcoin=Podívejte se na potvrzení na blockchainu ve své alltcoin peněžence nebo v blok exploreru a potvrďte platbu, pokud máte dostatečné potvrzení na blockchainu. +portfolio.pending.step3_seller.buyerStartedPayment.altcoin=Podívejte se na potvrzení na blockchainu ve své altcoin peněžence nebo v blok exploreru a potvrďte platbu, pokud máte dostatečné potvrzení na blockchainu. portfolio.pending.step3_seller.buyerStartedPayment.fiat=Zkontrolujte na svém obchodním účtu (např. Bankovní účet) a potvrďte, kdy jste platbu obdrželi. portfolio.pending.step3_seller.warn.part1a=na {0} blockchainu portfolio.pending.step3_seller.warn.part1b=u vašeho poskytovatele plateb (např. banky) @@ -706,7 +721,7 @@ portfolio.pending.step3_seller.onPaymentReceived.part1=Obdrželi jste od svého # suppress inspection "TrailingSpacesInProperty" portfolio.pending.step3_seller.onPaymentReceived.fiat=ID obchodní (\"důvod platby\" text) transakce je: \"{0}\"\n\n # suppress inspection "TrailingSpacesInProperty" -portfolio.pending.step3_seller.onPaymentReceived.name=Ověřte také, zda se jméno odesílatele uvedené v obchodní smlouvě shoduje s jménem uvedeným na výpisu z účtu:\nJméno odesílatele podle obchodní smlouvy: {0}\n\nPokud jména nejsou úplně stejná, nepotvrzujte příjem platby. Místo toho otevřete spor stisknutím \"alt + o\" nebo \"option + o\".\n\n +portfolio.pending.step3_seller.onPaymentReceived.name=Ověřte také, zda se jméno odesílatele uvedené v obchodní smlouvě shoduje se jménem uvedeným na výpisu z účtu:\nJméno odesílatele podle obchodní smlouvy: {0}\n\nPokud jména nejsou úplně stejná, nepotvrzujte příjem platby. Místo toho otevřete spor stisknutím \"alt + o\" nebo \"option + o\".\n\n # suppress inspection "TrailingSpacesInProperty" portfolio.pending.step3_seller.onPaymentReceived.note=Vezměte prosím na vědomí, že jakmile potvrdíte příjem, bude uzamčená částka obchodu vrácena kupujícímu BTC a záloha bude vrácena.\n\n portfolio.pending.step3_seller.onPaymentReceived.confirm.headline=Potvrďte, že jste obdržel(a) platbu @@ -755,7 +770,7 @@ portfolio.pending.openSupportTicket.msg=Použijte tuto funkci pouze v naléhavý portfolio.pending.timeLockNotOver=Než budete moci zahájit rozhodčí spor, musíte počkat do ≈{0} ({1} dalších bloků). portfolio.pending.error.depositTxNull=Vkladová operace je nulová. Nemůžete otevřít spor bez platné vkladové transakce. Přejděte do \"Nastavení/Informace o síti\" a proveďte resynchronizaci SPV.\n\nPro další pomoc prosím kontaktujte podpůrný kanál v Bisq Keybase týmu. portfolio.pending.mediationResult.error.depositTxNull=Vkladová transakce je nulová. Obchod můžete přesunout do neúspěšných obchodů. -portfolio.pending.mediationResult.error.delayedPayoutTxNull=Zpožděná výplatní transakce je nulová. Obchod můžete přesunout do neúspěšných obchodů. +portfolio.pending.mediationResult.error.delayedPayoutTxNull=Odložená výplatní transakce je nulová. Obchod můžete přesunout do neúspěšných obchodů. portfolio.pending.error.depositTxNotConfirmed=Vkladová transakce není potvrzena. Nemůžete zahájit rozhodčí spor s nepotvrzenou vkladovou transakcí. Počkejte prosím, až bude potvrzena, nebo přejděte do \"Nastavení/Informace o síti\" a proveďte resynchronizaci SPV.\n\nPro další pomoc prosím kontaktujte podpůrný kanál v Bisq Keybase týmu. portfolio.pending.support.headline.getHelp=Potřebujete pomoc? @@ -789,8 +804,8 @@ portfolio.pending.mediationResult.popup.alreadyAccepted=Už jste přijali portfolio.pending.failedTrade.taker.missingTakerFeeTx=Chybí poplatek příjemce transakce.\n\nBez tohoto tx nelze obchod dokončit. Nebyly uzamčeny žádné prostředky a nebyl zaplacen žádný obchodní poplatek. Tento obchod můžete přesunout do neúspěšných obchodů. portfolio.pending.failedTrade.maker.missingTakerFeeTx=Chybí poplatek příjemce transakce.\n\nBez tohoto tx nelze obchod dokončit. Nebyly uzamčeny žádné prostředky. Vaše nabídka je stále k dispozici dalším obchodníkům, takže jste neztratili poplatek za vytvoření. Tento obchod můžete přesunout do neúspěšných obchodů. portfolio.pending.failedTrade.missingDepositTx=Vkladová transakce (transakce 2-of-2 multisig) chybí.\n\nBez tohoto tx nelze obchod dokončit. Nebyly uzamčeny žádné prostředky, ale byl zaplacen váš obchodní poplatek. Zde můžete požádat o vrácení obchodního poplatku: [HYPERLINK:https://github.com/bisq-network/support/issues]\n\nKlidně můžete přesunout tento obchod do neúspěšných obchodů. -portfolio.pending.failedTrade.buyer.existingDepositTxButMissingDelayedPayoutTx=Zpožděná výplatní transakce chybí, ale prostředky byly uzamčeny v vkladové transakci.\n\nNezasílejte prosím fiat nebo altcoin platbu prodejci BTC, protože bez zpožděné platby tx nelze zahájit arbitráž. Místo toho otevřete mediační úkol pomocí Cmd/Ctrl+o. Mediátorl by měl navrhnout, aby oba partneři dostali zpět celou částku svých bezpečnostních vkladů (přičemž prodejce také obdrží plnou částku obchodu). Tímto způsobem nehrozí žádné bezpečnostní riziko a jsou ztraceny pouze obchodní poplatky.\n\nO vrácení ztracených obchodních poplatků můžete požádat zde: [HYPERLINK:https://github.com/bisq-network/support/issues] -portfolio.pending.failedTrade.seller.existingDepositTxButMissingDelayedPayoutTx=Zpožděná výplatní transakce chybí, ale prostředky byly v depozitní transakci uzamčeny.\n\nPokud kupujícímu chybí také zpožděná výplatní transakce, bude poučen, aby platbu NEPOSLAL a místo toho otevřel mediační úkol. Měli byste také otevřít mediační úkol pomocí Cmd/Ctrl+o.\n\nPokud kupující ještě neposlal platbu, měl by zprostředkovatel navrhnout, aby oba partneři dostali zpět celou částku svých bezpečnostních vkladů (přičemž prodejce také obdrží plnou částku obchodu). Jinak by částka obchodu měla jít kupujícímu.\n\nO vrácení ztracených obchodních poplatků můžete požádat zde: [HYPERLINK:https://github.com/bisq-network/support/issues] +portfolio.pending.failedTrade.buyer.existingDepositTxButMissingDelayedPayoutTx=Odložená výplatní transakce chybí, ale prostředky byly uzamčeny v vkladové transakci.\n\nNezasílejte prosím fiat nebo altcoin platbu prodejci BTC, protože bez odložené platby tx nelze zahájit arbitráž. Místo toho otevřete mediační úkol pomocí Cmd/Ctrl+o. Mediátor by měl navrhnout, aby oba partneři dostali zpět celou částku svých bezpečnostních vkladů (přičemž prodejce také obdrží plnou částku obchodu). Tímto způsobem nehrozí žádné bezpečnostní riziko a jsou ztraceny pouze obchodní poplatky.\n\nO vrácení ztracených obchodních poplatků můžete požádat zde: [HYPERLINK:https://github.com/bisq-network/support/issues] +portfolio.pending.failedTrade.seller.existingDepositTxButMissingDelayedPayoutTx=Odložená výplatní transakce chybí, ale prostředky byly v depozitní transakci uzamčeny.\n\nPokud kupujícímu chybí také odložená výplatní transakce, bude poučen, aby platbu NEPOSLAL a místo toho otevřel mediační úkol. Měli byste také otevřít mediační úkol pomocí Cmd/Ctrl+o.\n\nPokud kupující ještě neposlal platbu, měl by zprostředkovatel navrhnout, aby oba partneři dostali zpět celou částku svých bezpečnostních vkladů (přičemž prodejce také obdrží plnou částku obchodu). Jinak by částka obchodu měla jít kupujícímu.\n\nO vrácení ztracených obchodních poplatků můžete požádat zde: [HYPERLINK:https://github.com/bisq-network/support/issues] portfolio.pending.failedTrade.errorMsgSet=Během provádění obchodního protokolu došlo k chybě.\n\nChyba: {0}\n\nJe možné, že tato chyba není kritická a obchod lze dokončit normálně. Pokud si nejste jisti, otevřete si mediační úkol a získejte radu od mediátorů Bisq.\n\nPokud byla chyba kritická a obchod nelze dokončit, možná jste ztratili obchodní poplatek. O vrácení ztracených obchodních poplatků požádejte zde: [HYPERLINK:https://github.com/bisq-network/support/issues] portfolio.pending.failedTrade.missingContract=Obchodní kontrakt není stanoven.\n\nObchod nelze dokončit a možná jste ztratili poplatek za obchodování. Pokud ano, můžete požádat o vrácení ztracených obchodních poplatků zde: [HYPERLINK:https://github.com/bisq-network/support/issues] portfolio.pending.failedTrade.info.popup=Obchodní protokol narazil na některé problémy.\n\n{0} @@ -801,15 +816,15 @@ portfolio.pending.failedTrade.warningIcon.tooltip=Kliknutím otevřete podrobnos portfolio.failed.revertToPending.popup=Chcete přesunout tento obchod do otevřených obchodů? portfolio.failed.revertToPending=Přesunout obchod do otevřených obchodů -portfolio.closed.completed=Hotovo -portfolio.closed.ticketClosed=Rozhodovaný -portfolio.closed.mediationTicketClosed=Mediovaný +portfolio.closed.completed=Dokončeno +portfolio.closed.ticketClosed=Rozhodnuto +portfolio.closed.mediationTicketClosed=Mediováno portfolio.closed.canceled=Zrušeno portfolio.failed.Failed=Selhalo portfolio.failed.unfail=Před pokračováním se ujistěte, že máte zálohu vašeho datového adresáře!\nChcete tento obchod přesunout zpět do otevřených obchodů?\nJe to způsob, jak odemknout finanční prostředky uvízlé v neúspěšném obchodu. portfolio.failed.cantUnfail=Tento obchod nelze v tuto chvíli přesunout zpět do otevřených obchodů.\nZkuste to znovu po dokončení obchodu (obchodů) {0} portfolio.failed.depositTxNull=Obchod nelze změnit zpět na otevřený obchod. Transakce s vkladem je neplatná. -portfolio.failed.delayedPayoutTxNull=Obchod nelze změnit zpět na otevřený obchod. Zpožděná výplatní transakce je nulová. +portfolio.failed.delayedPayoutTxNull=Obchod nelze změnit zpět na otevřený obchod. Odložená výplatní transakce je nulová. #################################################################### @@ -831,21 +846,21 @@ funds.deposit.withdrawFromWallet=Pošlete peníze z peněženky funds.deposit.amount=Částka v BTC (volitelná) funds.deposit.generateAddress=Vygenerujte novou adresu funds.deposit.generateAddressSegwit=Nativní formát segwit (Bech32) -funds.deposit.selectUnused=Vyberte prosím nepoužívanou adresu z výše uvedené tabulky spíše než generovat novou. +funds.deposit.selectUnused=Vyberte prosím nepoužívanou adresu z výše uvedené tabulky místo generování nové. funds.withdrawal.arbitrationFee=Poplatek za arbitráž funds.withdrawal.inputs=Volba vstupů funds.withdrawal.useAllInputs=Použijte všechny dostupné vstupy funds.withdrawal.useCustomInputs=Použijte vlastní vstupy -funds.withdrawal.receiverAmount=Částka příjemce -funds.withdrawal.senderAmount=Částka odesílatele +funds.withdrawal.receiverAmount=Částka pro příjemce +funds.withdrawal.senderAmount=Náklad pro odesílatele funds.withdrawal.feeExcluded=Částka nezahrnuje poplatek za těžbu funds.withdrawal.feeIncluded=Částka zahrnuje poplatek za těžbu funds.withdrawal.fromLabel=Výběr z adresy -funds.withdrawal.toLabel=Adresa výběru +funds.withdrawal.toLabel=Adresa příjemce funds.withdrawal.memoLabel=Poznámka k výběru funds.withdrawal.memo=Volitelně vyplňte poznámku -funds.withdrawal.withdrawButton=Zvolen výběr +funds.withdrawal.withdrawButton=Odeslat výběr funds.withdrawal.noFundsAvailable=Pro výběr nejsou k dispozici žádné finanční prostředky funds.withdrawal.confirmWithdrawalRequest=Potvrďte žádost o výběr funds.withdrawal.withdrawMultipleAddresses=Výběr z více adres ({0}) @@ -864,12 +879,12 @@ funds.locked.noFunds=V obchodech nejsou zamčeny žádné prostředky funds.locked.locked=Uzamčeno v multisig adrese pro obchodování s ID: {0} funds.tx.direction.sentTo=Odesláno na: -funds.tx.direction.receivedWith=Přijato s: +funds.tx.direction.receivedWith=Přijato z: funds.tx.direction.genesisTx=Z Genesis tx: funds.tx.txFeePaymentForBsqTx=Poplatek za těžbu za BSQ tx funds.tx.createOfferFee=Poplatky tvůrce a tx: {0} funds.tx.takeOfferFee=Poplatky příjemce a tx: {0} -funds.tx.multiSigDeposit=Vlkad na multisig adresu: {0} +funds.tx.multiSigDeposit=Vklad na multisig adresu: {0} funds.tx.multiSigPayout=Výběr z multisig adresy: {0} funds.tx.disputePayout=Výběr ze sporu: {0} funds.tx.disputeLost=Prohraných sporů: {0} @@ -886,13 +901,12 @@ funds.tx.noTxAvailable=Není k dispozici žádná transakce funds.tx.revert=Vrátit funds.tx.txSent=Transakce byla úspěšně odeslána na novou adresu v lokální peněžence Bisq. funds.tx.direction.self=Poslat sobě -funds.tx.daoTxFee=Poplatek za těžbu za DAO tx +funds.tx.daoTxFee=Poplatek za těžbu za BSQ tx funds.tx.reimbursementRequestTxFee=Žádost o vyrovnání -funds.tx.compensationRequestTxFee=Žádost o odškodnění +funds.tx.compensationRequestTxFee=Žádost o odměnu funds.tx.dustAttackTx=Přijaté drobné funds.tx.dustAttackTx.popup=Tato transakce odesílá do vaší peněženky velmi malou částku BTC a může se jednat o pokus společností provádějících analýzu blockchainu o špehování vaší peněženky.\n\nPoužijete-li tento transakční výstup ve výdajové transakci, zjistí, že jste pravděpodobně také vlastníkem jiné adresy (sloučení mincí).\n\nKvůli ochraně vašeho soukromí ignoruje peněženka Bisq takové drobné výstupy pro účely utrácení a na obrazovce zůstatku. Můžete nastavit hodnotu "drobnosti", kdy je výstup považován za drobné, v nastavení. - #################################################################### # Support #################################################################### @@ -900,13 +914,13 @@ funds.tx.dustAttackTx.popup=Tato transakce odesílá do vaší peněženky velmi support.tab.mediation.support=Mediace support.tab.arbitration.support=Arbitráž support.tab.legacyArbitration.support=Starší arbitráž -support.tab.ArbitratorsSupportTickets={0} úkoly +support.tab.ArbitratorsSupportTickets=Úkoly pro {0} support.filter=Hledat spory support.filter.prompt=Zadejte ID obchodu, datum, onion adresu nebo údaje o účtu -support.sigCheck.button=Ověřít výsledek +support.sigCheck.button=Ověřit výsledek support.sigCheck.popup.info=V případě žádosti o vrácení peněz DAO musíte vložit souhrnnou zprávu procesu zprostředkování a rozhodčího řízení do své žádosti o vrácení peněz na Githubu. Aby bylo toto prohlášení ověřitelné, může každý uživatel pomocí tohoto nástroje zkontrolovat, zda se podpis mediátora nebo rozhodce shoduje se souhrnnou zprávou. -support.sigCheck.popup.header=Ověřít podpis výsledku sporu +support.sigCheck.popup.header=Ověřit podpis výsledku sporu support.sigCheck.popup.msg.label=Souhrnná zpráva support.sigCheck.popup.msg.prompt=Zkopírovat a vložit souhrnnou zprávu ze sporu support.sigCheck.popup.result=Výsledek ověření @@ -938,11 +952,12 @@ support.closeTicket=Zavřít úkol support.attachments=Přílohy: support.savedInMailbox=Zpráva uložena ve schránce příjemce support.arrived=Zpráva dorazila k příjemci -support.acknowledged=Příjetí zprávy potvrzeno příjemcem +support.acknowledged=Přijetí zprávy potvrzeno příjemcem support.error=Příjemce nemohl zpracovat zprávu. Chyba: {0} support.buyerAddress=Adresa kupujícího BTC support.sellerAddress=Adresa prodejce BTC support.role=Role +support.agent=Agent podpory support.state=Stav support.closed=Zavřeno support.open=Otevřené @@ -962,7 +977,7 @@ support.peerOpenedDispute=Váš obchodní partner požádal o spor.\n\n{0}\n\nBi support.peerOpenedDisputeForMediation=Váš obchodní partner požádal o mediaci.\n\n{0}\n\nBisq verze: {1} support.mediatorsDisputeSummary=Systémová zpráva: Shrnutí sporu mediátora:\n{0} support.mediatorsAddress=Adresa uzlu mediátora: {0} -support.warning.disputesWithInvalidDonationAddress=Zpožděná výplatní transakce použila neplatnou adresu příjemce. Neshoduje se s žádnou z hodnot parametrů DAO pro platné dárcovské adresy.\n\nMůže to být pokus o podvod. Informujte prosím vývojáře o tomto incidentu a neuzavírejte tento případ, dokud nebude situace vyřešena!\n\nAdresa použitá ve sporu: {0}\n\nVšechny parametry pro darovací adresy DAO: {1}\n\nObchodní ID: {2} {3} +support.warning.disputesWithInvalidDonationAddress=Odložená výplatní transakce použila neplatnou adresu příjemce. Neshoduje se s žádnou z hodnot parametrů DAO pro platné dárcovské adresy.\n\nMůže to být pokus o podvod. Informujte prosím vývojáře o tomto incidentu a neuzavírejte tento případ, dokud nebude situace vyřešena!\n\nAdresa použitá ve sporu: {0}\n\nVšechny parametry pro darovací adresy DAO: {1}\n\nObchodní ID: {2} {3} support.warning.disputesWithInvalidDonationAddress.mediator=\n\nStále chcete spor uzavřít? support.warning.disputesWithInvalidDonationAddress.refundAgent=\n\nVýplatu nesmíte provést. @@ -972,7 +987,7 @@ support.warning.disputesWithInvalidDonationAddress.refundAgent=\n\nVýplatu nesm #################################################################### settings.tab.preferences=Preference settings.tab.network=Informace o síti -settings.tab.about=O +settings.tab.about=O Bisq setting.preferences.general=Základní nastavení setting.preferences.explorer=Bitcoin Explorer @@ -984,7 +999,7 @@ setting.preferences.autoConfirmXMR=Automatické potvrzení XMR setting.preferences.autoConfirmEnabled=Povoleno setting.preferences.autoConfirmRequiredConfirmations=Požadovaná potvrzení setting.preferences.autoConfirmMaxTradeSize=Max. částka obchodu (BTC) -setting.preferences.autoConfirmServiceAddresses=Monero Explorer URL (používá Tor, kromě localhost, LAN IP adres a * .local hostname) +setting.preferences.autoConfirmServiceAddresses=Monero Explorer URL (používá Tor, kromě localhost, LAN IP adres a názvů hostitele *.local) setting.preferences.deviationToLarge=Hodnoty vyšší než {0} % nejsou povoleny. setting.preferences.txFee=Poplatek za výběr transakce (satoshi/vbyte) setting.preferences.useCustomValue=Použijte vlastní hodnotu @@ -1006,11 +1021,11 @@ setting.preferences.showOwnOffers=Zobrazit mé vlastní nabídky v seznamu nabí setting.preferences.useAnimations=Použít animace setting.preferences.useDarkMode=Použít tmavý režim setting.preferences.sortWithNumOffers=Seřadit seznamy trhů s počtem nabídek/obchodů -setting.preferences.resetAllFlags=Obnovit všechny příznaky \"Nezobrazovat znovu\" +setting.preferences.resetAllFlags=Zrušit všechny "Nezobrazovat znovu" settings.preferences.languageChange=Chcete-li použít změnu jazyka na všech obrazovkách, musíte restartovat aplikaci. settings.preferences.supportLanguageWarning=V případě sporu mějte na paměti, že zprostředkování je řešeno v {0} a arbitráž v {1}. setting.preferences.daoOptions=Možnosti DAO -setting.preferences.dao.resyncFromGenesis.label=Znovu obnovit stav DAO z genesis tx +setting.preferences.dao.resyncFromGenesis.label=Obnovit stav DAO z genesis tx setting.preferences.dao.resyncFromResources.label=Obnovit stav DAO ze zdrojů setting.preferences.dao.resyncFromResources.popup=Po restartu aplikace budou data správy sítě Bisq znovu načtena z počátečních uzlů a stav konsensu BSQ bude znovu vytvořen z nejnovějších zdrojů. setting.preferences.dao.resyncFromGenesis.popup=Resynchronizace z genesis transakce může stát značné množství času a prostředků CPU. Opravdu to chcete udělat? Většinou je resynchronizace z nejnovějších zdrojových souborů dostatečná a mnohem rychlejší.\n\nPokud budete pokračovat, po restartu aplikace budou data správy sítě Bisq znovu načtena z počátečních uzlů a stav konsensu BSQ bude znovu vytvořen z genesis transakce. @@ -1043,7 +1058,7 @@ settings.net.useCustomNodesRadio=Použijte vlastní Bitcoin Core node settings.net.warn.usePublicNodes=Používáte-li veřejnou bitcoinovou síť, jste vystaveni závažnému problému s ochranou soukromí způsobenému porušením návrhu a implementace bloom filtru, který se používá pro peněženky SPV, jako je BitcoinJ (použitý v Bisq). Každý full node, ke kterému jste připojeni, mohl zjistit, že všechny vaše adresy peněženky patří jedné entitě.\n\nPřečtěte si více o podrobnostech na adrese: [HYPERLINK:https://bisq.network/blog/privacy-in-bitsquare].\n\nOpravdu chcete použít veřejné nody? settings.net.warn.usePublicNodes.useProvided=Ne, použijte nabízené nody settings.net.warn.usePublicNodes.usePublic=Ano, použít veřejnou síť -settings.net.warn.useCustomNodes.B2XWarning=Ujistěte se, že váš bitcoinový node je důvěryhodný BItcoin Core node!\n\nPřipojení k nodům, které nedodržují pravidla konsensu Bitcoin Core, může poškodit vaši peněženku a způsobit problémy v obchodním procesu.\n\nUživatelé, kteří se připojují k nodům, které porušují pravidla konsensu, odpovídají za případné škody, které z toho vyplývají. Jakékoli výsledné spory budou rozhodnuty ve prospěch druhého obchodníka. Uživatelům, kteří ignorují tyto varovné a ochranné mechanismy, nebude poskytována technická podpora! +settings.net.warn.useCustomNodes.B2XWarning=Ujistěte se, že váš bitcoinový node je důvěryhodný Bitcoin Core node!\n\nPřipojení k nodům, které nedodržují pravidla konsensu Bitcoin Core, může poškodit vaši peněženku a způsobit problémy v obchodním procesu.\n\nUživatelé, kteří se připojují k nodům, které porušují pravidla konsensu, odpovídají za případné škody, které z toho vyplývají. Jakékoli výsledné spory budou rozhodnuty ve prospěch druhého obchodníka. Uživatelům, kteří ignorují tyto varovné a ochranné mechanismy, nebude poskytována technická podpora! settings.net.warn.invalidBtcConfig=Připojení k bitcoinové síti selhalo, protože je vaše konfigurace neplatná.\n\nVaše konfigurace byla resetována, aby se místo toho použily poskytnuté bitcoinové uzly. Budete muset restartovat aplikaci. settings.net.localhostBtcNodeInfo=Základní informace: Bisq při spuštění hledá místní Bitcoinový uzel. Pokud je nalezen, Bisq bude komunikovat se sítí Bitcoin výhradně skrze něj. settings.net.p2PPeersLabel=Připojené uzly @@ -1052,6 +1067,7 @@ settings.net.creationDateColumn=Založeno settings.net.connectionTypeColumn=Příchozí/Odchozí settings.net.sentDataLabel=Statistiky odeslaných dat settings.net.receivedDataLabel=Statistiky přijatých dat +settings.net.chainHeightLabel=Poslední výška bloku BTC settings.net.roundTripTimeColumn=Roundtrip settings.net.sentBytesColumn=Odesláno settings.net.receivedBytesColumn=Přijato @@ -1066,6 +1082,7 @@ settings.net.needRestart=Chcete-li použít tuto změnu, musíte restartovat apl settings.net.notKnownYet=Není dosud známo... settings.net.sentData=Odeslaná data: {0}, {1} zprávy, {2} zprávy/sekundu settings.net.receivedData=Přijatá data: {0}, {1} zprávy, {2} zprávy/sekundu +settings.net.chainHeight=Bisq: {0} | Peer: {1} settings.net.ips=[IP adresa:port | název hostitele:port | onion adresa:port] (oddělené čárkou). Pokud je použit výchozí port (8333), lze port vynechat. settings.net.seedNode=Seed node settings.net.directPeer=Peer uzel (přímý) @@ -1074,7 +1091,7 @@ settings.net.inbound=příchozí settings.net.outbound=odchozí settings.net.reSyncSPVChainLabel=Znovu synchronizovat SPV řetěz settings.net.reSyncSPVChainButton=Odstraňte soubor SPV a znovu synchronizujte -settings.net.reSyncSPVSuccess=Při dalším spuštění bude smazán řetězový soubor SPV. Nyní je třeba aplikaci restartovat.\n\nPo restartu může chvíli trvat, než se znovu synchronizuje se sítí, a všechny transakce uvidíte až po dokončení resynchronizace.\n\nV závislosti na počtu transakcí a stáří vaší peněženky může resynchronizace trvat až několik hodin a spotřebovávat 100% CPU. Proces nepřerušujte, jinak jej musíte opakovat. +settings.net.reSyncSPVSuccess=Opravdu chcete provést synchronizaci SPV? Pokud budete pokračovat, soubor řetězce SPV bude při příštím spuštění smazán.\n\nPo restartu může chvíli trvat, než se znovu provede synchronizuje se sítí a všechny transakce se zobrazí až po dokončení synchronizace.\n\nV závislosti na počtu transakcí a stáří vaší peněženky může resynchronizace trvat až několik hodin a spotřebuje 100% CPU. Nepřerušujte proces, jinak ho budete muset opakovat. settings.net.reSyncSPVAfterRestart=Soubor řetězu SPV byl odstraněn. Prosím, buďte trpěliví. Resynchronizace se sítí může chvíli trvat. settings.net.reSyncSPVAfterRestartCompleted=Resynchronizace je nyní dokončena. Restartujte aplikaci. settings.net.reSyncSPVFailed=Nelze odstranit soubor řetězce SPV.\nChyba: {0} @@ -1152,25 +1169,35 @@ setting.info.msg=Při prodeji BTC za XMR můžete pomocí funkce automatického #################################################################### account.tab.mediatorRegistration=Registrace mediátora -account.tab.refundAgentRegistration=Registrace agenta vrácení peněz +account.tab.refundAgentRegistration=Registrace rozhodce pro vrácení peněz account.tab.signing=Podepisování account.info.headline=Vítejte ve vašem účtu Bisq -account.info.msg=Zde můžete přidat obchodní účty pro národní měny & altcoiny a vytvořit zálohu dat vaší peněženky a účtu.\n\nPři prvním spuštění Bisq byla vytvořena nová bitcoinová peněženka.\n\nDůrazně doporučujeme zapsat si seed slova bitcoinových peněženek (viz záložka nahoře) a před financováním zvážit přidání hesla. Vklady a výběry bitcoinů jsou spravovány v sekci \ "Finance \".\n\nOchrana osobních údajů a zabezpečení: protože Bisq je decentralizovaná smenárna, všechna data jsou uložena ve vašem počítači. Neexistují žádné servery, takže nemáme přístup k vašim osobním informacím, vašim finančním prostředkům ani vaší IP adrese. Údaje, jako jsou čísla bankovních účtů, adresy altcoinů a bitcoinu atd., jsou sdíleny pouze s obchodním partnerem za účelem uskutečnění obchodů, které zahájíte (v případě sporu uvidí Prostředník nebo Rozhodce stejná data jako váš obchodní peer uzel). +account.info.msg=Zde můžete přidat obchodní účty pro národní měny & altcoiny a vytvořit zálohu dat vaší peněženky a účtu.\n\nPři prvním spuštění Bisq byla vytvořena nová bitcoinová peněženka.\n\nDůrazně doporučujeme zapsat si seed slova bitcoinových peněženek (viz záložka nahoře) a před financováním zvážit přidání hesla. Vklady a výběry bitcoinů jsou spravovány v sekci \ "Finance \".\n\nOchrana osobních údajů a zabezpečení: protože Bisq je decentralizovaná směnárna, všechna data jsou uložena ve vašem počítači. Neexistují žádné servery, takže nemáme přístup k vašim osobním informacím, vašim finančním prostředkům ani vaší IP adrese. Údaje, jako jsou čísla bankovních účtů, adresy altcoinů a bitcoinu atd., jsou sdíleny pouze s obchodním partnerem za účelem uskutečnění obchodů, které zahájíte (v případě sporu uvidí Prostředník nebo Rozhodce stejná data jako váš obchodní peer uzel). account.menu.paymentAccount=Účty v národní měně account.menu.altCoinsAccountView=Altcoinové účty account.menu.password=Heslo peněženky account.menu.seedWords=Seed peněženky +account.menu.walletInfo=Info o peněžence account.menu.backup=Záloha account.menu.notifications=Oznámení +account.menu.walletInfo.balance.headLine=Zůstatky v peněžence +account.menu.walletInfo.balance.info=Zde jsou zobrazeny celkové zůstatky v interní peněžence včetně nepotvrzených transakcí.\nInterní zůstatek BTC uvedený níže by měl odpovídat součtu hodnot 'Dostupný zůstatek' a 'Rezervováno v nabídkách' v pravém horním rohu aplikace. +account.menu.walletInfo.xpub.headLine=Veřejné klíče (xpub) +account.menu.walletInfo.walletSelector={0} {1} peněženka +account.menu.walletInfo.path.headLine=HD identifikátory klíčů +account.menu.walletInfo.path.info=Pokud importujete vaše seed slova do jiné peněženky (např. Electrum), budete muset nastavit také identifikátor klíčů (BIP32 path). Toto provádějte pouze ve výjimečných případech, např. pokud úplně ztratíte kontrolu nad Bisq peněženkou.\nMějte na paměti, že provádění transakcí pomocí jiných softwarových peněženek může snadno poškodit interní datové struktury systému Bisq, a znemožnit tak provádění obchodů.\n\nNIKDY neposílejte BSQ pomocí jiných softwarových peněženek než Bisq, protože byste tím velmi pravděpodobně vytvořili neplatnou BSQ transakci, a ztratili tak své BSQ. + +account.menu.walletInfo.openDetails=Zobrazit detailní data peněženky a soukromé klíče + ## TODO should we rename the following to a gereric name? account.arbitratorRegistration.pubKey=Veřejný klíč account.arbitratorRegistration.register=Registrovat -account.arbitratorRegistration.registration={0} registrace +account.arbitratorRegistration.registration=Registrace {0} account.arbitratorRegistration.revoke=Odvolat -account.arbitratorRegistration.info.msg=Upozorňujeme, že po odvolání musíte zůstat k dispozici 15 dní, protože mohou existovat obchody, které vás používají jako {0}. Max. povolené obchodní období je 8 dní a proces řešení sporu může trvat až 7 dní. +account.arbitratorRegistration.info.msg=Upozorňujeme, že po odvolání musíte zůstat k dispozici 15 dní, protože mohou existovat obchody, pro které jste {0}. Max. povolené obchodní období je 8 dní a proces řešení sporu může trvat až 7 dní. account.arbitratorRegistration.warn.min1Language=Musíte nastavit alespoň 1 jazyk.\nPřidali jsme vám výchozí jazyk. account.arbitratorRegistration.removedSuccess=Úspěšně jste odstranili svou registraci ze sítě Bisq. account.arbitratorRegistration.removedFailed=Registraci se nepodařilo odebrat. {0} @@ -1178,18 +1205,18 @@ account.arbitratorRegistration.registerSuccess=Úspěšně jste se zaregistroval account.arbitratorRegistration.registerFailed=Registraci se nepodařilo dokončit. {0} account.altcoin.yourAltcoinAccounts=Vaše altcoinové účty -account.altcoin.popup.wallet.msg=Ujistěte se, že dodržujete požadavky na používání peněženek {0}, jak je popsáno na webové stránce {1}.\nPoužití peněženek z centralizovaných směnáren, kde (a) nevlastníte své privátní klíče nebo (b) které nepoužívají kompatibilní software peněženky, je riskantní: může to vést ke ztrátě obchodovaných prostředků!\nMediátor nebo rozhodce není specialista {2} a v takových případech nemůže pomoci. +account.altcoin.popup.wallet.msg=Ujistěte se, že dodržujete požadavky na používání peněženek {0}, jak je popsáno na webové stránce {1}.\nPoužití peněženek z centralizovaných směnáren, kde (a) nevlastníte své soukromé klíče nebo (b) které nepoužívají kompatibilní software peněženky, je riskantní: může to vést ke ztrátě obchodovaných prostředků!\nMediátor nebo rozhodce není specialista {2} a v takových případech nemůže pomoci. account.altcoin.popup.wallet.confirm=Rozumím a potvrzuji, že vím, jakou peněženku musím použít. # suppress inspection "UnusedProperty" -account.altcoin.popup.upx.msg=Obchodování s UPX na Bisq vyžaduje, abyste pochopili a splnili následující požadavky:\n\nK odeslání UPX musíte použít buď oficiální peněženku GUI uPlexa nebo CLI peněženku uPlexa s povoleným příznakem store-tx-info (výchozí hodnota v nových verzích). Ujistěte se, že máte přístup k klíči tx, který může být vyžadován v případě sporu.\nuplexa-wallet-cli (použijte příkaz get_tx_key)\nuplexa-wallet-gui (přejděte na záložku historie a pro potvrzení platby klikněte na tlačítko (P))\n\nV normálním block exploreru není přenos ověřitelný.\n\nV případě sporu musíte rozhodci poskytnout následující údaje:\n- Soukromý klíč tx\n- Hash transakce\n- Veřejnou adresa příjemce\n\nPokud neposkytnete výše uvedená data nebo použijete nekompatibilní peněženku, dojde ke prohrání sporu. Odesílatel UPX odpovídá za zajištění ověření přenosu UPX rozhodci v případě sporu.\n\nNení požadováno žádné platební ID, pouze normální veřejná adresa.\nPokud si nejste jisti tímto procesem, vyhledejte další informace na discord kanálu uPlexa (https://discord.gg/vhdNSrV) nebo uPlexa Telegram Chatu (https://t.me/uplexaOfficial). +account.altcoin.popup.upx.msg=Obchodování s UPX na Bisq vyžaduje, abyste pochopili a splnili následující požadavky:\n\nK odeslání UPX musíte použít buď oficiální peněženku GUI uPlexa nebo CLI peněženku uPlexa s povoleným příznakem store-tx-info (výchozí hodnota v nových verzích). Ujistěte se, že máte přístup ke klíči tx, který může být vyžadován v případě sporu.\nuplexa-wallet-cli (použijte příkaz get_tx_key)\nuplexa-wallet-gui (přejděte na záložku historie a pro potvrzení platby klikněte na tlačítko (P))\n\nV normálním block exploreru není přenos ověřitelný.\n\nV případě sporu musíte rozhodci poskytnout následující údaje:\n- Soukromý klíč tx\n- Hash transakce\n- Veřejnou adresa příjemce\n\nPokud neposkytnete výše uvedená data nebo použijete nekompatibilní peněženku, dojde ke prohrání sporu. Odesílatel UPX odpovídá za zajištění ověření přenosu UPX rozhodci v případě sporu.\n\nNení požadováno žádné platební ID, pouze normální veřejná adresa.\nPokud si nejste jisti tímto procesem, vyhledejte další informace na discord kanálu uPlexa (https://discord.gg/vhdNSrV) nebo uPlexa Telegram Chatu (https://t.me/uplexaOfficial). # suppress inspection "UnusedProperty" -account.altcoin.popup.arq.msg=Obchodování ARQ na Bisq vyžaduje, abyste pochopili a splnili následující požadavky:\n\nK odeslání ARQ musíte použít buď oficiální peněženku ArQmA GUI nebo peněženku ArQmA CLI s povoleným příznakem store-tx-info (výchozí hodnota v nových verzích). Ujistěte se, že máte přístup k klíči tx, který může být vyžadován v případě sporu.\narqma-wallet-cli (použijte příkaz get_tx_key)\narqma-wallet-gui (přejděte na kartu historie a pro potvrzení platby klikněte na tlačítko (P))\n\nV normálním blok exploreru není přenos ověřitelný.\n\nV případě sporu musíte mediátorovi nebo rozhodci poskytnout následující údaje:\n- Soukromý klíč tx\n- Hash transakce\n- Veřejnou adresu příjemce\n\nPokud neposkytnete výše uvedená data nebo použijete nekompatibilní peněženku, dojde ke prohrání sporu. Odesílatel ARQ odpovídá za zajištění ověření převodu ARQ mediátorovi nebo rozhodci v případě sporu.\n\nNení požadováno žádné platební ID, pouze normální veřejná adresa.\nPokud si nejste jisti tímto procesem, navštivte discord kanál ArQmA (https://discord.gg/s9BQpJT) nebo fórum ArQmA (https://labs.arqma.com). +account.altcoin.popup.arq.msg=Obchodování ARQ na Bisq vyžaduje, abyste pochopili a splnili následující požadavky:\n\nK odeslání ARQ musíte použít buď oficiální peněženku ArQmA GUI nebo peněženku ArQmA CLI s povoleným příznakem store-tx-info (výchozí hodnota v nových verzích). Ujistěte se, že máte přístup ke klíči tx, který může být vyžadován v případě sporu.\narqma-wallet-cli (použijte příkaz get_tx_key)\narqma-wallet-gui (přejděte na kartu historie a pro potvrzení platby klikněte na tlačítko (P))\n\nV normálním blok exploreru není přenos ověřitelný.\n\nV případě sporu musíte mediátorovi nebo rozhodci poskytnout následující údaje:\n- Soukromý klíč tx\n- Hash transakce\n- Veřejnou adresu příjemce\n\nPokud neposkytnete výše uvedená data nebo použijete nekompatibilní peněženku, dojde ke prohrání sporu. Odesílatel ARQ odpovídá za zajištění ověření převodu ARQ mediátorovi nebo rozhodci v případě sporu.\n\nNení požadováno žádné platební ID, pouze normální veřejná adresa.\nPokud si nejste jisti tímto procesem, navštivte discord kanál ArQmA (https://discord.gg/s9BQpJT) nebo fórum ArQmA (https://labs.arqma.com). # suppress inspection "UnusedProperty" account.altcoin.popup.xmr.msg=Obchodování s XMR na Bisq vyžaduje, abyste pochopili následující požadavek.\n\nPokud prodáváte XMR, musíte být schopni v případě sporu poskytnout mediátorovi nebo rozhodci následující informace:\n- transakční klíč (Tx klíč, Tx tajný klíč nebo Tx soukromý klíč)\n- ID transakce (Tx ID nebo Tx Hash)\n- cílová adresa (adresa příjemce)\n\nNa wiki najdete podrobnosti, kde najdete tyto informace v populárních peněženkách Monero:\n[HYPERLINK:https://bisq.wiki/Trading_Monero#Proving_payments].\n\nNeposkytnutí požadovaných údajů o transakci bude mít za následek ztrátu sporů.\n\nVšimněte si také, že Bisq nyní nabízí automatické potvrzení transakcí XMR, aby byly obchody rychlejší, ale musíte to povolit v Nastavení.\n\nDalší informace o funkci automatického potvrzení najdete na wiki:\n[HYPERLINK:https://bisq.wiki/Trading_Monero#Auto-confirming_trades]. # suppress inspection "UnusedProperty" -account.altcoin.popup.msr.msg=Obchodování MSR na Bisq vyžaduje, abyste pochopili a splnili následující požadavky:\n\nK odeslání MSR musíte použít buď oficiální peněženku Masari GUI, peněženku Masari CLI s povoleným příznakem store-tx-info (ve výchozím nastavení povoleno) nebo webovou peněženku Masari (https://wallet.getmasari.org). Ujistěte se, že máte přístup k klíči tx, který může být vyžadován v případě sporu.\nmasari-wallet-cli (použijte příkaz get_tx_key)\nmasari-wallet-gui (přejděte na kartu historie a klikněte na tlačítko (P) pro potvrzení platby)\n\nWebová peněženka Masari (jděte do Účet -> Historie transakcí a zobrazte podrobností o odeslané transakci)\n\nOvěření lze provést v peněžence.\nmasari-wallet-cli: pomocí příkazu (check_tx_key).\nmasari-wallet-gui: na stránce Pokročilé > Dokázat/Ověřit.\nOvěření lze provést v block exploreru\nOtevřete Block explorer (https://explorer.getmasari.org), použijte vyhledávací lištu k nalezení hash transakce.\nJakmile je transakce nalezena, přejděte dolů do oblasti „Prokázat odesílání“ a podle potřeby vyplňte podrobnosti.\nV případě sporu musíte zprostředkovateli nebo rozhodci poskytnout následující údaje:\n- Soukromý klíč tx\n- Hash transakce\n- Veřejnou adresu příjemce\n\nPokud neposkytnete výše uvedená data nebo použijete nekompatibilní peněženku, dojde ke ztrátě sporu. Odesílatel MSR odpovídá za zajištění ověření přenosu MSR mediátorovi nebo rozhodci v případě sporu.\n\nNení požadováno žádné platební ID, pouze normální veřejná adresa.\nPokud si nejste jisti tímto procesem, požádejte o pomoc oficiální Masari Discord (https://discord.gg/sMCwMqs). +account.altcoin.popup.msr.msg=Obchodování MSR na Bisq vyžaduje, abyste pochopili a splnili následující požadavky:\n\nK odeslání MSR musíte použít buď oficiální peněženku Masari GUI, peněženku Masari CLI s povoleným příznakem store-tx-info (ve výchozím nastavení povoleno) nebo webovou peněženku Masari (https://wallet.getmasari.org). Ujistěte se, že máte přístup ke klíči tx, který může být vyžadován v případě sporu.\nmasari-wallet-cli (použijte příkaz get_tx_key)\nmasari-wallet-gui (přejděte na kartu historie a klikněte na tlačítko (P) pro potvrzení platby)\n\nWebová peněženka Masari (jděte do Účet -> Historie transakcí a zobrazte podrobností o odeslané transakci)\n\nOvěření lze provést v peněžence.\nmasari-wallet-cli: pomocí příkazu (check_tx_key).\nmasari-wallet-gui: na stránce Pokročilé > Dokázat/Ověřit.\nOvěření lze provést v block exploreru\nOtevřete Block explorer (https://explorer.getmasari.org), použijte vyhledávací lištu k nalezení hash transakce.\nJakmile je transakce nalezena, přejděte dolů do oblasti „Prokázat odesílání“ a podle potřeby vyplňte podrobnosti.\nV případě sporu musíte zprostředkovateli nebo rozhodci poskytnout následující údaje:\n- Soukromý klíč tx\n- Hash transakce\n- Veřejnou adresu příjemce\n\nPokud neposkytnete výše uvedená data nebo použijete nekompatibilní peněženku, dojde ke ztrátě sporu. Odesílatel MSR odpovídá za zajištění ověření přenosu MSR mediátorovi nebo rozhodci v případě sporu.\n\nNení požadováno žádné platební ID, pouze normální veřejná adresa.\nPokud si nejste jisti tímto procesem, požádejte o pomoc oficiální Masari Discord (https://discord.gg/sMCwMqs). # suppress inspection "UnusedProperty" -account.altcoin.popup.blur.msg=Obchodování BLUR na Bisq vyžaduje, abyste pochopili a splnili následující požadavky:\n\nK odeslání BLUR musíte použít Blur Network CLI nebo GUI peněženku.\n\nPoužíváte-li peněženku CLI, po odeslání transakce se zobrazí hash transakce (tx ID). Tyto informace si musíte uložit. Ihned po odeslání tranakce musíte použít příkaz 'get_tx_key' pro načtení soukromého klíče transakce. Pokud tento krok neprovedete, pravděpodobně nebudete moci klíč získat později.\n\nPokud používáte peněženku GUI Blur Network, lze soukromý klíč transakce a ID transakce pohodlně nalézt na kartě Historie. Ihned po odeslání vyhledejte příslušnou transakci. Klikněte na "?" symbol v pravém dolním rohu pole obsahující transakci. Tyto informace si musíte uložit.\n\nV případě, že je nutné rozhodčí řízení, musíte mediátorovi nebo rozhodci předložit následující: 1.) ID transakce, 2.) soukromý klíč transakce a 3.) Adresu příjemce. Mediátor nebo rozhodce poté ověří přenos BLUR pomocí prohlížeče BLUR transakcí (https://blur.cash/#tx-viewer).\n\nNeposkytnutí požadovaných informací mediátorovi nebo rozhodci povede k prohrání sporu. Ve všech sporných případech nese odesílatel BLUR 100% odpovědnosti za ověřování transakcí mediátorovi nebo rozhodci.\n\nPokud těmto požadavkům nerozumíte, neobchodujte na Bisq. Nejprve vyhledejte pomoc na Blur Network Discord (https://discord.gg/dMWaqVW). +account.altcoin.popup.blur.msg=Obchodování BLUR na Bisq vyžaduje, abyste pochopili a splnili následující požadavky:\n\nK odeslání BLUR musíte použít Blur Network CLI nebo GUI peněženku.\n\nPoužíváte-li peněženku CLI, po odeslání transakce se zobrazí hash transakce (tx ID). Tyto informace si musíte uložit. Ihned po odeslání transakce musíte použít příkaz 'get_tx_key' pro načtení soukromého klíče transakce. Pokud tento krok neprovedete, pravděpodobně nebudete moci klíč získat později.\n\nPokud používáte peněženku GUI Blur Network, lze soukromý klíč transakce a ID transakce pohodlně nalézt na kartě Historie. Ihned po odeslání vyhledejte příslušnou transakci. Klikněte na "?" symbol v pravém dolním rohu pole obsahující transakci. Tyto informace si musíte uložit.\n\nV případě, že je nutné rozhodčí řízení, musíte mediátorovi nebo rozhodci předložit následující: 1.) ID transakce, 2.) soukromý klíč transakce a 3.) Adresu příjemce. Mediátor nebo rozhodce poté ověří přenos BLUR pomocí prohlížeče BLUR transakcí (https://blur.cash/#tx-viewer).\n\nNeposkytnutí požadovaných informací mediátorovi nebo rozhodci povede k prohrání sporu. Ve všech sporných případech nese odesílatel BLUR 100% odpovědnosti za ověřování transakcí mediátorovi nebo rozhodci.\n\nPokud těmto požadavkům nerozumíte, neobchodujte na Bisq. Nejprve vyhledejte pomoc na Blur Network Discord (https://discord.gg/dMWaqVW). # suppress inspection "UnusedProperty" account.altcoin.popup.solo.msg=Obchodování Solo na Bisq vyžaduje, abyste pochopili a splnili následující požadavky:\n\nK odeslání Solo musíte použít peněženku CLI Solo Network.\n\nPoužíváte-li peněženku CLI, po odeslání přenosu se zobrazí hash transakce (tx ID). Tyto informace si musíte uložit. Ihned po odeslání převodu musíte použít příkaz 'get_tx_key' pro načtení soukromého klíče transakce. Pokud tento krok neprovedete, pravděpodobně nebudete moci klíč získat později.\n\nV případě, že je nutné rozhodčí řízení, musíte mediátorovi nebo rozhodci předložit následující: 1.) ID transakce, 2.) Soukromý klíč transakce a 3.) Adresu příjemce. Mediátor nebo rozhodce poté ověří převod Solo pomocí Solo Block Exploreru vyhledáním transakce a poté pomocí funkce „Prokažte odesílání“ (https://explorer.minesolo.com/).\n\nneposkytnutí požadovaných informací mediátorovi nebo rozhodci povede k prohrání sporu. Ve všech sporných případech nese Solo odesílatel 100% odpovědnost za ověřování transakcí mediátorovi nebo rozhodci.\n\nPokud těmto požadavkům nerozumíte, neobchodujte na Bisq. Nejprve vyhledejte pomoc na stránce Solo Network Discord (https://discord.minesolo.com/). # suppress inspection "UnusedProperty" @@ -1207,13 +1234,13 @@ account.altcoin.popup.grin.msg=GRIN vyžaduje k vytvoření transakce interaktiv # suppress inspection "UnusedProperty" account.altcoin.popup.beam.msg=BEAM vyžaduje k vytvoření transakce interaktivní proces mezi odesílatelem a příjemcem.\n\nNezapomeňte postupovat podle pokynů na webové stránce projektu BEAM, abyste spolehlivě odeslali a přijali BEAM (příjemce musí být online nebo alespoň online během určitého časového období).\n\nOdesílatel BEAM je povinen prokázat, že úspěšně odeslali BEAM. Nezapomeňte použít software peněženku, která může takový důkaz předložit. Pokud peněženka nemůže poskytnout důkaz, bude potenciální spor vyřešen ve prospěch příjemce BEAM. # suppress inspection "UnusedProperty" -account.altcoin.popup.pars.msg=Trading ParsiCoin na Bisq vyžaduje, abyste pochopili a splnili následující požadavky:\n\nK odeslání PARS musíte použít oficiální ParsiCoin peněženku verze 3.0.0 nebo vyšší.\n\nV Peněženka GUI (ParsiPay) si můžete zkontrolovat svůj Hash Transakce a Klíč Transakce on Transactions v sekci Transakce.\n\nV případě, že je nutné rozhodčí řízení, musíte mediátorovi nebo rozhodci předložit: 1) Hash Transakce, 2) Transakční Klíč a 3) Adresu PARS příjemce. Mediátor nebo rozhodce poté ověří přenos PARS pomocí Block exploreru ParsiCoin (http://explorer.parsicoin.net/#check_payment).\n\nNeposkytnutí požadovaných informací mediátorovi nebo rozhodci povede k prohrání sporu. Ve všech sporných případech nese odesílatel ParsiCoin 100% odpovědnost za ověřování transakcí mediátorovi nebo rozhodci.\n\nPokud těmto požadavkům nerozumíte, neobchodujte na Bisq. Nejprve vyhledejte pomoc na ParsiCoin Discord (https://discord.gg/c7qmFNh). +account.altcoin.popup.pars.msg=Trading ParsiCoin na Bisq vyžaduje, abyste pochopili a splnili následující požadavky:\n\nK odeslání PARS musíte použít oficiální ParsiCoin peněženku verze 3.0.0 nebo vyšší.\n\nV Peněženka GUI (ParsiPay) si můžete zkontrolovat svůj Hash Transakce a Klíč Transakce v sekci Transakce.\n\nV případě, že je nutné rozhodčí řízení, musíte mediátorovi nebo rozhodci předložit: 1) Hash Transakce, 2) Transakční Klíč a 3) Adresu PARS příjemce. Mediátor nebo rozhodce poté ověří přenos PARS pomocí Block exploreru ParsiCoin (http://explorer.parsicoin.net/#check_payment).\n\nNeposkytnutí požadovaných informací mediátorovi nebo rozhodci povede k prohrání sporu. Ve všech sporných případech nese odesílatel ParsiCoin 100% odpovědnost za ověřování transakcí mediátorovi nebo rozhodci.\n\nPokud těmto požadavkům nerozumíte, neobchodujte na Bisq. Nejprve vyhledejte pomoc na ParsiCoin Discord (https://discord.gg/c7qmFNh). # suppress inspection "UnusedProperty" account.altcoin.popup.blk-burnt.msg=Chcete-li obchodovat s burnt blackcoiny, musíte znát následující:\n\nBurnt blackcoiny jsou nevyčerpatelné. Aby je bylo možné obchodovat na Bisq, musí mít výstupní skripty podobu: OP_RETURN OP_PUSHDATA, následované přidruženými datovými bajty, které po hexadecimálním zakódování tvoří adresy. Například Burnt blackcoiny s adresou 666f6f („foo“ v UTF-8) budou mít následující skript:\n\nOP_RETURN OP_PUSHDATA 666f6f\n\nPro vytvoření Burnt blackcoinů lze použít příkaz „burn“ RPC, který je k dispozici v některých peněženkách.\n\nPro možné případy použití se můžete podívat na https://ibo.laboratorium.ee.\n\nVzhledem k tomu, že Burnt blackcoiny jsou nevyčerpatelné, nelze je znovu prodat. „Prodej“ Burnt blackcoinů znamená vypalování běžných blackcoinů (s přidruženými údaji rovnými cílové adrese).\n\nV případě sporu musí prodejce BLK poskytnout hash transakce. # suppress inspection "UnusedProperty" -account.altcoin.popup.liquidbitcoin.msg=Obchodování s L-BTC na Bisq vyžaduje, abyste pochopili následující skutečnosti:\n\nKdyž přijímáte L-BTC za obchod na Bisq, nemůžete použít mobilní peněženku Green od Blockstreamu ani jinou custidial peněženku nebo peněženku na burze. L-BTC musíte přijmout pouze do peněženky Liquid Elements Core nebo do jiné L-BTC peněženky, která vám umožní získat slepý klíč pro vaši slepou adresu L-BTC.\n\nV případě, že je nutné zprostředkování, nebo pokud dojde k obchodnímu sporu, musíte zprostředkujícímu mediátorovi Bisq nebo agentovi, který vrací peníze zaslat slepý klíč pro vaši L-BTC adresu, aby mohli ověřit podrobnosti vaší důvěrné transakce na svém vlastním Elements Core full-nodu.\n\nNeposkytnutí požadovaných informací zprostředkovateli nebo agentovi pro vrácení peněz povede ke prohrání sporu. Ve všech sporných případech nese příjemce L-BTC 100% břemeno odpovědnosti za poskytnutí kryptografického důkazu zprostředkovateli nebo agentovi pro vrácení peněz.\n\nPokud těmto požadavkům nerozumíte, neobchodujte s L-BTC na Bisq. +account.altcoin.popup.liquidbitcoin.msg=Obchodování s L-BTC na Bisq vyžaduje, abyste pochopili následující skutečnosti:\n\nKdyž přijímáte L-BTC za obchod na Bisq, nemůžete použít mobilní peněženku Green od Blockstreamu ani jinou custodial peněženku nebo peněženku na burze. L-BTC musíte přijmout pouze do peněženky Liquid Elements Core nebo do jiné L-BTC peněženky, která vám umožní získat slepý klíč pro vaši slepou adresu L-BTC.\n\nV případě, že je nutné zprostředkování, nebo pokud dojde k obchodnímu sporu, musíte zprostředkujícímu mediátorovi Bisq nebo agentovi, který vrací peníze zaslat slepý klíč pro vaši L-BTC adresu, aby mohli ověřit podrobnosti vaší důvěrné transakce na svém vlastním Elements Core full-nodu.\n\nNeposkytnutí požadovaných informací zprostředkovateli nebo agentovi pro vrácení peněz povede ke prohrání sporu. Ve všech sporných případech nese příjemce L-BTC 100% břemeno odpovědnosti za poskytnutí kryptografického důkazu zprostředkovateli nebo agentovi pro vrácení peněz.\n\nPokud těmto požadavkům nerozumíte, neobchodujte s L-BTC na Bisq. account.fiat.yourFiatAccounts=Vaše účty v národní měně @@ -1289,14 +1316,14 @@ account.notifications.marketAlert.addButton=Přidat upozornění na nabídku account.notifications.marketAlert.manageAlertsButton=Spravovat upozornění na nabídku account.notifications.marketAlert.manageAlerts.title=Spravovat upozornění na nabídku account.notifications.marketAlert.manageAlerts.header.paymentAccount=Platební účet -account.notifications.marketAlert.manageAlerts.header.trigger=Spouštěcí cena +account.notifications.marketAlert.manageAlerts.header.trigger=Limitní cena account.notifications.marketAlert.manageAlerts.header.offerType=Typ nabídky account.notifications.marketAlert.message.title=Upozornění na nabídku account.notifications.marketAlert.message.msg.below=pod account.notifications.marketAlert.message.msg.above=nad account.notifications.marketAlert.message.msg=Do nabídky Bisq byla zveřejněna nová nabídka ''{0} {1}'' s cenou {2} ({3} {4} tržní cena) a způsob platby ''{5}''.\nID nabídky: {6}. account.notifications.priceAlert.message.title=Upozornění na cenu pro {0} -account.notifications.priceAlert.message.msg=Vaše upozornění na cenu bylo spuštěno. Aktuální {0} cena je {1} {2} +account.notifications.priceAlert.message.msg=Vaše upozornění na cenu bylo aktivováno. Aktuální {0} cena je {1} {2} account.notifications.noWebCamFound.warning=Nebyla nalezena žádná webkamera.\n\nPoužijte e-mailu k odeslání tokenu a šifrovacího klíče z vašeho mobilního telefonu do aplikace Bisq. account.notifications.priceAlert.warning.highPriceTooLow=Vyšší cena musí být větší než nižší cena. account.notifications.priceAlert.warning.lowerPriceTooHigh=Nižší cena musí být nižší než vyšší cena. @@ -1312,11 +1339,11 @@ dao.tab.factsAndFigures=Fakta & Čísla dao.tab.bsqWallet=Peněženka BSQ dao.tab.proposals=Vláda dao.tab.bonding=Upisování -dao.tab.proofOfBurn=Poplatek za výpis majetku/Důkaz o spálení +dao.tab.proofOfBurn=Poplatek za vedení aktiva/Důkaz spálení dao.tab.monitor=Sledování sítě dao.tab.news=Novinky -dao.paidWithBsq=zaplaceno BSQ +dao.paidWithBsq=zaplacen BSQ dao.availableBsqBalance=K dispozici pro výdaje (ověřené + nepotvrzené drobné výstupy) dao.verifiedBsqBalance=Zůstatek všech ověřených UTXO dao.unconfirmedChangeBalance=Zůstatek všech nepotvrzených drobných výstupů @@ -1324,11 +1351,11 @@ dao.unverifiedBsqBalance=Zůstatek všech neověřených transakcí (čeká se n dao.lockedForVoteBalance=Použito pro hlasování dao.lockedInBonds=Uzamčeno v úpisech dao.availableNonBsqBalance=Dostupný zůstatek mimo BSQ (BTC) -dao.reputationBalance=Hodnota Meritů - (nedá se utratit) +dao.reputationBalance=Body zásluhy (nedají se utratit) dao.tx.published.success=Vaše transakce byla úspěšně zveřejněna. -dao.proposal.menuItem.make=Navrhněte -dao.proposal.menuItem.browse=Procházet otevřené návrhy +dao.proposal.menuItem.make=Podat návrh +dao.proposal.menuItem.browse=Otevřené návrhy dao.proposal.menuItem.vote=Hlasování o návrzích dao.proposal.menuItem.result=Výsledky hlasování dao.cycle.headline=Hlasovací cyklus @@ -1343,14 +1370,14 @@ dao.cycle.voteResult=Výsledek hlasování dao.cycle.phaseDuration={0} bloky (≈{1}); Bloky {2} - {3} (≈{4} - ≈{5}) dao.cycle.phaseDurationWithoutBlocks=Blok {0} - {1} (≈{2} - ≈{3}) -dao.voteReveal.txPublished.headLine=Odhalené hlasování o transakci zveřejněno -dao.voteReveal.txPublished=Vaše odhalené hlasování o transakci s ID transakce {0} bylo úspěšně zveřejněn.\n\nTo se stane automaticky pomocí softwaru, pokud jste se zúčastnili hlasování DAO. +dao.voteReveal.txPublished.headLine=Transakce odhalující hlasování zveřejněna +dao.voteReveal.txPublished=Vaše transakce odhalující hlasování s ID transakce {0} byla úspěšně zveřejněna.\n\nToto se provádí automaticky, pokud jste se zúčastnili hlasování DAO. dao.results.cycles.header=Cykly dao.results.cycles.table.header.cycle=Cyklus dao.results.cycles.table.header.numProposals=Návrhy dao.results.cycles.table.header.voteWeight=Váha hlasování -dao.results.cycles.table.header.issuance=Vydání +dao.results.cycles.table.header.issuance=Emise dao.results.results.table.item.cycle=Cyklus {0} začal: {1} @@ -1360,7 +1387,7 @@ dao.results.proposals.table.header.details=Detaily dao.results.proposals.table.header.myVote=Můj hlas dao.results.proposals.table.header.result=Výsledek hlasování dao.results.proposals.table.header.threshold=Práh -dao.results.proposals.table.header.quorum=Kvorum +dao.results.proposals.table.header.quorum=Kvórum dao.results.proposals.voting.detail.header=Výsledky hlasování pro vybraný návrh @@ -1394,9 +1421,9 @@ dao.param.PROPOSAL_FEE=Poplatek za návrh v BSQ dao.param.BLIND_VOTE_FEE=Hlasovací poplatek v BSQ # suppress inspection "UnusedProperty" -dao.param.COMPENSATION_REQUEST_MIN_AMOUNT=Žádost o odškodnění min. částka BSQ +dao.param.COMPENSATION_REQUEST_MIN_AMOUNT=Žádost o odměnu - min. částka BSQ # suppress inspection "UnusedProperty" -dao.param.COMPENSATION_REQUEST_MAX_AMOUNT=Žádost o odškodnění max. částka BSQ +dao.param.COMPENSATION_REQUEST_MAX_AMOUNT=Žádost o odměnu - max. částka BSQ # suppress inspection "UnusedProperty" dao.param.REIMBURSEMENT_MIN_AMOUNT=Žádost o vyrovnání min. částka BSQ # suppress inspection "UnusedProperty" @@ -1405,22 +1432,22 @@ dao.param.REIMBURSEMENT_MAX_AMOUNT=Žádost o vyrovnání max. částka BSQ # suppress inspection "UnusedProperty" dao.param.QUORUM_GENERIC=Požadované kvórum v BSQ pro obecný návrh # suppress inspection "UnusedProperty" -dao.param.QUORUM_COMP_REQUEST=Požadované kvórum v BSQ pro žádost o odškodnění +dao.param.QUORUM_COMP_REQUEST=Požadované kvórum v BSQ pro žádost o odměnu # suppress inspection "UnusedProperty" -dao.param.QUORUM_REIMBURSEMENT=Požadované kvorum v BSQ pro žádost o vyrovnání +dao.param.QUORUM_REIMBURSEMENT=Požadované kvórum v BSQ pro žádost o vyrovnání # suppress inspection "UnusedProperty" -dao.param.QUORUM_CHANGE_PARAM=Požadované kvorum v BSQ pro změnu parametru +dao.param.QUORUM_CHANGE_PARAM=Požadované kvórum v BSQ pro změnu parametru # suppress inspection "UnusedProperty" dao.param.QUORUM_REMOVE_ASSET=Požadované kvórum v BSQ pro odebrání aktiva # suppress inspection "UnusedProperty" dao.param.QUORUM_CONFISCATION=Požadované kvórum v BSQ pro žádost o konfiskaci # suppress inspection "UnusedProperty" -dao.param.QUORUM_ROLE=Požadované kvorum v BSQ pro žádost o upsání +dao.param.QUORUM_ROLE=Požadované kvórum v BSQ pro žádost o upsání # suppress inspection "UnusedProperty" dao.param.THRESHOLD_GENERIC=Požadovaná prahová hodnota v % pro obecný návrh # suppress inspection "UnusedProperty" -dao.param.THRESHOLD_COMP_REQUEST=Požadovaná prahová hodnota v % pro žádost o odškodnění +dao.param.THRESHOLD_COMP_REQUEST=Požadovaná prahová hodnota v % pro žádost o odměnu # suppress inspection "UnusedProperty" dao.param.THRESHOLD_REIMBURSEMENT=Požadovaná prahová hodnota v % pro žádost o vyrovnání # suppress inspection "UnusedProperty" @@ -1436,7 +1463,7 @@ dao.param.THRESHOLD_ROLE=Požadovaná prahová hodnota v % pro žádost o úpis dao.param.RECIPIENT_BTC_ADDRESS=BTC adresa příjemce # suppress inspection "UnusedProperty" -dao.param.ASSET_LISTING_FEE_PER_DAY=Poplatek za výpis aktiv za den +dao.param.ASSET_LISTING_FEE_PER_DAY=Poplatek za vedení aktiva za den # suppress inspection "UnusedProperty" dao.param.ASSET_MIN_VOLUME=Min. objem obchodu s aktivy @@ -1481,9 +1508,9 @@ dao.results.votes.table.header.stake=Vklad dao.results.votes.table.header.merit=Vyděláno dao.results.votes.table.header.vote=Hlas -dao.bond.menuItem.bondedRoles=Úpisy -dao.bond.menuItem.reputation=Úpisová reputace -dao.bond.menuItem.bonds=Úpisy +dao.bond.menuItem.bondedRoles=Role s úpisy +dao.bond.menuItem.reputation=Vaše úpisy +dao.bond.menuItem.bonds=Všechny úpisy dao.bond.dashboard.bondsHeadline=Upsané BSQ dao.bond.dashboard.lockupAmount=Zamknout prostředky @@ -1504,8 +1531,8 @@ dao.bond.reputation.unlock.details=Odemknout částku: {0}\nČas odemknutí: {1} dao.bond.allBonds.header=Všechny úpisy -dao.bond.bondedReputation=Úpisová reputace -dao.bond.bondedRoles=Úpisy +dao.bond.bondedReputation=Úpis reputace +dao.bond.bondedRoles=Role s úpisy dao.bond.details.header=Podrobnosti role dao.bond.details.role=Role @@ -1519,7 +1546,7 @@ dao.bond.table.column.name=Jméno dao.bond.table.column.link=Odkaz dao.bond.table.column.bondType=Typ úpisu dao.bond.table.column.details=Detaily -dao.bond.table.column.lockupTxId=Zamknout Tx ID +dao.bond.table.column.lockupTxId=Tx ID úpisu dao.bond.table.column.bondState=Stav úpisu dao.bond.table.column.lockTime=Čas odemknutí dao.bond.table.column.lockupDate=Datum uzamčení @@ -1543,7 +1570,7 @@ dao.bond.bondState.UNLOCK_TX_CONFIRMED=Odemknutí tx potvrzeno # suppress inspection "UnusedProperty" dao.bond.bondState.UNLOCKING=Odblokování úpisů # suppress inspection "UnusedProperty" -dao.bond.bondState.UNLOCKED=Úpis odemčen +dao.bond.bondState.UNLOCKED=Odemčený úpis # suppress inspection "UnusedProperty" dao.bond.bondState.CONFISCATED=Úpis konfiskován @@ -1552,7 +1579,7 @@ dao.bond.lockupReason.UNDEFINED=Nedefinováno # suppress inspection "UnusedProperty" dao.bond.lockupReason.BONDED_ROLE=Úpis # suppress inspection "UnusedProperty" -dao.bond.lockupReason.REPUTATION=Úpisová reputace +dao.bond.lockupReason.REPUTATION=Úpis reputace # suppress inspection "UnusedProperty" dao.bond.bondedRoleType.UNDEFINED=Nedefinováno @@ -1575,7 +1602,7 @@ dao.bond.bondedRoleType.NETLAYER_MAINTAINER=Netlayer správce # suppress inspection "UnusedProperty" dao.bond.bondedRoleType.WEBSITE_OPERATOR=Správce webu # suppress inspection "UnusedProperty" -dao.bond.bondedRoleType.FORUM_OPERATOR=Operator fóra +dao.bond.bondedRoleType.FORUM_OPERATOR=Operátor fóra # suppress inspection "UnusedProperty" dao.bond.bondedRoleType.SEED_NODE_OPERATOR=Operátor seed nodu # suppress inspection "UnusedProperty" @@ -1599,10 +1626,10 @@ dao.bond.bondedRoleType.ARBITRATOR=Rozhodce # suppress inspection "UnusedProperty" dao.bond.bondedRoleType.BTC_DONATION_ADDRESS_OWNER=Majitel dárcovské adresy BTC -dao.burnBsq.assetFee=Výpis aktiv -dao.burnBsq.menuItem.assetFee=Poplatek za výpis aktiv -dao.burnBsq.menuItem.proofOfBurn=Důkaz spálením -dao.burnBsq.header=Poplatek za výpis aktiv +dao.burnBsq.assetFee=Vedení aktiva +dao.burnBsq.menuItem.assetFee=Poplatek za vedení aktiva +dao.burnBsq.menuItem.proofOfBurn=Důkaz spálení +dao.burnBsq.header=Poplatek za vedení aktiva dao.burnBsq.selectAsset=Vybrat aktivum dao.burnBsq.fee=Poplatek dao.burnBsq.trialPeriod=Zkušební doba @@ -1628,18 +1655,18 @@ dao.assetState.DE_LISTED=Odstranění ze seznamu kvůli nečinnosti # suppress inspection "UnusedProperty" dao.assetState.REMOVED_BY_VOTING=Odebráno hlasováním -dao.proofOfBurn.header=Důkaz spálením +dao.proofOfBurn.header=Důkaz spálení dao.proofOfBurn.amount=Množství -dao.proofOfBurn.preImage=Předobraz +dao.proofOfBurn.preImage=Předloha dao.proofOfBurn.burn=Spálit -dao.proofOfBurn.allTxs=Všechny důkazy o spálení transakcí -dao.proofOfBurn.myItems=Můj důkaz o spálení transakcí +dao.proofOfBurn.allTxs=Všechny transakce dokazující spálení +dao.proofOfBurn.myItems=Moje důkazy spálení dao.proofOfBurn.date=Datum dao.proofOfBurn.hash=Hash dao.proofOfBurn.txs=Transakce dao.proofOfBurn.pubKey=Pubkey -dao.proofOfBurn.signature.window.title=Podepište zprávu klíčem z důkazu o spálení transakce -dao.proofOfBurn.verify.window.title=Ověřte zprávu pomocí klíče z důkazu o spálení transakce +dao.proofOfBurn.signature.window.title=Podepište zprávu klíčem z transakce dokazující spálení +dao.proofOfBurn.verify.window.title=Ověřte zprávu pomocí klíče z transakce dokazující spálení dao.proofOfBurn.copySig=Zkopírujte podpis do schránky dao.proofOfBurn.sign=Podepsat dao.proofOfBurn.message=Zpráva @@ -1668,20 +1695,20 @@ dao.phase.RESULT=Hlasujte ve výsledné fázi # suppress inspection "UnusedProperty" dao.phase.separatedPhaseBar.PROPOSAL=Fáze návrhu # suppress inspection "UnusedProperty" -dao.phase.separatedPhaseBar.BLIND_VOTE=Slepý hlas +dao.phase.separatedPhaseBar.BLIND_VOTE=Slepé hlasování # suppress inspection "UnusedProperty" -dao.phase.separatedPhaseBar.VOTE_REVEAL=Odhalit hlasování +dao.phase.separatedPhaseBar.VOTE_REVEAL=Odhalení hlasování # suppress inspection "UnusedProperty" dao.phase.separatedPhaseBar.RESULT=Výsledek hlasování # suppress inspection "UnusedProperty" dao.proposal.type.UNDEFINED=Nedefinováno # suppress inspection "UnusedProperty" -dao.proposal.type.COMPENSATION_REQUEST=Žádost o odškodnění +dao.proposal.type.COMPENSATION_REQUEST=Žádost o odměnu # suppress inspection "UnusedProperty" dao.proposal.type.REIMBURSEMENT_REQUEST=Žádost o vyrovnání # suppress inspection "UnusedProperty" -dao.proposal.type.BONDED_ROLE=Źádost o úpis +dao.proposal.type.BONDED_ROLE=Žádost o úpis # suppress inspection "UnusedProperty" dao.proposal.type.REMOVE_ASSET=Návrh na odstranění aktiva # suppress inspection "UnusedProperty" @@ -1689,12 +1716,12 @@ dao.proposal.type.CHANGE_PARAM=Návrh na změnu parametru # suppress inspection "UnusedProperty" dao.proposal.type.GENERIC=Obecný návrh # suppress inspection "UnusedProperty" -dao.proposal.type.CONFISCATE_BOND=Źádost o konfiskaci úpisu +dao.proposal.type.CONFISCATE_BOND=Žádost o konfiskaci úpisu # suppress inspection "UnusedProperty" dao.proposal.type.short.UNDEFINED=Nedefinováno # suppress inspection "UnusedProperty" -dao.proposal.type.short.COMPENSATION_REQUEST=Žádost o odškodnění +dao.proposal.type.short.COMPENSATION_REQUEST=Žádost o odměnu # suppress inspection "UnusedProperty" dao.proposal.type.short.REIMBURSEMENT_REQUEST=Žádost o vyrovnání # suppress inspection "UnusedProperty" @@ -1763,7 +1790,7 @@ dao.proposal.myVote.invalid=Hlasování bylo neplatné dao.proposal.voteResult.success=Přijato dao.proposal.voteResult.failed=Odmítnuto -dao.proposal.voteResult.summary=Výsledek: {0}; Prahová hodnota: {1} (požadováno > {2}); Kvórum: {3} (povinné > {4}) +dao.proposal.voteResult.summary=Výsledek: {0}; Prahová hodnota: {1} (požadováno > {2}); Kvórum: {3} (požadováno > {4}) dao.proposal.display.paramComboBox.label=Vyberte parametr, který chcete změnit dao.proposal.display.paramValue=Hodnota parametru @@ -1777,7 +1804,7 @@ dao.blindVote.startPublishing=Publikování transakce se slepým hlasováním .. dao.blindVote.success=Vaše transakce se slepým hlasováním byla úspěšně zveřejněna.\n\nVezměte prosím na vědomí, že musíte být online ve fázi odhalení hlasování, aby vaše aplikace Bisq mohla zveřejnit transakci odhalení hlasování. Bez transakce odhalení hlasování by byl váš hlas neplatný! dao.wallet.menuItem.send=Odeslat -dao.wallet.menuItem.receive=Přijat +dao.wallet.menuItem.receive=Přijmout dao.wallet.menuItem.transactions=Transakce dao.wallet.dashboard.myBalance=Můj zůstatek v peněžence @@ -1796,7 +1823,7 @@ dao.wallet.send.setDestinationAddress=Vyplňte svou cílovou adresu dao.wallet.send.send=Pošlete BSQ prostředky dao.wallet.send.sendBtc=Pošlete BTC prostředky dao.wallet.send.sendFunds.headline=Potvrďte žádost o výběr -dao.wallet.send.sendFunds.details=Odesílání: {0}\nNa přijímací adresu: {1}.\nPožadovaný transakční poplatek je: {2} ({3} satoshi/vbyte)\nTransakční vsize: {4} vKb\n\nPříjemce obdrží: {5}\n\nOpravdu chcete tuto částku vybrat? +dao.wallet.send.sendFunds.details=Odesílání: {0}\nNa adresu pro příjem: {1}.\nPožadovaný poplatek za těžbu je: {2} ({3} satoshi/vbyte)\nVelikost transakce: {4} vKb\n\nPříjemce obdrží: {5}\n\nOpravdu chcete tuto částku vybrat? dao.wallet.chainHeightSynced=Poslední ověřený blok: {0} dao.wallet.chainHeightSyncing=Čekání na bloky... Ověřeno {0} bloků z {1} dao.wallet.tx.type=Typ @@ -1820,7 +1847,7 @@ dao.tx.type.enum.sent.TRANSFER_BSQ=Odeslané BSQ # suppress inspection "UnusedProperty" dao.tx.type.enum.PAY_TRADE_FEE=Obchodní poplatek # suppress inspection "UnusedProperty" -dao.tx.type.enum.COMPENSATION_REQUEST=Poplatek za žádost o odškodnění +dao.tx.type.enum.COMPENSATION_REQUEST=Poplatek za žádost o odměnu # suppress inspection "UnusedProperty" dao.tx.type.enum.REIMBURSEMENT_REQUEST=Poplatek za žádost o vyrovnání # suppress inspection "UnusedProperty" @@ -1828,23 +1855,23 @@ dao.tx.type.enum.PROPOSAL=Poplatek za návrh # suppress inspection "UnusedProperty" dao.tx.type.enum.BLIND_VOTE=Poplatek za slepé hlasování # suppress inspection "UnusedProperty" -dao.tx.type.enum.VOTE_REVEAL=Odhalit hlasování +dao.tx.type.enum.VOTE_REVEAL=Odhalení hlasování # suppress inspection "UnusedProperty" dao.tx.type.enum.LOCKUP=Zamknout úpis # suppress inspection "UnusedProperty" dao.tx.type.enum.UNLOCK=Odemknout úpis # suppress inspection "UnusedProperty" -dao.tx.type.enum.ASSET_LISTING_FEE=Poplatek za výpis majetku +dao.tx.type.enum.ASSET_LISTING_FEE=Poplatek za vedení aktiva # suppress inspection "UnusedProperty" -dao.tx.type.enum.PROOF_OF_BURN=Důkaz spálením +dao.tx.type.enum.PROOF_OF_BURN=Důkaz spálení # suppress inspection "UnusedProperty" dao.tx.type.enum.IRREGULAR=Nepravidelný dao.tx.withdrawnFromWallet=BTC vybrané z peněženky -dao.tx.issuanceFromCompReq=Žádost o odškodnění/vydání -dao.tx.issuanceFromCompReq.tooltip=Žádost o kompenzaci, která vedla k vydání nového BSQ.\nDatum vydání: {0} -dao.tx.issuanceFromReimbursement=Žádost o vyrovnání/vydání -dao.tx.issuanceFromReimbursement.tooltip=Žádost o kompenzaci, která vedla k vydání nového BSQ.\nDatum vydání: {0} +dao.tx.issuanceFromCompReq=Vydání odměny +dao.tx.issuanceFromCompReq.tooltip=Žádost o odměnu, která vedla k vydání nového BSQ.\nDatum vydání: {0} +dao.tx.issuanceFromReimbursement=Vydání vyrovnání +dao.tx.issuanceFromReimbursement.tooltip=Žádost o vyrovnání, která vedla k vydání nového BSQ.\nDatum vydání: {0} dao.proposal.create.missingBsqFunds=Pro vytvoření návrhu nemáte dostatečné prostředky BSQ. Pokud máte nepotvrzenou transakci BSQ, musíte počkat na potvrzení na blockchainu, protože BSQ je validováno, pouze pokud je zahrnuto v bloku.\nChybí: {0} dao.proposal.create.missingBsqFundsForBond=Pro tuto roli nemáte dostatečné prostředky BSQ. Tento návrh můžete stále zveřejnit, ale pokud bude přijat, budete potřebovat celou částku BSQ potřebnou pro tuto roli.\nChybí: {0} @@ -1864,7 +1891,7 @@ dao.news.bisqDAO.readMoreLink=Dozvědět se více o Bisq DAO dao.news.pastContribution.title=PŘISPĚLI JSTE V MINULOSTI? POŽÁDEJTE O BSQ dao.news.pastContribution.description=Pokud jste přispěli do projektu Bisq, použijte prosím níže uvedenou adresu BSQ a požádejte o účast na distribuci prvních BSQ. -dao.news.pastContribution.yourAddress=Adresa vaší bsq peněženky +dao.news.pastContribution.yourAddress=Adresa vaší BSQ peněženky dao.news.pastContribution.requestNow=Požádat hned dao.news.DAOOnTestnet.title=SPUSŤTE BISQ DAO NA NAŠEM TESTNETU @@ -1884,7 +1911,7 @@ dao.monitor.proposals=Stav návrhů dao.monitor.blindVotes=Stav slepých hlasů dao.monitor.table.peers=Peer uzly -dao.monitor.table.conflicts=Konflikt +dao.monitor.table.conflicts=Konflikty dao.monitor.state=Stav dao.monitor.requestAlHashes=Vyžádat si všechny hashe dao.monitor.resync=Znovu synchronizovat stav DAO @@ -1906,7 +1933,7 @@ dao.monitor.daoState.checkpoint.popup=Stav DAO není synchronizován se sítí. dao.monitor.proposal.headline=Stav návrhů dao.monitor.proposal.table.headline=Řetězec hashů stavu návrhu -dao.monitor.proposal.conflictTable.headline=Návrhované stavy hashů od partnerů v konfliktu +dao.monitor.proposal.conflictTable.headline=Navrhované stavy hashů od partnerů v konfliktu dao.monitor.proposal.table.hash=Hash stavu návrhu dao.monitor.proposal.table.prev=Předchozí hash @@ -1928,21 +1955,21 @@ dao.factsAndFigures.menuItem.transactions=Transakce BSQ dao.factsAndFigures.dashboard.avgPrice90=Průměrná obchodní cena BSQ/BTC za 90 dní dao.factsAndFigures.dashboard.avgPrice30=Průměrná obchodní cena BSQ/BTC za 30 dní -dao.factsAndFigures.dashboard.avgUSDPrice90=90-denní objem váženého průměru obchodní ceny USD/BSQ -dao.factsAndFigures.dashboard.avgUSDPrice30=30-denní objem váženého průměru obchodní ceny USD/BSQ -dao.factsAndFigures.dashboard.marketCap=Tržní kapitalizace (na základě obchodní ceny) +dao.factsAndFigures.dashboard.avgUSDPrice90=90denní objemově vážená průměrná cena USD/BSQ +dao.factsAndFigures.dashboard.avgUSDPrice30=30denní objemově vážená průměrná cena USD/BSQ +dao.factsAndFigures.dashboard.marketCap=Tržní kapitalizace (na základě průměrné ceny USD/BSQ za posledních 30 dní) dao.factsAndFigures.dashboard.availableAmount=Celkem k dispozici BSQ -dao.factsAndFigures.supply.issuedVsBurnt=Vydaných BSQ v. Spálených BSQ +dao.factsAndFigures.supply.issuedVsBurnt=Vydaných BSQ vs. Spálených BSQ dao.factsAndFigures.supply.issued=Vydáno BSQ dao.factsAndFigures.supply.genesisIssueAmount=BSQ vydané při první (genesis) transakci -dao.factsAndFigures.supply.compRequestIssueAmount=BSQ vydáno pro žádosti o odškodnění -dao.factsAndFigures.supply.reimbursementAmount=BSQ vydané pro žádosti o vyrovnání +dao.factsAndFigures.supply.compRequestIssueAmount=BSQ vydáno na žádosti o odměnu +dao.factsAndFigures.supply.reimbursementAmount=BSQ vydáno na žádosti o vyrovnání dao.factsAndFigures.supply.burnt=Spálených BSQ -dao.factsAndFigures.supply.burntMovingAverage=15-denní klouzavý průměr -dao.factsAndFigures.supply.burntZoomToInliers=Přiblížit k vnitřnímu +dao.factsAndFigures.supply.burntMovingAverage=15denní klouzavý průměr +dao.factsAndFigures.supply.burntZoomToInliers=Přiblížit klouzavý průměr dao.factsAndFigures.supply.locked=Globální stav uzamčených BSQ dao.factsAndFigures.supply.totalLockedUpAmount=Zamčeno v úpisech @@ -1958,8 +1985,8 @@ dao.factsAndFigures.transactions.genesisTxId=ID genesis transakce dao.factsAndFigures.transactions.txDetails=Statistiky transakcí BSQ dao.factsAndFigures.transactions.allTx=Počet všech transakcí BSQ dao.factsAndFigures.transactions.utxo=Počet všech nevyčerpaných transakčních výstupů -dao.factsAndFigures.transactions.compensationIssuanceTx=Počet všech transakcí s žádostí o odškodnění -dao.factsAndFigures.transactions.reimbursementIssuanceTx=Počet všech transakcí k vydání žádosti o vyrovnání +dao.factsAndFigures.transactions.compensationIssuanceTx=Počet všech transakcí s vydáním odměn +dao.factsAndFigures.transactions.reimbursementIssuanceTx=Počet všech transakcí s vydáním vyrovnání dao.factsAndFigures.transactions.burntTx=Počet všech poplatků platebních transakcí dao.factsAndFigures.transactions.invalidTx=Počet všech neplatných transakcí dao.factsAndFigures.transactions.irregularTx=Počet všech nepravidelných transakcí @@ -2000,11 +2027,11 @@ disputeSummaryWindow.openDate=Datum otevření úkolu disputeSummaryWindow.role=Role obchodníka disputeSummaryWindow.payout=Výplata částky obchodu disputeSummaryWindow.payout.getsTradeAmount=BTC {0} dostane výplatu částky obchodu -disputeSummaryWindow.payout.getsAll=BTC {0} získá vše +disputeSummaryWindow.payout.getsAll=BTC {0} dostane maximální výplatu disputeSummaryWindow.payout.custom=Vlastní výplata disputeSummaryWindow.payoutAmount.buyer=Výše výplaty kupujícího disputeSummaryWindow.payoutAmount.seller=Výše výplaty prodejce -disputeSummaryWindow.payoutAmount.invert=Pužít prohraného jako vydavatele +disputeSummaryWindow.payoutAmount.invert=Poražený ve sporu odesílá transakci disputeSummaryWindow.reason=Důvod sporu # dynamic values are not recognized by IntelliJ @@ -2017,13 +2044,13 @@ disputeSummaryWindow.reason.PROTOCOL_VIOLATION=Porušení protokolu # suppress inspection "UnusedProperty" disputeSummaryWindow.reason.NO_REPLY=Bez odpovědi # suppress inspection "UnusedProperty" -disputeSummaryWindow.reason.SCAM=Scam +disputeSummaryWindow.reason.SCAM=Podvod # suppress inspection "UnusedProperty" disputeSummaryWindow.reason.OTHER=Jiný # suppress inspection "UnusedProperty" disputeSummaryWindow.reason.BANK_PROBLEMS=Banka # suppress inspection "UnusedProperty" -disputeSummaryWindow.reason.OPTION_TRADE=Možnost obchodu +disputeSummaryWindow.reason.OPTION_TRADE=Obchodování opcí # suppress inspection "UnusedProperty" disputeSummaryWindow.reason.SELLER_NOT_RESPONDING=Prodejce neodpovídá # suppress inspection "UnusedProperty" @@ -2045,7 +2072,7 @@ disputeSummaryWindow.close.msg=Ticket uzavřen {0}\n{1} adresa uzlu: {2}\n\nSouh disputeSummaryWindow.close.msgWithSig={0}{1}{2}{3} disputeSummaryWindow.close.nextStepsForMediation=\nDalší kroky:\nOtevřete obchod a přijměte nebo odmítněte návrhy od mediátora -disputeSummaryWindow.close.nextStepsForRefundAgentArbitration=\nDalší kroky:\nNevyžadují se od vás žádné další kroky. Pokud rozhodce rozhodl ve váš prospěch, zobrazí se ve Prostředky/Transakce transakce „Vrácení peněz z rozhodčího řízení“ +disputeSummaryWindow.close.nextStepsForRefundAgentArbitration=\nDalší kroky:\nNevyžadují se od vás žádné další kroky. Pokud rozhodce rozhodl ve váš prospěch, v sekci Prostředky/Transakce se zobrazí transakce „Vrácení peněz z rozhodčího řízení“ disputeSummaryWindow.close.closePeer=Potřebujete také zavřít úkol obchodního peer uzlu! disputeSummaryWindow.close.txDetails.headline=Zveřejněte transakci vrácení peněz # suppress inspection "TrailingSpacesInProperty" @@ -2080,7 +2107,7 @@ filterWindow.bannedAccountWitnessSignerPubKeys=Filtrované veřejné klíče ú filterWindow.bannedPrivilegedDevPubKeys=Filtrované privilegované klíče pub dev (hex nebo pub klíče oddělené čárkou) filterWindow.arbitrators=Filtrovaní rozhodci (onion adresy oddělené čárkami) filterWindow.mediators=Filtrovaní mediátoři (onion adresy oddělené čárkami) -filterWindow.refundAgents=Filtrovaní zástupci pro vrácení peněz (adresy oddělené čárkami) +filterWindow.refundAgents=Filtrovaní rozhodci pro vrácení peněz (onion adresy oddělené čárkami) filterWindow.seedNode=Filtrované seed nody (onion adresy oddělené čárkami) filterWindow.priceRelayNode=Filtrované cenové relay nody (onion adresy oddělené čárkami) filterWindow.btcNode=Filtrované Bitcoinové nody (adresy+porty oddělené čárkami) @@ -2154,6 +2181,7 @@ tradeDetailsWindow.tradingPeersOnion=Onion adresa obchodního peer uzlu tradeDetailsWindow.tradingPeersPubKeyHash=Pubkey hash obchodních partnerů tradeDetailsWindow.tradeState=Stav obchodu tradeDetailsWindow.agentAddresses=Rozhodce/Mediátor +tradeDetailsWindow.detailData=Detailní data walletPasswordWindow.headline=Pro odemknutí zadejte heslo @@ -2166,7 +2194,7 @@ torNetworkSettingWindow.obfs3=obfs3 torNetworkSettingWindow.obfs4=obfs4 (doporučeno) torNetworkSettingWindow.meekAmazon=meek-amazon torNetworkSettingWindow.meekAzure=meek-azure -torNetworkSettingWindow.enterBridge=Zadejte jedno nebo více mostových relé - bridge relays (jedno na řádek) +torNetworkSettingWindow.enterBridge=Zadejte jeden nebo více bridge relays (jeden na řádek) torNetworkSettingWindow.enterBridgePrompt=typ addresa:port torNetworkSettingWindow.restartInfo=Chcete-li použít změny, musíte restartovat aplikaci torNetworkSettingWindow.openTorWebPage=Otevřít webovou stránku projektu Tor @@ -2183,6 +2211,8 @@ feeOptionWindow.info=Můžete si vybrat, zda chcete zaplatit obchodní poplatek feeOptionWindow.optionsLabel=Vyberte měnu pro platbu obchodního poplatku feeOptionWindow.useBTC=Použít BTC feeOptionWindow.fee={0} (≈ {1}) +feeOptionWindow.btcFeeWithFiatAndPercentage={0} (≈ {1} / {2}) +feeOptionWindow.btcFeeWithPercentage={0} ({1}) #################################################################### @@ -2200,7 +2230,7 @@ popup.headline.warning=Varování popup.headline.error=Chyba popup.doNotShowAgain=Znovu nezobrazovat -popup.reportError.log=Otevřete log soubor +popup.reportError.log=Otevřít log popup.reportError.gitHub=Nahlaste problém na GitHub popup.reportError={0}\n\nChcete-li nám pomoci vylepšit software, nahlaste tuto chybu otevřením nového problému na adrese https://github.com/bisq-network/bisq/issues.\nVýše uvedená chybová zpráva bude zkopírována do schránky po kliknutí na některé z níže uvedených tlačítek.\nUsnadníte ladění, pokud zahrnete soubor bisq.log stisknutím tlačítka „Otevřít log soubor“, uložením kopie a připojením ke zprávě o chybě. @@ -2226,13 +2256,14 @@ popup.warning.noMediatorsAvailable=Nejsou k dispozici žádní mediátoři. popup.warning.notFullyConnected=Musíte počkat, až budete plně připojeni k síti.\nTo může při spuštění trvat až 2 minuty. popup.warning.notSufficientConnectionsToBtcNetwork=Musíte počkat, až budete mít alespoň {0} připojení k bitcoinové síti. popup.warning.downloadNotComplete=Musíte počkat, až bude stahování chybějících bitcoinových bloků kompletní. +popup.warning.chainNotSynced=Výška blockchainu peněženky Bisq není správně synchronizována. Pokud jste aplikaci spustili nedávno, počkejte, dokud nebude zveřejněn jeden blok bitcoinů.\n\nVýšku blockchainu můžete zkontrolovat v Nastavení/Informace o síti. Pokud projde více než jeden blok a tento problém přetrvává, asi být zastaven, v takovém případě byste měli provést SPV resynchonizaci. [HYPERLINK:https://bisq.wiki/Resyncing_SPV_file] popup.warning.removeOffer=Opravdu chcete tuto nabídku odebrat?\nPokud tuto nabídku odstraníte, ztratí se poplatek tvůrce {0}. popup.warning.tooLargePercentageValue=Nelze nastavit procento 100% nebo větší. popup.warning.examplePercentageValue=Zadejte procento jako číslo \"5.4\" pro 5.4% popup.warning.noPriceFeedAvailable=Pro tuto měnu není k dispozici žádný zdroj cen. Nelze použít procentuální cenu.\nVyberte pevnou cenu. -popup.warning.sendMsgFailed=Odeslání zprávy vašemu obchodnímu partnerovi se nezdařilo.\nZkuste to prosím znovu a pokud to i nadále selže, nahláste chybu. +popup.warning.sendMsgFailed=Odeslání zprávy vašemu obchodnímu partnerovi se nezdařilo.\nZkuste to prosím znovu a pokud to i nadále selže, nahlaste chybu. popup.warning.insufficientBtcFundsForBsqTx=Nemáte dostatečné prostředky BTC k zaplacení poplatku za těžbu za tuto transakci.\nFinancujte prosím svou BTC peněženku.\nChybějící prostředky: {0} -popup.warning.bsqChangeBelowDustException=Tato transakce vytváří výstup BSQ, který je pod limitem drobných (5,46 BSQ) a byl by bitcoinovou sítí odmítnut.\n\nMusíte buď poslat vyšší částku, abyste se vyhnuli drobným (např. Přidáním drobné částky do vaší odeslané částky), nebo přidejte do své peněženky další prostředky BSQ, abyste se vyhnuli generování drobných.\n\nVýstup drobných {0}. +popup.warning.bsqChangeBelowDustException=Tato transakce vytváří výstup BSQ, který je pod limitem drobných (5,46 BSQ) a byl by bitcoinovou sítí odmítnut.\n\nMusíte buď poslat vyšší částku, abyste se vyhnuli drobným (např. přidáním drobné částky do vaší odeslané částky), nebo přidejte do své peněženky další prostředky BSQ, abyste se vyhnuli generování drobných.\n\nVýstup drobných {0}. popup.warning.btcChangeBelowDustException=Tato transakce vytváří výstup, který je pod limitem drobných (546 satoshi) a byl by bitcoinovou sítí odmítnut.\n\nMusíte přidat vyšší množství drobných k vašemu odesílanému množství, abyste se vyhnuli vytváření drobných.\n\nVýstup drobných je {0}. popup.warning.insufficientBsqFundsForBtcFeePayment=K provedení této transakce budete potřebovat více BSQ - posledních 5,46 BSQ ve vaší peněžence nelze použít k placení obchodních poplatků kvůli omezení prachových mincí v bitcoinovém protokolu.\n\nMůžete si buď koupit více BSQ, nebo zaplatit obchodní poplatky pomocí BTC.\n\nChybějící prostředky: {0} @@ -2254,7 +2285,7 @@ popup.warning.openOffer.makerFeeTxRejected=Transakční poplatek tvůrce za nab popup.warning.trade.txRejected.tradeFee=obchodní poplatek popup.warning.trade.txRejected.deposit=vklad -popup.warning.trade.txRejected={0} transakce pro obchod s ID {1} byla bitcoinovou sítí odmítnuta.\nID transakce = {2}}\nObchod byl přesunut do neúspěšných obchodů.\nPřejděte do \"Nastavení/Informace o síti\" a proveďte synchronizaci SPV.\nPro další pomoc prosím kontaktujte podpůrný kanál v Bisq Keybase týmu. +popup.warning.trade.txRejected=Bitcoinová síť odmítla {0} transakci pro obchod s ID {1}.\nID transakce = {2}\nObchod byl přesunut do neúspěšných obchodů.\nPřejděte do části \"Nastavení/Informace o síti\" a proveďte synchronizaci SPV.\nPro další pomoc prosím kontaktujte podpůrný kanál v Bisq Keybase týmu. popup.warning.openOfferWithInvalidMakerFeeTx=Transakční poplatek tvůrce za nabídku s ID {0} je neplatný.\nID transakce = {1}.\nPřejděte do \"Nastavení/Informace o síti\" a proveďte synchronizaci SPV.\nPro další pomoc prosím kontaktujte podpůrný kanál v Bisq Keybase týmu. @@ -2264,14 +2295,15 @@ popup.info.cashDepositInfo=Ujistěte se, že ve své oblasti máte pobočku bank popup.info.cashDepositInfo.confirm=Potvrzuji, že mohu provést vklad popup.info.shutDownWithOpenOffers=Bisq se vypíná, ale existují otevřené nabídky.\n\nTyto nabídky nebudou dostupné v síti P2P, pokud bude Bisq vypnutý, ale budou znovu publikovány do sítě P2P při příštím spuštění Bisq.\n\nChcete-li zachovat své nabídky online, udržujte Bisq spuštěný a ujistěte se, že tento počítač zůstává online (tj. Ujistěte se, že nepřejde do pohotovostního režimu...pohotovostní režim monitoru není problém). popup.info.qubesOSSetupInfo=Zdá se, že používáte Bisq na Qubes OS.\n\nUjistěte se, že je vaše Bisq qube nastaveno podle našeho průvodce nastavením na [HYPERLINK:https://bisq.wiki/Running_Bisq_on_Qubes]. +popup.warn.downGradePrevention=Downgrade z verze {0} na verzi {1} není podporován. Použijte prosím nejnovější verzi Bisq. +popup.warn.daoRequiresRestart=Došlo k problému při synchronizaci stavu DAO. Pro nápravu prosím restartujte aplikaci. popup.privateNotification.headline=Důležité soukromé oznámení! popup.securityRecommendation.headline=Důležité bezpečnostní doporučení popup.securityRecommendation.msg=Chtěli bychom vám připomenout, abyste zvážili použití ochrany heslem pro vaši peněženku, pokud jste ji již neaktivovali.\n\nDůrazně se také doporučuje zapsat seed slova peněženky. Tato seed slova jsou jako hlavní heslo pro obnovení vaší bitcoinové peněženky.\nV sekci "Seed peněženky" naleznete další informace.\n\nDále byste měli zálohovat úplnou složku dat aplikace v sekci \"Záloha\". -popup.bitcoinLocalhostNode.msg=Bisq detekoval lokálně spuštěný Bitcoin Core node (na localhostu).\nPřed spuštěním Bisq se ujistěte, že tento node je plně synchronizován a že není spuštěn v pruned mode režimu. -popup.bitcoinLocalhostNode.additionalRequirements=\n\nPožadavky pro dobře nakonfigurovaný uzel jsou, aby bylo zakázáno prořezávání (pruning) a aby byly povoleny bloom filtry. +popup.bitcoinLocalhostNode.msg=Bisq detekoval Bitcoin Core node běžící na tomto systému (na localhostu).\n\nProsím ujistěte se, že:\n- tento node je plně synchronizován před spuštěním Bisq\n- prořezávání je vypnuto ('prune=0' v bitcoin.conf)\n- Bloomovy filtry jsou zapnuty ('peerbloomfilters=1' v bitcoin.conf) popup.shutDownInProgress.headline=Probíhá vypínání popup.shutDownInProgress.msg=Vypnutí aplikace může trvat několik sekund.\nProsím, nepřerušujte tento proces. @@ -2303,15 +2335,12 @@ popup.accountSigning.signedByPeer=Jeden z vašich platebních účtů byl ověř popup.accountSigning.peerLimitLifted=Počáteční limit pro jeden z vašich účtů byl zrušen.\n\n{0} popup.accountSigning.peerSigner=Jeden z vašich účtů je dostatečně zralý, aby podepsal další platební účty, a počáteční limit pro jeden z vašich účtů byl zrušen.\n\n{0} -popup.accountSigning.singleAccountSelect.headline=Vyberte svědka stáří účtu -popup.accountSigning.singleAccountSelect.description=Vyhledejte svědka stáří účtu. -popup.accountSigning.singleAccountSelect.datePicker=Vyberte čas pro podpis +popup.accountSigning.singleAccountSelect.headline=Importujte svědka stáří účtu k podepsání popup.accountSigning.confirmSingleAccount.headline=Potvrďte vybrané svědky o stáří účtu popup.accountSigning.confirmSingleAccount.selectedHash=Hash vybraného svědka popup.accountSigning.confirmSingleAccount.button=Podepsat svědka stáří účtu popup.accountSigning.successSingleAccount.description=Svědek {0} byl podepsán popup.accountSigning.successSingleAccount.success.headline=Úspěch -popup.accountSigning.successSingleAccount.signError=Nepodařilo se podepsat svědka, {0} popup.accountSigning.unsignedPubKeys.headline=Nepodepsané Pubkeys popup.accountSigning.unsignedPubKeys.sign=Podepsat Pubkeys @@ -2360,15 +2389,15 @@ guiUtil.accountExport.savedToPath=Obchodní účty uložené na:\n{0} guiUtil.accountExport.noAccountSetup=Nemáte nastaveny obchodní účty pro export. guiUtil.accountExport.selectPath=Vyberte cestu k {0} # suppress inspection "TrailingSpacesInProperty" -guiUtil.accountExport.tradingAccount=Obchodní účet s ID {0} +guiUtil.accountExport.tradingAccount=Obchodní účet s ID {0}\n # suppress inspection "TrailingSpacesInProperty" guiUtil.accountImport.noImport=Neobchodovali jsme obchodní účet s ID {0}, protože již existuje.\n guiUtil.accountExport.exportFailed=Export do CSV selhal kvůli chybě.\nChyba = {0} guiUtil.accountExport.selectExportPath=Vyberte složku pro export guiUtil.accountImport.imported=Obchodní účet importovaný z:\n{0}\n\nImportované účty:\n{1} guiUtil.accountImport.noAccountsFound=Nebyly nalezeny žádné exportované obchodní účty na: {0}.\nNázev souboru je {1}." -guiUtil.openWebBrowser.warning=Chystáte se otevřít webovou stránku ve webovém prohlížeči.\nChcete nyní otevřít webovou stránku?\n\nPokud nepoužíváte \"Tor Browser\" jako výchozí systémový webový prohlížeč, připojíte se k webové stránce v čisté síti.\n\nURL: \"{0}\" -guiUtil.openWebBrowser.doOpen=Otevřete webovou stránku a znovu se neptát +guiUtil.openWebBrowser.warning=Chystáte se otevřít webovou stránku ve webovém prohlížeči.\nChcete nyní otevřít webovou stránku?\n\nPokud nepoužíváte \"Tor Browser\" jako výchozí systémový webový prohlížeč, připojíte se k webové stránce přes nechráněné spojení.\n\nURL: \"{0}\" +guiUtil.openWebBrowser.doOpen=Otevřít webovou stránku a znovu se neptat guiUtil.openWebBrowser.copyUrl=Zkopírovat URL a zrušit guiUtil.ofTradeAmount=obchodní částky guiUtil.requiredMinimum=(požadované minimum) @@ -2438,7 +2467,7 @@ navigation.settings.preferences=\"Nastavení/Preference\" # suppress inspection "UnusedProperty" navigation.funds.transactions=\"Prostředky/Transakce\" navigation.support=\"Podpora\" -navigation.dao.wallet.receive=\"DAO/BSQ peněženka/Přímout\" +navigation.dao.wallet.receive="DAO/Peněženka BSQ/Přijmout" #################################################################### @@ -2447,11 +2476,11 @@ navigation.dao.wallet.receive=\"DAO/BSQ peněženka/Přímout\" formatter.formatVolumeLabel={0} částka{1} formatter.makerTaker=Tvůrce jako {0} {1} / Příjemce jako {2} {3} -formatter.youAreAsMaker=Jste {0} {1} jako tvůrce / Příjemce je {2} {3} -formatter.youAreAsTaker=Jste {0} {1} jako příjemce / Tvůrce je {2} {3} -formatter.youAre=Jste {0} {1} ({2} {3}) -formatter.youAreCreatingAnOffer.fiat=Vytváříte nabídku pro {0} {1} -formatter.youAreCreatingAnOffer.altcoin=Vytváříte nabídku pro {0} {1} ({2} {3}) +formatter.youAreAsMaker=Jste {1} {0} (jako tvůrce) / Příjemce je {3} {2} +formatter.youAreAsTaker=Jste {1} {0} (jako příjemce) / Tvůrce je {3} {2} +formatter.youAre={0}te {1} ({2}te {3}) +formatter.youAreCreatingAnOffer.fiat=Vytváříte nabídku: {0} {1} +formatter.youAreCreatingAnOffer.altcoin=Vytváříte nabídku: {0} {1} ({2}te {3}) formatter.asMaker={0} {1} jako tvůrce formatter.asTaker={0} {1} jako příjemce @@ -2494,7 +2523,7 @@ time.seconds=sekundy password.enterPassword=Vložte heslo password.confirmPassword=Potvrďte heslo password.tooLong=Heslo musí mít méně než 500 znaků. -password.deriveKey=Odvozte klíč z hesla +password.deriveKey=Odvozuji klíč z hesla password.walletDecrypted=Peněženka úspěšně dešifrována a ochrana heslem byla odstraněna. password.wrongPw=Zadali jste nesprávné heslo.\n\nZkuste prosím zadat heslo znovu a pečlivě zkontrolujte překlepy nebo pravopisné chyby. password.walletEncrypted=Peněženka úspěšně šifrována a ochrana heslem povolena. @@ -2510,7 +2539,7 @@ seed.date=Datum peněženky seed.restore.title=Obnovit peněženky z seed slov seed.restore=Obnovit peněženky seed.creationDate=Datum vzniku -seed.warn.walletNotEmpty.msg=Vaše bitcoinová peněženka není prázdná.\n\nTuto peněženku musíte vyprázdnit, než se pokusíte obnovit starší, protože smíchání peněženek může vést ke zneplatnění záloh.\n\nDokončete své obchody, uzavřete všechny otevřené nabídky a přejděte do sekce Prostředky, kde si můžete vybrat své bitcoiny.\nV případě, že nemáte přístup ke svým bitcoinům, můžete použít nouzový nástroj k vyprázdnění peněženky.\nNouzový nástroj otevřete stisknutím kombinace kláves \"Alt+e\" or \"Cmd/Ctrl+e\". +seed.warn.walletNotEmpty.msg=Vaše bitcoinová peněženka není prázdná.\n\nTuto peněženku musíte vyprázdnit, než se pokusíte obnovit starší, protože smíchání peněženek může vést ke zneplatnění záloh.\n\nDokončete své obchody, uzavřete všechny otevřené nabídky a přejděte do sekce Prostředky, kde si můžete vybrat své bitcoiny.\nV případě, že nemáte přístup ke svým bitcoinům, můžete použít nouzový nástroj k vyprázdnění peněženky.\nNouzový nástroj otevřete stisknutím kombinace kláves \"Alt+e\" nebo \"Cmd/Ctrl+e\". seed.warn.walletNotEmpty.restore=Chci přesto obnovit seed.warn.walletNotEmpty.emptyWallet=Nejprve vyprázdním své peněženky seed.warn.notEncryptedAnymore=Vaše peněženky jsou šifrovány.\n\nPo obnovení již nebudou peněženky šifrovány a musíte nastavit nové heslo.\n\nChcete pokračovat? @@ -2561,6 +2590,7 @@ payment.venmo.venmoUserName=Uživatelské jméno Venmo payment.popmoney.accountId=E-mail nebo číslo telefonu payment.promptPay.promptPayId=Občanské/daňové identifikační číslo nebo telefonní číslo payment.supportedCurrencies=Podporované měny +payment.supportedCurrenciesForReceiver=Měny pro příjem prostředků payment.limitations=Omezení payment.salt=Salt pro ověření stáří účtu payment.error.noHexSalt=Salt musí být ve formátu HEX.\nDoporučujeme upravit pole salt, pokud chcete salt převést ze starého účtu, aby bylo stáří vašeho účtu zachováno. Stáří účtu se ověřuje pomocí salt účtu a identifikačních údajů účtu (např. IBAN). @@ -2597,7 +2627,7 @@ payment.accountType=Typ účtu payment.checking=Kontrola payment.savings=Úspory payment.personalId=Číslo občanského průkazu -payment.clearXchange.info=Zelle je služba převodu peněz, která funguje nejlépe *prostřednictvím* jiné banky.\n\n1. Na této stránce zjistěte, zda (a jak) vaše banka spolupracuje se Zelle:\n[HYPERLINK:https://www.zellepay.com/get-started]\n\n2. Zaznamenejte si zvláštní limity převodů - limity odesílání se liší podle banky a banky často určují samostatné denní, týdenní a měsíční limity.\n\n3. Pokud vaše banka s Zelle nepracuje, můžete ji stále používat prostřednictvím mobilní aplikace Zelle, ale vaše limity převodu budou mnohem nižší.\n\n4. Název uvedený na vašem účtu Bisq MUSÍ odpovídat názvu vašeho účtu Zelle/bankovního účtu.\n\nPokud nemůžete dokončit transakci Zelle, jak je uvedeno ve vaší obchodní smlouvě, můžete ztratit část (nebo všechn) ze svého bezpečnostního vkladu.\n\nVzhledem k poněkud vyššímu riziku zpětného zúčtování společnosti Zelle se prodejcům doporučuje kontaktovat nepodepsané kupující prostřednictvím e-mailu nebo SMS, aby ověřili, že kupující skutečně vlastní účet Zelle uvedený v Bisq. +payment.clearXchange.info=Zelle je služba převodu peněz, která funguje nejlépe *prostřednictvím* jiné banky.\n\n1. Na této stránce zjistěte, zda (a jak) vaše banka spolupracuje se Zelle:\n[HYPERLINK:https://www.zellepay.com/get-started]\n\n2. Zaznamenejte si zvláštní limity převodů - limity odesílání se liší podle banky a banky často určují samostatné denní, týdenní a měsíční limity.\n\n3. Pokud vaše banka s Zelle nepracuje, můžete ji stále používat prostřednictvím mobilní aplikace Zelle, ale vaše limity převodu budou mnohem nižší.\n\n4. Název uvedený na vašem účtu Bisq MUSÍ odpovídat názvu vašeho účtu Zelle/bankovního účtu.\n\nPokud nemůžete dokončit transakci Zelle, jak je uvedeno ve vaší obchodní smlouvě, můžete ztratit část (nebo vše) ze svého bezpečnostního vkladu.\n\nVzhledem k poněkud vyššímu riziku zpětného zúčtování společnosti Zelle se prodejcům doporučuje kontaktovat nepodepsané kupující prostřednictvím e-mailu nebo SMS, aby ověřili, že kupující skutečně vlastní účet Zelle uvedený v Bisq. payment.fasterPayments.newRequirements.info=Některé banky začaly ověřovat celé jméno příjemce pro převody Faster Payments. Váš současný účet Faster Payments nepožadoval celé jméno.\n\nZvažte prosím znovu vytvoření svého Faster Payments účtu v Bisqu, abyste mohli budoucím kupujícím {0} poskytnout celé jméno.\n\nPři opětovném vytvoření účtu nezapomeňte zkopírovat přesný kód řazení, číslo účtu a hodnoty soli (salt) pro ověření věku ze starého účtu do nového účtu. Tím zajistíte zachování stáří a stavu vašeho stávajícího účtu. payment.moneyGram.info=Při používání MoneyGram musí BTC kupující zaslat autorizační číslo a fotografii potvrzení e-mailem prodejci BTC. Potvrzení musí jasně uvádět celé jméno prodejce, zemi, stát a částku. E-mail prodávajícího se kupujícímu zobrazí během procesu obchodování. payment.westernUnion.info=Při používání služby Western Union musí kupující BTC zaslat prodejci BTC e-mailem MTCN (sledovací číslo) a fotografii potvrzení. Potvrzení musí jasně uvádět celé jméno prodejce, město, zemi a částku. E-mail prodávajícího se kupujícímu zobrazí během procesu obchodování. @@ -2635,7 +2665,8 @@ payment.japan.recipient=Jméno payment.australia.payid=PayID payment.payid=PayID spojené s finanční institucí. Jako e-mailová adresa nebo mobilní telefon. payment.payid.info=PayID jako telefonní číslo, e-mailová adresa nebo australské obchodní číslo (ABN), které můžete bezpečně propojit se svou bankou, družstevní záložnou nebo účtem stavební spořitelny. Musíte mít již vytvořený PayID u své australské finanční instituce. Odesílající i přijímající finanční instituce musí podporovat PayID. Další informace najdete na [HYPERLINK:https://payid.com.au/faqs/] -payment.amazonGiftCard.info=Chcete-li platit kartou Amazon eGift, musíte si na svém účtu Amazon zakoupit kartu Amazon eGift a použít e-mail nebo mobilní číslo prodejce BTC. jako příjemce. Amazon poté odešle příjemci e-mail nebo textovou zprávu. Pro pole zprávy použijte ID obchodu.\n\nKarty Amazon eGift lze uplatnit pouze na účtech Amazon se stejnou měnou.\n\nDalší informace najdete na webové stránce Amazon eGift Card. [HYPERLINK:https://www.amazon.com/Amazon-1_US_Email-eGift-Card/dp/B004LLIKVU] +payment.amazonGiftCard.info=Chcete-li platit dárkovou kartou Amazon eGift, budete muset prodejci BTC poslat kartu Amazon eGift přes svůj účet Amazon.\n\nBisq zobrazí e-mail nebo mobilní číslo prodejce BTC, kam bude potřeba odeslat tuto dárkovou kartu. Na kartě ve zprávě pro příjemce musí být uvedeno ID obchodu. Pro další detaily a rady viz wiki: [HYPERLINK:https://bisq.wiki/Amazon_eGift_card].\n\nZde jsou tři důležité poznámky:\n- Preferujte dárkové karty v hodnotě do 100 USD, protože Amazon může považovat nákupy karet s vyššími částkami jako podezřelé a zablokovat je.\n- Na kartě do zprávy pro příjemce můžete přidat i vlastní originální text (např. "Happy birthday Susan!") spolu s ID obchodu. (V takovém případě o tom informujte protistranu pomocí obchodovacího chatu, aby mohli s jistotou ověřit, že obdržená dárková karta pochází od vás.)\n- Karty Amazon eGift lze uplatnit pouze na té stránce Amazon, na které byly také koupeny (např. karta koupená na amazon.it může být uplatněna zase jen na amazon.it). + # We use constants from the code so we do not use our normal naming convention # dynamic values are not recognized by IntelliJ @@ -2840,7 +2871,7 @@ validation.interacETransfer.invalidAnswer=Musí to být jedno slovo a obsahovat validation.inputTooLarge=Vstup nesmí být větší než {0} validation.inputTooSmall=Vstup musí být větší než {0} validation.inputToBeAtLeast=Vstup musí být alespoň {0} -validation.amountBelowDust=Množství pod mezní hodnotou prachových mincí {0} satoshi není povoleno. +validation.amountBelowDust=Množství pod mezní hodnotou drobných (dust limit) {0} není povoleno. validation.length=Délka musí být mezi {0} a {1} validation.pattern=Vstup musí být ve formátu: {0} validation.noHexString=Vstup není ve formátu HEX. diff --git a/core/src/main/resources/i18n/displayStrings_de.properties b/core/src/main/resources/i18n/displayStrings_de.properties index 1dc96b9a6f..eb8095ba29 100644 --- a/core/src/main/resources/i18n/displayStrings_de.properties +++ b/core/src/main/resources/i18n/displayStrings_de.properties @@ -71,6 +71,7 @@ shared.amountWithCur=Betrag in {0} shared.volumeWithCur=Volumen in {0} shared.currency=Währung shared.market=Markt +shared.deviation=Abweichung shared.paymentMethod=Zahlungsmethode shared.tradeCurrency=Handelswährung shared.offerType=Angebotstyp @@ -104,7 +105,6 @@ shared.selectTradingAccount=Handelskonto auswählen shared.fundFromSavingsWalletButton=Gelder aus Bisq-Wallet überweisen shared.fundFromExternalWalletButton=Ihre externe Wallet zum Finanzieren öffnen shared.openDefaultWalletFailed=Öffnen einer Bitcoin Wallet Applikation fehlgeschlagen. Bist du sicher, dass du eine installiert hast? -shared.distanceInPercent=Abstand vom Marktpreis in % shared.belowInPercent=% unter dem Marktpreis shared.aboveInPercent=% über dem Marktpreis shared.enterPercentageValue=%-Wert eingeben @@ -191,7 +191,7 @@ shared.tradeWalletBalance=Guthaben der Handels-Wallet shared.makerTxFee=Ersteller: {0} shared.takerTxFee=Abnehmer: {0} shared.iConfirm=Ich bestätige -shared.tradingFeeInBsqInfo=gleichwertig mit {0} als Trading-Gebühr +shared.tradingFeeInBsqInfo=≈ {0} shared.openURL=Öffne {0} shared.fiat=Fiat shared.crypto=Crypto @@ -218,6 +218,9 @@ shared.refundAgentForSupportStaff=Rückerstattungsbeauftragten shared.delayedPayoutTxId=Verzögerte Auszahlungs-ID der Transaktion shared.delayedPayoutTxReceiverAddress=Verzögerte Auszahlungs-Transaktion gesendet zu shared.unconfirmedTransactionsLimitReached=Sie haben im Moment zu viele unbestätigte Transaktionen. Bitte versuchen Sie es später noch einmal. +shared.numItemsLabel=Number of entries: {0} +shared.filter=Filter +shared.enabled=Aktiviert #################################################################### @@ -248,14 +251,14 @@ mainView.balance.locked=In Trades gesperrt mainView.balance.reserved.short=Reserviert mainView.balance.locked.short=Gesperrt -mainView.footer.usingTor=(nutzt Tor) +mainView.footer.usingTor=(über Tor) mainView.footer.localhostBitcoinNode=(localhost) -mainView.footer.btcInfo={0} {1} {2} +mainView.footer.btcInfo={0} {1} mainView.footer.btcFeeRate=/ Aktuelle Gebühr: {0} sat/vB mainView.footer.btcInfo.initializing=Verbindung mit Bitcoin-Netzwerk wird hergestellt mainView.footer.bsqInfo.synchronizing=/ Synchronisiere DAO -mainView.footer.btcInfo.synchronizingWith=Synchronisiere mit -mainView.footer.btcInfo.synchronizedWith=Synchronisiert mit +mainView.footer.btcInfo.synchronizingWith=Synchronisierung mit {0} bei Block: {1} / {2} +mainView.footer.btcInfo.synchronizedWith=Synchronisierung mit {0} bei Block {1} mainView.footer.btcInfo.connectingTo=Verbinde mit mainView.footer.btcInfo.connectionFailed=Verbindung fehlgeschlagen zu mainView.footer.p2pInfo=Bitcoin Netzwerk Peers: {0} / Bisq Netzwerk Peers: {1} @@ -336,10 +339,10 @@ offerbook.offerersAcceptedBankSeats=Als Banksitz akzeptierte Länder (Abnehmer): offerbook.availableOffers=Verfügbare Angebote offerbook.filterByCurrency=Nach Währung filtern offerbook.filterByPaymentMethod=Nach Zahlungsmethode filtern -offerbook.timeSinceSigning=Unterzeichnet seit +offerbook.timeSinceSigning=Konto Informationen offerbook.timeSinceSigning.info=Dieses Konto wurde verifiziert und {0} offerbook.timeSinceSigning.info.arbitrator=von einem Vermittler unterzeichnet und kann Partner-Konten unterzeichnen -offerbook.timeSinceSigning.info.peer=von einem Partner unterzeichnet, der darauf wartet, dass die Limits aufgehoben werden +offerbook.timeSinceSigning.info.peer=von einem Peer unterzeichnet, der %d Tage wartet bis die Limits aufgehoben werden offerbook.timeSinceSigning.info.peerLimitLifted=von einem Partner unterzeichnet und Limits wurden aufgehoben offerbook.timeSinceSigning.info.signer=vom Partner unterzeichnet und kann Partner-Konten unterzeichnen (Limits aufgehoben) offerbook.timeSinceSigning.info.banned=Konto wurde geblockt @@ -349,9 +352,12 @@ offerbook.xmrAutoConf=Automatische Bestätigung aktiviert offerbook.timeSinceSigning.help=Wenn Sie einen Trade mit einem Partner erfolgreich abschließen, der ein unterzeichnetes Zahlungskonto hat, wird Ihr Zahlungskonto unterzeichnet.\n{0} Tage später wird das anfängliche Limit von {1} aufgehoben und Ihr Konto kann die Zahlungskonten anderer Partner unterzeichnen. offerbook.timeSinceSigning.notSigned=Noch nicht unterzeichnet +offerbook.timeSinceSigning.notSigned.ageDays={0} Tage offerbook.timeSinceSigning.notSigned.noNeed=N/A -shared.notSigned=DIeses Konto wurde noch nicht unterzeichnet -shared.notSigned.noNeed=Dieser Kontotyp verwendet keine Unterzeichnung +shared.notSigned=Dieses Konto wurde noch nicht unterzeichnet und wurde {0} Tage zuvor erstellt +shared.notSigned.noNeed=Dieser Kontotyp benötigt keine Unterzeichnung +shared.notSigned.noNeedDays=Dieser Kontotyp benötigt keine Unterzeichnung und wurde {0} zuvor unterzeichnet +shared.notSigned.noNeedAlts=Altcoin Konten benötigen weisen keine Unterzeichnung und kein Konto-Alter auf. offerbook.nrOffers=Anzahl der Angebote: {0} offerbook.volume={0} (min - max) @@ -435,11 +441,15 @@ createOffer.warning.sellBelowMarketPrice=Sie erhalten immer {0}% weniger als der createOffer.warning.buyAboveMarketPrice=Sie zahlen immer {0}% mehr als der aktuelle Marktpreis, da ihr Angebot ständig aktualisiert wird. createOffer.tradeFee.descriptionBTCOnly=Handelsgebühr createOffer.tradeFee.descriptionBSQEnabled=Gebührenwährung festlegen -createOffer.tradeFee.fiatAndPercent=≈ {0} / {1} vom Handelsbetrag + +createOffer.triggerPrice.prompt=Set optional trigger price +createOffer.triggerPrice.label=Deactivate offer if market price is {0} +createOffer.triggerPrice.tooltip=As protecting against drastic price movements you can set a trigger price which deactivates the offer if the market price reaches that value. +createOffer.triggerPrice.invalid.tooLow=Value must be higher than {0} +createOffer.triggerPrice.invalid.tooHigh=Value must be lower than {0} # new entries createOffer.placeOfferButton=Überprüfung: Anbieten Bitcoins zu {0} -createOffer.alreadyFunded=Sie hatten das Angebot bereits finanziert.\nIhre Gelder wurden in Ihre lokale Bisq-Wallet verschoben und können unter \"Gelder/Gelder senden\" abgehoben werden. createOffer.createOfferFundWalletInfo.headline=Ihr Angebot finanzieren # suppress inspection "TrailingSpacesInProperty" createOffer.createOfferFundWalletInfo.tradeAmount=- Handelsbetrag: {0} \n @@ -496,7 +506,6 @@ takeOffer.error.message=Bei der Angebotsannahme trat ein Fehler auf.\n\n{0} # new entries takeOffer.takeOfferButton=Überprüfung: Angebot annehmen Bitcoins zu {0} takeOffer.noPriceFeedAvailable=Sie können dieses Angebot nicht annehmen, da es auf einem Prozentsatz vom Marktpreis basiert, jedoch keiner verfügbar ist. -takeOffer.alreadyFunded.movedFunds=Sie haben das Angebot bereits finanziert.\nIhre Gelder wurden in Ihre lokale Bisq-Wallet verschoben und können unter \"Gelder/Gelder senden\" abgehoben werden. takeOffer.takeOfferFundWalletInfo.headline=Ihren Handel finanzieren # suppress inspection "TrailingSpacesInProperty" takeOffer.takeOfferFundWalletInfo.tradeAmount=- Handelsbetrag: {0}\n @@ -524,6 +533,10 @@ takeOffer.tac=Mit der Annahme dieses Angebots stimme ich den oben festgelegten H # Offerbook / Edit offer #################################################################### +openOffer.header.triggerPrice=Triggerpreis +openOffer.triggerPrice=Trigger price {0} +openOffer.triggered=The offer has been deactivated because the market price reached your trigger price.\nPlease edit the offer to define a new trigger price + editOffer.setPrice=Preis festlegen editOffer.confirmEdit=Bestätigen: Angebot bearbeiten editOffer.publishOffer=Ihr Angebot wird veröffentlicht. @@ -541,6 +554,8 @@ portfolio.tab.history=Verlauf portfolio.tab.failed=Fehlgeschlagen portfolio.tab.editOpenOffer=Angebot bearbeiten +portfolio.closedTrades.deviation.help=Prozentuale Preisabweichung vom Markt + portfolio.pending.invalidDelayedPayoutTx=Es gibt ein Problem mit einer fehlenden oder ungültigen Transaktion.\n\nBitte senden Sie KEINE Fiat oder Altcoin Zahlung. Kontaktieren Sie Bisq Entwickler auf Keybase [HYPERLINK:https://keybase.io/team/bisq] oder im Forum [HYPERLINK:https://bisq.community] for further assistance.\n\nFehlermeldung: {0} portfolio.pending.step1.waitForConf=Auf Blockchain-Bestätigung warten @@ -886,13 +901,12 @@ funds.tx.noTxAvailable=Keine Transaktionen verfügbar funds.tx.revert=Umkehren funds.tx.txSent=Transaktion erfolgreich zu einer neuen Adresse in der lokalen Bisq-Wallet gesendet. funds.tx.direction.self=An Sie selbst senden -funds.tx.daoTxFee=Mining-Gebühr für DAO Tx +funds.tx.daoTxFee=Mining-Gebühr für BSQ-Tx funds.tx.reimbursementRequestTxFee=Rückerstattungsantrag funds.tx.compensationRequestTxFee=Entlohnungsanfrage funds.tx.dustAttackTx=Staub erhalten funds.tx.dustAttackTx.popup=Diese Transaktion sendet einen sehr kleinen BTC Betrag an Ihre Wallet und kann von Chainanalyse Unternehmen genutzt werden um ihre Wallet zu spionieren.\n\nWenn Sie den Transaktionsausgabe in einer Ausgabe nutzen, wird es lernen, dass Sie wahrscheinlich auch Besitzer der anderen Adressen sind (coin merge),\n\nUm Ihre Privatsphäre zu schützen, wir die Bisqwallet Staubausgaben für Ausgaben und bei der Anzeige der Guthabens ignorieren. Sie können den Grenzwert, ab wann ein Wert als Staub angesehen wird in den Einstellungen ändern. - #################################################################### # Support #################################################################### @@ -943,6 +957,7 @@ support.error=Empfänger konnte die Nachricht nicht verarbeiten. Fehler: {0} support.buyerAddress=BTC-Adresse des Käufers support.sellerAddress=BTC-Adresse des Verkäufers support.role=Rolle +support.agent=Support agent support.state=Status support.closed=Geschlossen support.open=Offen @@ -1052,6 +1067,7 @@ settings.net.creationDateColumn=Eingerichtet settings.net.connectionTypeColumn=Ein/Aus settings.net.sentDataLabel=Daten-Statistiken senden settings.net.receivedDataLabel=Daten-Statistiken empfangen +settings.net.chainHeightLabel=Letzte BTC Blockzeit settings.net.roundTripTimeColumn=Umlaufzeit settings.net.sentBytesColumn=Gesendet settings.net.receivedBytesColumn=Erhalten @@ -1066,6 +1082,7 @@ settings.net.needRestart=Sie müssen die Anwendung neustarten, um die Änderunge settings.net.notKnownYet=Noch nicht bekannt... settings.net.sentData=Gesendete Daten: {0}, {1} Nachrichten, {2} Nachrichten/Sekunde settings.net.receivedData=Empfangene Daten: {0}, {1} Nachrichten, {2} Nachrichten/Sekunde +settings.net.chainHeight=Bisq: {0} | Peers: {1} settings.net.ips=[IP Adresse:Port | Hostname:Port | Onion-Adresse:Port] (Komma getrennt). Port kann weggelassen werden, wenn Standard genutzt wird (8333). settings.net.seedNode=Seed-Knoten settings.net.directPeer=Peer (direkt) @@ -1074,7 +1091,7 @@ settings.net.inbound=eingehend settings.net.outbound=ausgehend settings.net.reSyncSPVChainLabel=SPV-Kette neu synchronisieren settings.net.reSyncSPVChainButton=SPV-Datei löschen und neu synchronisieren -settings.net.reSyncSPVSuccess=Die SPV-Chain-Datei wird beim nächsten Start gelöscht. Sie müssen Ihre Anwendung jetzt neu starten.\n\nNach dem Neustart kann es eine Weile dauern, bis die Neusynchronisierung mit dem Netzwerk abgeschlossen ist, und Sie sehen erst nach Abschluss der Neusynchronisierung alle Transaktionen.\n\nAbhängig von der Anzahl der Transaktionen und dem Alter Ihrer Wallet kann die Resynchronisation bis zu einigen Stunden dauern und verbraucht 100% der CPU. Unterbrechen Sie den Prozess nicht, da Sie ihn sonst wiederholen müssen. +settings.net.reSyncSPVSuccess=Sind Sie sicher, dass Sie den SPV Resync starten möchten? Wenn Sie fortfahren, wird die SPV chain beim nächsten Start gelöscht.\n\nNach dem Restart kann der Resync des Netzwerks etwas Zeit in Anspruch nehmen und Sie werden die Transaktionen erst sehen wenn der Resync vollständig durchgeführt wurde.\n\nAbhängig von der Anzahl an Transaktionen und dem Alter Ihrer Wallet kann der Resync mehrere Stunden dauern und 100% der CPU Power beanspruchen. Unterbrechen Sie den Resync nicht, ansonsten müssen Sie ihn wiederholen. settings.net.reSyncSPVAfterRestart=Die SPV-Kettendatei wurde gelöscht. Haben Sie bitte Geduld, es kann eine Weile dauern mit dem Netzwerk neu zu synchronisieren. settings.net.reSyncSPVAfterRestartCompleted=Die erneute Synchronisation ist jetzt abgeschlossen. Bitte starten Sie die Anwendung neu. settings.net.reSyncSPVFailed=Konnte SPV-Kettendatei nicht löschen.\nFehler: {0} @@ -1161,9 +1178,19 @@ account.menu.paymentAccount=Nationale Währungskonten account.menu.altCoinsAccountView=Altcoin-Konten account.menu.password=Wallet-Passwort account.menu.seedWords=Wallet-Seed +account.menu.walletInfo=Wallet info account.menu.backup=Backup account.menu.notifications=Benachrichtigungen +account.menu.walletInfo.balance.headLine=Wallet balances +account.menu.walletInfo.balance.info=This shows the internal wallet balance including unconfirmed transactions.\nFor BTC, the internal wallet balance shown below should match the sum of the 'Available' and 'Reserved' balances shown in the top right of this window. +account.menu.walletInfo.xpub.headLine=Watch keys (xpub keys) +account.menu.walletInfo.walletSelector={0} {1} wallet +account.menu.walletInfo.path.headLine=HD keychain paths +account.menu.walletInfo.path.info=If you import seed words into another wallet (like Electrum), you'll need to define the path. This should only be done in emergency cases when you lose access to the Bisq wallet and data directory.\nKeep in mind that spending funds from a non-Bisq wallet can bungle the internal Bisq data structures associated with the wallet data, which can lead to failed trades.\n\nNEVER send BSQ from a non-Bisq wallet, as it will probably lead to an invalid BSQ transaction and losing your BSQ. + +account.menu.walletInfo.openDetails=Show raw wallet details and private keys + ## TODO should we rename the following to a gereric name? account.arbitratorRegistration.pubKey=Öffentlicher Schlüssel @@ -1796,7 +1823,7 @@ dao.wallet.send.setDestinationAddress=Tragen Sie Ihre Zieladresse ein dao.wallet.send.send=BSQ-Gelder senden dao.wallet.send.sendBtc=BTC-Gelder senden dao.wallet.send.sendFunds.headline=Abhebeanfrage bestätigen -dao.wallet.send.sendFunds.details=Sending: {0}\nTo receiving address: {1}.\nRequired transaction fee is: {2} ({3} satoshis/vbyte)\nTransaction vsize: {4} vKb\n\nThe recipient will receive: {5}\n\nAre you sure you want to withdraw that amount? +dao.wallet.send.sendFunds.details=Senden: {0}\nEmpfangsadresse: {1}.\nBenötigte Mining-Gebühr beträgt: {2} ({3} satoshis/vbyte)\nTransaktion vsize: {4} vKb\n\nDer empfänger wird erhalten: {5}\n\nSind Sie sich sicher die Menge abzuheben? dao.wallet.chainHeightSynced=Synchronisiert bis Block: {0} dao.wallet.chainHeightSyncing=Erwarte Blöcke... {0} von {1} Blöcken verifiziert dao.wallet.tx.type=Typ @@ -1854,9 +1881,9 @@ dao.proposal.create.missingMinerFeeFunds=Du hast nicht ausreichend BTC, um die V dao.proposal.create.missingIssuanceFunds=Sie haben nicht ausreichend BTC, um die Vorschlags-Transaktion zu erstellen. Jede BSQ-Transaktion benötigt eine Mining-Gebühr in BTC, Ausgabetransaktionen brauchen auch BTC für den angefragten BSQ Betrag ({0} Satoshis/BSQ).\nEs fehlen: {1} dao.feeTx.confirm=Bestätige {0} Transaktion -dao.feeTx.confirm.details={0} fee: {1}\nMining fee: {2} ({3} Satoshis/vbyte)\nTransaction vsize: {4} vKb\n\nAre you sure you want to publish the {5} transaction? +dao.feeTx.confirm.details={0} Gebühr: {1} \nMining-Gebühr: {2} ({3} Satoshis/vByte)\nTransaktionsgröße: {4} Kb\n\nSind Sie sicher, dass Sie die {5} Transaktion senden wollen? -dao.feeTx.issuanceProposal.confirm.details={0} fee: {1}\nBTC needed for BSQ issuance: {2} ({3} Satoshis/BSQ)\nMining fee: {4} ({5} Satoshis/vbyte)\nTransaction vsize: {6} vKb\n\nIf your request is approved, you will receive the amount you requested net of the 2 BSQ proposal fee.\n\nAre you sure you want to publish the {7} transaction? +dao.feeTx.issuanceProposal.confirm.details={0} Gebühr: {1}\nBenötigte BTC für die BSQ Ausgabe: {2} ({3} Satoshis/BSQ)\nMining-Gebühr: {4} ({5} Satoshis/Byte)\nTransaktionsgröße: {6} Kb\n\nFalls Ihre Anfrage angenommen wird, erhalten Sie den angefragten Betrag minus die 2 BSQ Antragsgebühr.\n\nSind Sie sicher, dass Sie die {7} Transaktion veröffentlichen wollen? dao.news.bisqDAO.title=DER BISQ DAO dao.news.bisqDAO.description=Genauso wie der Bisq Handelsplatz dezentral und resistent gegen Zensur ist, ist auch die Führung der DAO - die Bisq DAO und der BSQ Token machen es möglich. @@ -2000,7 +2027,7 @@ disputeSummaryWindow.openDate=Erstellungsdatum des Tickets disputeSummaryWindow.role=Rolle des Händlers disputeSummaryWindow.payout=Auszahlung des Handelsbetrags disputeSummaryWindow.payout.getsTradeAmount=Der BTC-{0} erhält die Auszahlung des Handelsbetrags -disputeSummaryWindow.payout.getsAll=Der BTC-{0} erhält alles +disputeSummaryWindow.payout.getsAll=Menge in BTC zu {0} disputeSummaryWindow.payout.custom=Spezifische Auszahlung disputeSummaryWindow.payoutAmount.buyer=Auszahlungsbetrag des Käufers disputeSummaryWindow.payoutAmount.seller=Auszahlungsbetrag des Verkäufers @@ -2052,7 +2079,7 @@ disputeSummaryWindow.close.txDetails.headline=Rückerstattungstransaktion veröf disputeSummaryWindow.close.txDetails.buyer=Käufer erhält {0} an Adresse: {1}\n # suppress inspection "TrailingSpacesInProperty" disputeSummaryWindow.close.txDetails.seller=Verkäufer erhält {0} an Adresse: {1}\n -disputeSummaryWindow.close.txDetails=Spending: {0}\n{1}{2}Transaction fee: {3} ({4} satoshis/vbyte)\nTransaction vsize: {5} vKb\n\nAre you sure you want to publish this transaction? +disputeSummaryWindow.close.txDetails=Ausgaben: {0}\n{1}{2}Transaktionsgebühr: {3} ({4} Satoshis/Byte)\nTransaktionsgröße: {5} Kb\n\nSind Sie sicher, dass Sie diese Transaktion veröffentlichen möchten? disputeSummaryWindow.close.noPayout.headline=Ohne Auszahlung schließen disputeSummaryWindow.close.noPayout.text=Wollen Sie schließen ohne eine Auszahlung zu tätigen? @@ -2087,7 +2114,7 @@ filterWindow.btcNode=Gefilterte Bitcoinknoten (Komma getr. Adresse + Port) filterWindow.preventPublicBtcNetwork=Nutzung des öffentlichen Bitcoin-Netzwerks verhindern filterWindow.disableDao=DAO deaktivieren filterWindow.disableAutoConf=Automatische Bestätigung deaktivieren -filterWindow.autoConfExplorers=Filtered auto-confirm explorers (comma sep. addresses) +filterWindow.autoConfExplorers=Gefilterter Explorer mit Auto-Bestätigung (Adressen mit Komma separiert) filterWindow.disableDaoBelowVersion=Min. für DAO erforderliche Version filterWindow.disableTradeBelowVersion=Min. zum Handeln erforderliche Version filterWindow.add=Filter hinzufügen @@ -2154,6 +2181,7 @@ tradeDetailsWindow.tradingPeersOnion=Onion-Adresse des Handelspartners tradeDetailsWindow.tradingPeersPubKeyHash=Trading Peers Pubkey Hash tradeDetailsWindow.tradeState=Handelsstatus tradeDetailsWindow.agentAddresses=Vermittler/Mediator +tradeDetailsWindow.detailData=Detaillierte Daten walletPasswordWindow.headline=Passwort zum Entsperren eingeben @@ -2183,6 +2211,8 @@ feeOptionWindow.info=Sie können wählen, die Gebühr in BSQ oder BTC zu zahlen. feeOptionWindow.optionsLabel=Währung für Handelsgebührzahlung auswählen feeOptionWindow.useBTC=BTC nutzen feeOptionWindow.fee={0} (≈ {1}) +feeOptionWindow.btcFeeWithFiatAndPercentage={0} (≈ {1} / {2}) +feeOptionWindow.btcFeeWithPercentage={0} ({1}) #################################################################### @@ -2226,6 +2256,7 @@ popup.warning.noMediatorsAvailable=Es sind keine Mediatoren verfügbar. popup.warning.notFullyConnected=Sie müssen warten, bis Sie vollständig mit dem Netzwerk verbunden sind.\nDas kann bis ungefähr 2 Minuten nach dem Start dauern. popup.warning.notSufficientConnectionsToBtcNetwork=Sie müssen warten, bis Sie wenigstens {0} Verbindungen zum Bitcoinnetzwerk haben. popup.warning.downloadNotComplete=Sie müssen warten bis der Download der fehlenden Bitcoinblöcke abgeschlossen ist. +popup.warning.chainNotSynced=Die Blockchain Größe der Bisq Wallet ist nicht korrekt synchronisiert. Wenn Sie kürzlich die Applikation geöffnet haben, warten Sie bitte bis ein Bitcoin Block veröffentlicht wurde.\n\nSie können die Blockchain Größe unter Einstellungen/Netzwerkinformationen finden. Wenn mehr als ein Block veröffentlicht wird und das Problem weiterhin bestehen sollte, wird es eventuell abgewürgt werden. Dann sollten Sie einen SPV Resync durchführen. [HYPERLINK:https://bisq.wiki/Resyncing_SPV_file] popup.warning.removeOffer=Sind Sie sicher, dass Sie das Angebot entfernen wollen?\nDie Erstellergebühr von {0} geht verloren, wenn Sie des Angebot entfernen. popup.warning.tooLargePercentageValue=Es kann kein Prozentsatz von 100% oder mehr verwendet werden. popup.warning.examplePercentageValue=Bitte geben sei einen Prozentsatz wie folgt ein \"5.4\" für 5.4% @@ -2254,7 +2285,7 @@ popup.warning.openOffer.makerFeeTxRejected=Die Verkäufergebühren-Transaktion f popup.warning.trade.txRejected.tradeFee=Trade-Gebühr popup.warning.trade.txRejected.deposit=Kaution -popup.warning.trade.txRejected=Die {0} Transaktion für den Trade mit der ID {1} wurde vom Bitcoin-Netzwerk abgelehnt.\nTransaktions-ID={2}}\nDer Trade wurde in gescheiterte Trades verschoben.\nBitte gehen Sie zu \"Einstellungen/Netzwerkinformationen\" und führen Sie eine SPV-Resynchronisierung durch.\nFür weitere Hilfe wenden Sie sich bitte an den Bisq-Support-Kanal des Bisq Keybase Teams. +popup.warning.trade.txRejected=Die {0} Transaktion für den Trade mit der ID {1} wurde vom Bitcoin-Netzwerk abgelehnt.\nTransaktions-ID={2}}\nDer Trade wurde in gescheiterte Trades verschoben.\nBitte gehen Sie zu \"Einstellungen/Netzwerkinformationen\" und führen Sie einen SPV Resync durch.\nFür weitere Hilfe wenden Sie sich bitte an den Bisq-Support-Kanal des Bisq Keybase Teams. popup.warning.openOfferWithInvalidMakerFeeTx=Die Verkäufergebühren-Transaktion für das Angebot mit der ID {0} ist ungültig.\nTransaktions-ID={1}.\nBitte gehen Sie zu \"Einstellungen/Netzwerkinformationen\" und führen Sie eine SPV-Resynchronisierung durch.\nFür weitere Hilfe wenden Sie sich bitte an den Bisq-Support-Kanal des Bisq Keybase Teams. @@ -2264,14 +2295,15 @@ popup.info.cashDepositInfo=Stellen Sie sicher, dass eine Bank-Filiale in Ihrer N popup.info.cashDepositInfo.confirm=Ich bestätige, dass ich die Kaution zahlen kann popup.info.shutDownWithOpenOffers=Bisq wird heruntergefahren, aber Sie haben offene Angebote verfügbar.\n\nDiese Angebote sind nach dem Herunterfahren nicht mehr verfügbar und werden erneut im P2P-Netzwerk veröffentlicht wenn Sie das nächste Mal Bisq starten.\n\nLassen Sie Bisq weiter laufen und stellen Sie sicher, dass Ihr Computer online bleibt, um Ihre Angebote verfügbar zu halten (z.B.: verhindern Sie den Standby-Modus... der Standby-Modus des Monitors stellt kein Problem dar). popup.info.qubesOSSetupInfo=Es scheint so als ob Sie Bisq auf Qubes OS laufen haben.\n\nBitte stellen Sie sicher, dass Bisq qube nach unserem Setup Guide eingerichtet wurde: [HYPERLINK:https://bisq.wiki/Running_Bisq_on_Qubes]. +popup.warn.downGradePrevention=Downgrade von Version {0} auf Version {1} wird nicht unterstützt. Bitte nutzen Sie die aktuelle Bisq Version. +popup.warn.daoRequiresRestart=There was a problem with synchronizing the DAO state. You have to restart the application to fix the issue. popup.privateNotification.headline=Wichtige private Benachrichtigung! popup.securityRecommendation.headline=Wichtige Sicherheitsempfehlung popup.securityRecommendation.msg=Wir würden Sie gerne daran erinnern, sich zu überlegen, den Passwortschutz Ihrer Wallet zu verwenden, falls Sie diesen noch nicht aktiviert haben.\n\nEs wird außerdem dringend empfohlen, dass Sie die Wallet-Seed-Wörter aufschreiben. Diese Seed-Wörter sind wie ein Master-Passwort zum Wiederherstellen ihrer Bitcoin-Wallet.\nIm \"Wallet-Seed\"-Abschnitt finden Sie weitere Informationen.\n\nZusätzlich sollten Sie ein Backup des ganzen Anwendungsdatenordners im \"Backup\"-Abschnitt erstellen. -popup.bitcoinLocalhostNode.msg=Bisq hat einen lokal laufenden Bitcoin-Core-Node entdeckt (bei localhost).\nStellen Sie bitte sicher, dass dieser Node vollständig synchronisiert ist, bevor Sie Bisq starten und dass er nicht im Pruned-Modus läuft. -popup.bitcoinLocalhostNode.additionalRequirements=\n\nFür einen gut konfigurierten Node sind die Anforderungen, dass das Pruning deaktiviert und die Bloom-Filter aktiviert sind. +popup.bitcoinLocalhostNode.msg=Bisq detected a Bitcoin Core node running on this machine (at localhost).\n\nPlease ensure:\n- the node is fully synced before starting Bisq\n- pruning is disabled ('prune=0' in bitcoin.conf)\n- bloom filters are enabled ('peerbloomfilters=1' in bitcoin.conf) popup.shutDownInProgress.headline=Anwendung wird heruntergefahren popup.shutDownInProgress.msg=Das Herunterfahren der Anwendung kann einige Sekunden dauern.\nBitte unterbrechen Sie diesen Vorgang nicht. @@ -2303,15 +2335,12 @@ popup.accountSigning.signedByPeer=Eines Ihrer Zahlungskonten wurde von einem Tra popup.accountSigning.peerLimitLifted=Das anfängliche Limit für eines Ihrer Konten wurde aufgehoben.\n\n{0} popup.accountSigning.peerSigner=Eines Ihrer Konten ist reif genug, um andere Zahlungskonten zu unterzeichnen, und das anfängliche Limit für eines Ihrer Konten wurde aufgehoben.\n\n{0} -popup.accountSigning.singleAccountSelect.headline=Zeuge für Konto-Alter auswählen -popup.accountSigning.singleAccountSelect.description=Nach Zeuge für Konto-Alter suchen. -popup.accountSigning.singleAccountSelect.datePicker=Zeitpunkt für Unterzeichnung auswählen +popup.accountSigning.singleAccountSelect.headline=Import unsigned account age witness popup.accountSigning.confirmSingleAccount.headline=Ausgewählten Zeugen für Konto-Alter bestätigen popup.accountSigning.confirmSingleAccount.selectedHash=Ausgewählter Zeugen-Hash popup.accountSigning.confirmSingleAccount.button=Zeuge für Konto-Alter unterzeichnen popup.accountSigning.successSingleAccount.description=Zeuge {0} wurde unterzeichnet popup.accountSigning.successSingleAccount.success.headline=Erfolg -popup.accountSigning.successSingleAccount.signError=Zeuge nicht unterzeichnet (fehlgeschlagen), {0} popup.accountSigning.unsignedPubKeys.headline=Nicht unterzeichnete Pubkeys popup.accountSigning.unsignedPubKeys.sign=Pubkeys unterzeichnen @@ -2447,8 +2476,8 @@ navigation.dao.wallet.receive=\"DAO/BSQ-Wallet/Erhalten\" formatter.formatVolumeLabel={0} Betrag{1} formatter.makerTaker=Ersteller als {0} {1} / Abnehmer als {2} {3} -formatter.youAreAsMaker=Sie {0} {1} als Ersteller / Abnehmer wird {3} {2} -formatter.youAreAsTaker=Sie {0} {1} als Abnehmer / Ersteller wird {3} {2} +formatter.youAreAsMaker=You are: {1} {0} (maker) / Taker is: {3} {2} +formatter.youAreAsTaker=You are: {1} {0} (taker) / Maker is: {3} {2} formatter.youAre=Sie {0} {1} ({2} {3}) formatter.youAreCreatingAnOffer.fiat=Sie erstellen ein Angebot um {1} zu {0} formatter.youAreCreatingAnOffer.altcoin=Sie erstellen ein Angebot {1} zu {0} ({3} zu {2}) @@ -2498,7 +2527,7 @@ password.deriveKey=Schlüssel aus Passwort ableiten password.walletDecrypted=Die Wallet wurde erfolgreich entschlüsselt und der Passwortschutz entfernt. password.wrongPw=Sie haben das falsche Passwort eingegeben.\n\nVersuchen Sie bitte Ihr Passwort erneut einzugeben, wobei Sie dies vorsichtig auf Tipp- und Rechtschreibfehler überprüfen sollten. password.walletEncrypted=Die Wallet wurde erfolgreich verschlüsselt und der Passwortschutz aktiviert. -password.walletEncryptionFailed=Wallet password could not be set. You may have imported seed words which do not match the wallet database. Please contact the developers on Keybase ([HYPERLINK:https://keybase.io/team/bisq]). +password.walletEncryptionFailed=Wallet Passwort konnte nicht eingerichtet werden. Sie haben vielleicht Seed-Wörter importiert, die nicht mit der Wallet-Datenbank übereinstimmen. Bitte kontaktieren Sie die Entwickler auf Keybase ([HYPERLINK:https://keybase.io/team/bisq]). password.passwordsDoNotMatch=Die 2 eingegebenen Passwörter stimmen nicht überein. password.forgotPassword=Passwort vergessen? password.backupReminder=Beachten Sie, dass wenn Sie ein Passwort setzen, alle automatisch erstellten Backups der unverschlüsselten Wallet gelöscht werden.\n\nEs wird dringend empfohlen ein Backup des Anwendungsverzeichnisses zu erstellen und die Seed-Wörter aufzuschreiben, bevor Sie ein Passwort erstellen! @@ -2561,6 +2590,7 @@ payment.venmo.venmoUserName=Venmo Nutzername payment.popmoney.accountId=E-Mail oder Telefonnummer payment.promptPay.promptPayId=Personalausweis/Steuernummer oder Telefonnr. payment.supportedCurrencies=Unterstützte Währungen +payment.supportedCurrenciesForReceiver=Currencies for receiving funds payment.limitations=Einschränkungen payment.salt=Salt für Überprüfung des Kontoalters payment.error.noHexSalt=Der Salt muss im HEX-Format sein.\nEs wird empfohlen das Salt-Feld zu bearbeiten, wenn Sie den Salt von einem alten Konto übertragen, um das Alter Ihres Kontos zu erhalten. Das Alter des Kontos wird durch den Konto-Salt und die Kontodaten (z.B. IBAN) verifiziert. @@ -2599,18 +2629,18 @@ payment.savings=Ersparnisse payment.personalId=Personalausweis payment.clearXchange.info=Zelle ist ein Geldtransferdienst, der am besten *durch* eine andere Bank funktioniert.\n\n1. Sehen Sie auf dieser Seite nach, ob (und wie) Ihre Bank mit Zelle zusammenarbeitet:\nhttps://www.zellepay.com/get-started\n\n2. Achten Sie besonders auf Ihre Überweisungslimits - die Sendelimits variieren je nach Bank, und die Banken geben oft separate Tages-, Wochen- und Monatslimits an.\n\n3. Wenn Ihre Bank nicht mit Zelle zusammenarbeitet, können Sie die Zahlungsmethode trotzdem über die Zelle Mobile App benutzen, aber Ihre Überweisungslimits werden viel niedriger sein.\n\n4. Der auf Ihrem Bisq-Konto angegebene Name MUSS mit dem Namen auf Ihrem Zelle/Bankkonto übereinstimmen. \n\nWenn Sie eine Zelle Transaktion nicht wie in Ihrem Handelsvertrag angegeben durchführen können, verlieren Sie möglicherweise einen Teil (oder die gesamte) Sicherheitskaution.\n\nWegen des etwas höheren Chargeback-Risikos von Zelle wird Verkäufern empfohlen, nicht unterzeichnete Käufer per E-Mail oder SMS zu kontaktieren, um zu überprüfen, ob der Käufer wirklich das in Bisq angegebene Zelle-Konto besitzt. payment.fasterPayments.newRequirements.info=Einige Banken haben damit begonnen, den vollständigen Namen des Empfängers für Faster Payments Überweisungen zu überprüfen. Ihr aktuelles Faster Payments-Konto gibt keinen vollständigen Namen an.\n\nBitte erwägen Sie, Ihr Faster Payments-Konto in Bisq neu einzurichten, um zukünftigen {0} Käufern einen vollständigen Namen zu geben.\n\nWenn Sie das Konto neu erstellen, stellen Sie sicher, dass Sie die genaue Bankleitzahl, Kontonummer und die "Salt"-Werte für die Altersverifikation von Ihrem alten Konto auf Ihr neues Konto kopieren. Dadurch wird sichergestellt, dass das Alter und der Unterschriftsstatus Ihres bestehenden Kontos erhalten bleiben. -payment.moneyGram.info=When using MoneyGram the BTC buyer has to send the Authorisation number and a photo of the receipt by email to the BTC seller. The receipt must clearly show the seller's full name, country, state and the amount. The seller's email will be displayed to the buyer during the trade process. -payment.westernUnion.info=When using Western Union the BTC buyer has to send the MTCN (tracking number) and a photo of the receipt by email to the BTC seller. The receipt must clearly show the seller's full name, city, country and the amount. The seller's email will be displayed to the buyer during the trade process. +payment.moneyGram.info=Bei der Nutzung von MoneyGram, muss der BTC Käufer die MoneyGram Zulassungsnummer und ein Foto der Quittung per E-Mail an den BTC-Verkäufer senden. Die Quittung muss den vollständigen Namen, das Land, das Bundesland des Verkäufers und den Betrag deutlich zeigen. Der Käufer bekommt die E-Mail-Adresse des Verkäufers im Handelsprozess angezeigt. +payment.westernUnion.info=Bei der Nutzung von Western Union, muss der BTC Käufer die MTCN (Tracking-Nummer) Foto der Quittung per E-Mail an den BTC-Verkäufer senden. Die Quittung muss den vollständigen Namen, das Land, die Stadt des Verkäufers und den Betrag deutlich zeigen. Der Käufer bekommt die E-Mail-Adresse des Verkäufers im Handelsprozess angezeigt. payment.halCash.info=Bei Verwendung von HalCash muss der BTC-Käufer dem BTC-Verkäufer den HalCash-Code per SMS vom Mobiltelefon senden.\n\nBitte achten Sie darauf, dass Sie den maximalen Betrag, den Sie bei Ihrer Bank mit HalCash versenden dürfen, nicht überschreiten. Der Mindestbetrag pro Auszahlung beträgt 10 EUR und der Höchstbetrag 600 EUR. Bei wiederholten Abhebungen sind es 3000 EUR pro Empfänger pro Tag und 6000 EUR pro Empfänger pro Monat. Bitte überprüfen Sie diese Limits bei Ihrer Bank, um sicherzustellen, dass sie die gleichen Limits wie hier angegeben verwenden.\n\nDer Auszahlungsbetrag muss ein Vielfaches von 10 EUR betragen, da Sie keine anderen Beträge an einem Geldautomaten abheben können. Die Benutzeroberfläche beim Erstellen und Annehmen eines Angebots passt den BTC-Betrag so an, dass der EUR-Betrag korrekt ist. Sie können keinen marktbasierten Preis verwenden, da sich der EUR-Betrag bei sich ändernden Preisen ändern würde.\n\nIm Streitfall muss der BTC-Käufer den Nachweis erbringen, dass er die EUR geschickt hat. # suppress inspection "UnusedMessageFormatParameter" -payment.limits.info=Please be aware that all bank transfers carry a certain amount of chargeback risk. To mitigate this risk, Bisq sets per-trade limits based on the estimated level of chargeback risk for the payment method used.\n\nFor this payment method, your per-trade limit for buying and selling is {2}.\n\nThis limit only applies to the size of a single trade—you can place as many trades as you like.\n\nSee more details on the wiki [HYPERLINK:https://bisq.wiki/Account_limits]. +payment.limits.info=Bitte beachten Sie, dass alle Banküberweisungen mit einem gewissen Rückbuchungsrisiko verbunden sind. Um dieses Risiko zu mindern, setzt Bisq Limits pro Trade fest, je nachdem wie hoch das Rückbuchungsrisiko der Zahlungsmethode ist. \n\nFür diese Zahlungsmethode beträgt Ihr Pro-Trade-Limit zum Kaufen oder Verkaufen {2}.\nDieses Limit gilt nur für die Größe eines einzelnen Trades - Sie können soviele Trades platzieren wie Sie möchten.\n\nFinden Sie mehr Informationen im Wiki [HYPERLINK:https://bisq.wiki/Account_limits]. # suppress inspection "UnusedProperty" -payment.limits.info.withSigning=To limit chargeback risk, Bisq sets per-trade limits for this payment account type based on the following 2 factors:\n\n1. General chargeback risk for the payment method\n2. Account signing status\n\nThis payment account is not yet signed, so it is limited to buying {0} per trade. After signing, buy limits will increase as follows:\n\n● Before signing, and for 30 days after signing, your per-trade buy limit will be {0}\n● 30 days after signing, your per-trade buy limit will be {1}\n● 60 days after signing, your per-trade buy limit will be {2}\n\nSell limits are not affected by account signing. You can sell {2} in a single trade immediately.\n\nThese limits only apply to the size of a single trade—you can place as many trades as you like. \n\nSee more details on the wiki [HYPERLINK:https://bisq.wiki/Account_limits]. +payment.limits.info.withSigning=Um das Risiko einer Rückbuchung zu minimieren, setzt Bisq für diese Zahlungsmethode Limits pro Trade auf der Grundlage der folgenden 2 Faktoren fest:\n\n1. Allgemeines Rückbuchungsrisiko für die Zahlungsmethode\n2. Status der Kontounterzeichnung\n\nDieses Zahlungskonto ist noch nicht unterzeichnet. Es ist daher auf den Kauf von {0} pro Trade beschränkt ist. Nach der Unterzeichnung werden die Kauflimits wie folgt erhöht:\n\n● Vor der Unterzeichnung und für 30 Tage nach der Unterzeichnung beträgt Ihr Kauflimit pro Trade {0}\n● 30 Tage nach der Unterzeichnung beträgt Ihr Kauflimit pro Trade {1}\n● 60 Tage nach der Unterzeichnung beträgt Ihr Kauflimit pro Trade {2}\n\nVerkaufslimits sind von der Kontounterzeichnung nicht betroffen. Sie können {2} in einem einzigen Trade sofort verkaufen.\n\nDieses Limit gilt nur für die Größe eines einzelnen Trades - Sie können soviele Trades platzieren wie sie möchten.\n\nWeitere Informationen gibt es im Wiki [HYPERLINK:https://bisq.wiki/Account_limits]. payment.cashDeposit.info=Bitte bestätigen Sie, dass Ihre Bank Bareinzahlungen in Konten von anderen Personen erlaubt. Zum Beispiel werden diese Einzahlungen bei der Bank of America und Wells Fargo nicht mehr erlaubt. payment.revolut.info=Revolut benötigt den "Benutzernamen" als Account ID und nicht die Telefonnummer oder E-Mail, wie es in der Vergangenheit war. -payment.account.revolut.addUserNameInfo={0}\nYour existing Revolut account ({1}) does not have a ''User name''.\nPlease enter your Revolut ''User name'' to update your account data.\nThis will not affect your account age signing status. +payment.account.revolut.addUserNameInfo={0}\nDein existierendes Revolut Konto ({1}) hat keinen "Benutzernamen".\nBitte geben Sie Ihren Revolut "Benutzernamen" ein um Ihre Kontodaten zu aktualisieren.\nDas wird Ihr Kontoalter und die Verifizierung nicht beeinflussen. payment.revolut.addUserNameInfo.headLine=Revolut Account updaten payment.usPostalMoneyOrder.info=Der Handel auf Bisq unter Verwendung eines US Postal Money Orders (USPMO) setzt voraus, dass Sie Folgendes verstehen:\n\n- Der BTC-Käufer muss den Namen des BTC-Verkäufers sowohl in das Feld des Zahlers als auch in das Feld des Zahlungsempfängers eintragen und vor dem Versand ein hochauflösendes Foto des USPMO und des Umschlags mit dem Tracking-Nachweis machen.\n- Der BTC-Käufer muss den USPMO zusammen mit der Lieferbestätigung an den BTC-Verkäufer schicken.\n\nFür den Fall, dass eine Mediation erforderlich ist oder es zu einem Handelskonflikt kommt, müssen Sie die Fotos zusammen mit der USPMO-Seriennummer, der Nummer des Postamtes und dem Dollarbetrag an den Bisq-Mediator oder Erstattungsagenten schicken, damit dieser die Angaben auf der Website des US-Postamtes überprüfen kann.\n\nWenn Sie dem Mediator oder Vermittler die erforderlichen Informationen nicht zur Verfügung stellen, führt dies dazu, dass der Konflikt zu Ihrem Nachteil entschieden wird.\n\nIn allen Konfliktfällen trägt der USPMO-Absender 100 % der Verantwortung für die Bereitstellung von Beweisen/Nachweisen für den Mediator oder Vermittler.\n\nWenn Sie diese Anforderungen nicht verstehen, handeln Sie bitte nicht auf Bisq unter Verwendung eines USPMO. @@ -2623,7 +2653,7 @@ payment.f2f.optionalExtra=Freiwillige zusätzliche Informationen payment.f2f.extra=Zusätzliche Informationen payment.f2f.extra.prompt=Der Ersteller kann "Geschäftsbedingungen" festlegen oder öffentliche Kontaktinformationen hinterlegen. Diese werden mit dem Angebot angezeigt. -payment.f2f.info='Face to Face' trades have different rules and come with different risks than online transactions.\n\nThe main differences are:\n● The trading peers need to exchange information about the meeting location and time by using their provided contact details.\n● The trading peers need to bring their laptops and do the confirmation of 'payment sent' and 'payment received' at the meeting place.\n● If a maker has special 'terms and conditions' they must state those in the 'Additional information' text field in the account.\n● By taking an offer the taker agrees to the maker's stated 'terms and conditions'.\n● In case of a dispute the mediator or arbitrator cannot be of much assistance as it is usually difficult to get tamper-proof evidence of what happened at the meeting. In such cases the BTC funds might get locked indefinitely or until the trading peers come to an agreement.\n\nTo be sure you fully understand the differences with 'Face to Face' trades please read the instructions and recommendations at: [HYPERLINK:https://docs.bisq.network/trading-rules.html#f2f-trading] +payment.f2f.info=Persönliche 'Face to Face' Trades haben unterschiedliche Regeln und sind mit anderen Risiken verbunden als gewöhnliche Online-Trades.\n\nDie Hauptunterschiede sind:\n● Die Trading Partner müssen die Kontaktdaten und Informationen über den Ort und die Uhrzeit des Treffens austauschen.\n● Die Trading Partner müssen ihre Laptops mitbringen und die Bestätigung der "gesendeten Zahlung" und der "erhaltenen Zahlung" am Treffpunkt vornehmen.\n● Wenn ein Ersteller eines Angebots spezielle "Allgemeine Geschäftsbedingungen" hat, muss er diese im Textfeld "Zusatzinformationen" des Kontos angeben.\n● Mit der Annahme eines Angebots erklärt sich der Käufer mit den vom Anbieter angegebenen "Allgemeinen Geschäftsbedingungen" einverstanden.\n● Im Konfliktfall kann der Mediator oder Arbitrator nicht viel tun, da es in der Regel schwierig ist zu bestimmen, was beim Treffen passiert ist. In solchen Fällen können die Bitcoin auf unbestimmte Zeit oder bis zu einer Einigung der Trading Peers gesperrt werden.\n\nUm sicherzustellen, dass Sie die Besonderheiten der persönlichen 'Face to Face' Trades vollständig verstehen, lesen Sie bitte die Anweisungen und Empfehlungen unter: [HYPERLINK:https://docs.bisq.network/trading-rules.html#f2f-trading] payment.f2f.info.openURL=Webseite öffnen payment.f2f.offerbook.tooltip.countryAndCity=Land und Stadt: {0} / {1} payment.f2f.offerbook.tooltip.extra=Zusätzliche Informationen: {0} @@ -2634,8 +2664,9 @@ payment.japan.account=Konto payment.japan.recipient=Name payment.australia.payid=PayID payment.payid=PayIDs wie E-Mail Adressen oder Telefonnummern die mit Finanzinstitutionen verbunden sind. -payment.payid.info=A PayID like a phone number, email address or an Australian Business Number (ABN), that you can securely link to your bank, credit union or building society account. You need to have already created a PayID with your Australian financial institution. Both sending and receiving financial institutions must support PayID. For more information please check [HYPERLINK:https://payid.com.au/faqs/] -payment.amazonGiftCard.info=To pay with Amazon eGift Card you need to purchase an Amazon eGift Card at your Amazon account and use the BTC seller''s email or mobile nr. as receiver. Amazon sends then an email or text message to the receiver. Use the trade ID for the message field.\n\nAmazon eGift Cards can only be redeemed by Amazon accounts with the same currency.\n\nFor more information visit the Amazon eGift Card webpage. [HYPERLINK:https://www.amazon.com/Amazon-1_US_Email-eGift-Card/dp/B004LLIKVU] +payment.payid.info=Eine PayID wie eine Telefonnummer, E-Mail Adresse oder Australische Business Number (ABN) mit der Sie sicher Ihre Bank, Kreditgenossenschaft oder Bausparkassenkonto verlinken können. Sie müssen bereits eine PayID mit Ihrer Australischen Finanzinstitution erstellt haben. Beide Institutionen, die die sendet und die die empfängt, müssen PayID unterstützen. Weitere informationen finden Sie unter [HYPERLINK:https://payid.com.au/faqs/] +payment.amazonGiftCard.info=To pay with Amazon eGift Card, you will need to send an Amazon eGift Card to the BTC seller via your Amazon account. \n\nBisq will show the BTC seller''s email address or phone number where the gift card should be sent, and you must include the trade ID in the gift card''s message field. Please see the wiki [HYPERLINK:https://bisq.wiki/Amazon_eGift_card] for further details and best practices. \n\nThree important notes:\n- try to send gift cards with amounts of 100 USD or smaller, as Amazon is known to flag larger gift cards as fraudulent\n- try to use creative, believable text for the gift card''s message (e.g., "Happy birthday Susan!") along with the trade ID (and use trader chat to tell your trading peer the reference text you picked so they can verify your payment)\n- Amazon eGift Cards can only be redeemed on the Amazon website they were purchased on (e.g., a gift card purchased on amazon.it can only be redeemed on amazon.it) + # We use constants from the code so we do not use our normal naming convention # dynamic values are not recognized by IntelliJ @@ -2852,7 +2883,7 @@ validation.numberFormatException=Zahlenformat Ausnahme {0} validation.mustNotBeNegative=Eingabe darf nicht negativ sein validation.phone.missingCountryCode=Es wird eine zweistellige Ländervorwahl benötigt, um die Telefonnummer zu bestätigen validation.phone.invalidCharacters=Telefonnummer {0} enthält ungültige Zeichen -validation.phone.insufficientDigits=Das ist keine gültige Telefonnummer. Sie habe nicht genügend Stellen angegeben. +validation.phone.insufficientDigits=Das ist keine gültige Telefonnummer. Sie habe nicht genügend Stellen angegeben. validation.phone.tooManyDigits=Es sind zu viele Ziffern in {0} um eine gültige Telefonnummer zu sein. -validation.phone.invalidDialingCode=Country dialing code for number {0} is invalid for country {1}. The correct dialing code is {2}. +validation.phone.invalidDialingCode=Die Ländervorwahl in der Nummer {0} ist für das Land {1} ungültig. Die richtige Vorwahl ist {2}. validation.invalidAddressList=Muss eine kommagetrennte Liste der gültigen Adressen sein diff --git a/core/src/main/resources/i18n/displayStrings_es.properties b/core/src/main/resources/i18n/displayStrings_es.properties index e6ca38d219..d6d7871993 100644 --- a/core/src/main/resources/i18n/displayStrings_es.properties +++ b/core/src/main/resources/i18n/displayStrings_es.properties @@ -71,6 +71,7 @@ shared.amountWithCur=Cantidad en {0} shared.volumeWithCur=Volumen en {0} shared.currency=Moneda shared.market=Mercado +shared.deviation=Desviación shared.paymentMethod=Método de pago shared.tradeCurrency=Moneda de intercambio shared.offerType=Tipo de oferta @@ -104,7 +105,6 @@ shared.selectTradingAccount=Selecionar cuenta de intercambio shared.fundFromSavingsWalletButton=Transferir fondos desde la cartera Bisq shared.fundFromExternalWalletButton=Abrir su monedero externo para agregar fondos shared.openDefaultWalletFailed=Fallo al abrir la aplicación de cartera predeterminada. ¿Tal vez no tenga una instalada? -shared.distanceInPercent=Distancia en % del precio de mercado shared.belowInPercent=% por debajo del precio de mercado shared.aboveInPercent=% por encima del precio de mercado shared.enterPercentageValue=Introduzca valor % @@ -123,7 +123,7 @@ shared.noDateAvailable=Sin fecha disponible shared.noDetailsAvailable=Sin detalles disponibles shared.notUsedYet=Sin usar aún shared.date=Fecha -shared.sendFundsDetailsWithFee=Sending: {0}\nFrom address: {1}\nTo receiving address: {2}.\nRequired mining fee is: {3} ({4} satoshis/vbyte)\nTransaction vsize: {5} vKb\n\nThe recipient will receive: {6}\n\nAre you sure you want to withdraw this amount? +shared.sendFundsDetailsWithFee=Enviando: {0}\nDesde la dirección: {1}\nA la dirección receptora: {2}.\nLa comisión requerida de transacción es: {3} ({4} Satoshis/vbyte)\nTamaño de la transacción: {5} vKb\n\nEl receptor recibirá: {6}\n\nSeguro que quiere retirar esta cantidad? # suppress inspection "TrailingSpacesInProperty" shared.sendFundsDetailsDust=Bisq detectó que esta transacción crearía una salida que está por debajo del umbral mínimo considerada polvo (y no está permitida por las reglas de consenso en Bitcoin). En cambio, esta transacción polvo ({0} satoshi {1}) se agregará a la tarifa de minería.\n\n\n shared.copyToClipboard=Copiar al portapapeles @@ -191,7 +191,7 @@ shared.tradeWalletBalance=Saldo de la cartera de intercambio shared.makerTxFee=Creador: {0} shared.takerTxFee=Tomador: {0} shared.iConfirm=Confirmo -shared.tradingFeeInBsqInfo=equivalente a {0} usado como tasa de intercambio +shared.tradingFeeInBsqInfo=≈ {0} shared.openURL=Abrir {0} shared.fiat=Fiat shared.crypto=Cripto @@ -218,6 +218,9 @@ shared.refundAgentForSupportStaff=Agente de devolución de fondos shared.delayedPayoutTxId=ID de transacción del pago demorado shared.delayedPayoutTxReceiverAddress=Transacción de pago demorado enviada a shared.unconfirmedTransactionsLimitReached=Tiene demasiadas transacciones no confirmadas en este momento. Por favor, inténtelo de nuevo más tarde. +shared.numItemsLabel=Número de entradas: {0} +shared.filter=Filtro +shared.enabled=Habilitado #################################################################### @@ -248,14 +251,14 @@ mainView.balance.locked=Bloqueado en intercambios mainView.balance.reserved.short=Reservado mainView.balance.locked.short=Bloqueado -mainView.footer.usingTor=(usando Tor) +mainView.footer.usingTor=(via Tor) mainView.footer.localhostBitcoinNode=(localhost) -mainView.footer.btcInfo={0} {1} {2} -mainView.footer.btcFeeRate=/ Tasas actuales: {0} sat/vB +mainView.footer.btcInfo={0} {1} +mainView.footer.btcFeeRate=/Tasas actuales: {0} sat/vB mainView.footer.btcInfo.initializing=Conectando a la red Bitcoin mainView.footer.bsqInfo.synchronizing=/ Sincronizando DAO -mainView.footer.btcInfo.synchronizingWith=Sincronizando con -mainView.footer.btcInfo.synchronizedWith=Sincronizado con +mainView.footer.btcInfo.synchronizingWith=Sincronizando con {0} en el bloque: {1} / {2} +mainView.footer.btcInfo.synchronizedWith=Sincronizado con {0} en el bloque {1} mainView.footer.btcInfo.connectingTo=Conectando a mainView.footer.btcInfo.connectionFailed=Conexión fallida a mainView.footer.p2pInfo=Pares de Bitcoin: {0} / Pares de la red de Bisq: {1} @@ -336,10 +339,10 @@ offerbook.offerersAcceptedBankSeats=Países de sede de banco aceptados (tomador) offerbook.availableOffers=Ofertas disponibles offerbook.filterByCurrency=Filtrar por moneda offerbook.filterByPaymentMethod=Filtrar por método de pago -offerbook.timeSinceSigning=Firmado desde +offerbook.timeSinceSigning=Información de la cuenta offerbook.timeSinceSigning.info=Esta cuenta fue verificada y {0} offerbook.timeSinceSigning.info.arbitrator=firmada por un árbitro y puede firmar cuentas de pares -offerbook.timeSinceSigning.info.peer=firmado por un par, esperando a que se eleven los límites +offerbook.timeSinceSigning.info.peer=firmado por un par, esperando %d días para aumentar límites offerbook.timeSinceSigning.info.peerLimitLifted=firmador por un par y los límites se elevaron offerbook.timeSinceSigning.info.signer=firmado por un par y puede firmar cuentas de pares (límites elevados) offerbook.timeSinceSigning.info.banned=La cuenta fue bloqueada @@ -349,9 +352,12 @@ offerbook.xmrAutoConf=¿Está habilitada la confirmación automática? offerbook.timeSinceSigning.help=Cuando complete con éxito un intercambio con un par que tenga una cuenta de pago firmada, su cuenta de pago es firmada.\n{0} días después, el límite inicial de {1} se eleva y su cuenta puede firmar tras cuentas de pago. offerbook.timeSinceSigning.notSigned=No firmada aún +offerbook.timeSinceSigning.notSigned.ageDays={0} días offerbook.timeSinceSigning.notSigned.noNeed=No disponible -shared.notSigned=Esta cuenta aún no se ha firmado -shared.notSigned.noNeed=Este tipo de cuenta no utiliza firmado +shared.notSigned=Esta cuenta no ha sido firmada aún y fue creada hace {0} días +shared.notSigned.noNeed=Este tipo de cuenta no necesita firmado +shared.notSigned.noNeedDays=Este tipo de cuenta no necesita firmado y fue creada hace {0} días +shared.notSigned.noNeedAlts=Las cuentas de altcoin no necesitan firmado o edad offerbook.nrOffers=Número de ofertas: {0} offerbook.volume={0} (min - max) @@ -435,11 +441,15 @@ createOffer.warning.sellBelowMarketPrice=Siempre tendrá {0}% menos que el preci createOffer.warning.buyAboveMarketPrice=Siempre pagará {0}% más que el precio de mercado ya que el precio de su oferta será actualizado continuamente. createOffer.tradeFee.descriptionBTCOnly=Comisión de transacción createOffer.tradeFee.descriptionBSQEnabled=Seleccionar moneda de comisión de intercambio -createOffer.tradeFee.fiatAndPercent=≈ {0} / {1} de cantidad de intercambio + +createOffer.triggerPrice.prompt=Set optional trigger price +createOffer.triggerPrice.label=Deactivate offer if market price is {0} +createOffer.triggerPrice.tooltip=As protecting against drastic price movements you can set a trigger price which deactivates the offer if the market price reaches that value. +createOffer.triggerPrice.invalid.tooLow=Value must be higher than {0} +createOffer.triggerPrice.invalid.tooHigh=Value must be lower than {0} # new entries createOffer.placeOfferButton=Revisar: Poner oferta para {0} bitcoin -createOffer.alreadyFunded=Ya había destinado fondos para esa oferta.\nSus fondos han sido movidos a la cartera Bisq local y están disponibles para retirar en la pantalla \"Fondos/Enviar fondos\". createOffer.createOfferFundWalletInfo.headline=Dote de fondos su trato. # suppress inspection "TrailingSpacesInProperty" createOffer.createOfferFundWalletInfo.tradeAmount=- Cantidad a intercambiar: {0}\n @@ -496,7 +506,6 @@ takeOffer.error.message=Un error ocurrió al tomar la oferta.\n\n{0} # new entries takeOffer.takeOfferButton=Revisión: Tomar oferta a {0} bitcoin takeOffer.noPriceFeedAvailable=No puede tomar esta oferta porque utiliza un precio porcentual basado en el precio de mercado y no hay fuentes de precio disponibles. -takeOffer.alreadyFunded.movedFunds=Ya había destinado fondos para esta oferta.\nSus fondos han sido movidos a la cartera Bisq local y están disponibles para retirar en la pantalla \"Fondos/Enviar fondos\". takeOffer.takeOfferFundWalletInfo.headline=Dotar de fondos su intercambio # suppress inspection "TrailingSpacesInProperty" takeOffer.takeOfferFundWalletInfo.tradeAmount=- Cantidad a intercambiar: {0}\n @@ -524,6 +533,10 @@ takeOffer.tac=Al tomar esta oferta, afirmo estar de acuerdo con las condiciones # Offerbook / Edit offer #################################################################### +openOffer.header.triggerPrice=Precio de activación +openOffer.triggerPrice=Trigger price {0} +openOffer.triggered=The offer has been deactivated because the market price reached your trigger price.\nPlease edit the offer to define a new trigger price + editOffer.setPrice=Establecer precio editOffer.confirmEdit=Confirmar: Editar oferta editOffer.publishOffer=Publicando su oferta. @@ -541,6 +554,8 @@ portfolio.tab.history=Historial portfolio.tab.failed=Fallidas portfolio.tab.editOpenOffer=Editar oferta +portfolio.closedTrades.deviation.help=Desviación porcentual de precio de mercado + portfolio.pending.invalidDelayedPayoutTx=Hay un problema con una transacción no válida o faltante.\n\nNO envíe el pago fiat o altcoin. Póngase en contacto con los desarrolladores de Bisq en Keybase [HYPERLINK:https://keybase.io/team/bisq] o en el foro [HYPERLINK:https://bisq.community] para obtener más ayuda.\n\nMensaje de error: {0} portfolio.pending.step1.waitForConf=Esperar a la confirmación en la cadena de bloques @@ -607,7 +622,7 @@ portfolio.pending.step2_buyer.moneyGram.extra=REQUERIMIENTO IMPORTANTE:\nDespué portfolio.pending.step2_buyer.westernUnion=Por favor pague {0} al vendedor de BTC usando Western Union.\n\n portfolio.pending.step2_buyer.westernUnion.extra=REQUERIMIENTO IMPORTANTE:\nDespués de haber realizado el pago envíe el MTCN (número de seguimiento) y una foto de el recibo por email a el vendedor de BTC.\nEl recibo debe mostrar claramente el nombre completo del emisor, la ciudad, país y la cantidad. El email del vendedor es: {0}. # suppress inspection "TrailingSpacesInProperty" -portfolio.pending.step2_buyer.amazonGiftCard=Please purchase an Amazon eGift Card for {0} at your Amazon account and use the BTC seller''s email or mobile number as receiver. In case the trade amount exceeds the permitted amount send multiple cards.\n\n +portfolio.pending.step2_buyer.amazonGiftCard=Por favor compre una Tarjeta Amazon eGift por {0} en su cuenta Amazon y use el email del vendedor BTC o el número de móvil como receptor. En caso de que la cantidad de intercambio exceda la cantidad permitida, envíe múltiples tarjetas. # suppress inspection "TrailingSpacesInProperty" portfolio.pending.step2_buyer.postal=Por favor envíe {0} mediante \"US Postal Money Order\" a el vendedor de BTC.\n\n @@ -680,7 +695,7 @@ portfolio.pending.step3_seller.cash=Debido a que el pago se hecho vía depósito portfolio.pending.step3_seller.moneyGram=El comprador tiene que enviarle el número de autorización y una foto del recibo por correo electrónico.\n\nEl recibo debe mostrar claramente el monto, asi como su nombre completo, país y demarcación (departamento,estado, etc.). Por favor revise su correo electrónico si recibió el número de autorización.\n\nDespués de cerrar esa ventana emergente (popup), verá el nombre y la dirección del comprador de BTC para retirar el dinero de MoneyGram.\n\n¡Solo confirme el recibo de transacción después de haber obtenido el dinero con éxito! portfolio.pending.step3_seller.westernUnion=El comprador tiene que enviarle el MTCN (número de seguimiento) y una foto de el recibo por email.\nEl recibo debe mostrar claramente su nombre completo, ciudad, país y la cantidad. Por favor compruebe su email si ha recibido el MTCN.\n\nDespués de cerrar ese popup verá el nombre del comprador de BTC y la dirección para recoger el dinero de Western Union.\n\nSolo confirme el recibo después de haber recogido satisfactoriamente el dinero! portfolio.pending.step3_seller.halCash=El comprador tiene que enviarle el código HalCash como un mensaje de texto. Junto a esto recibirá un mensaje desde HalCash con la información requerida para retirar los EUR de un cajero que soporte HalCash.\n\nDespués de retirar el dinero del cajero confirme aquí la recepción del pago! -portfolio.pending.step3_seller.amazonGiftCard=The buyer has sent you an Amazon eGift Card by email or by text message to your mobile phone. Please redeem now the Amazon eGift Card at your Amazon account and once accepted confirm the payment receipt. +portfolio.pending.step3_seller.amazonGiftCard=El comprador le ha enviado una Tarjeta Amazon eGift por email o mensaje de texto al teléfono móvil. Por favor canjee ahora la Tarjeta Amazon eGift en su cuenta Amazon y una vez aceptado confirme el recibo del pago. portfolio.pending.step3_seller.bankCheck=\n\nPor favor verifique también que el nombre y el emisor especificado en el contrato de intercambio se corresponde con el nombre que aparece en su declaración bancaria:\nNombre del emisor, para el contrato de intercambio: {0}\n\nSi los nombres no son exactamente los mismos, {1} # suppress inspection "TrailingSpacesInProperty" @@ -886,13 +901,12 @@ funds.tx.noTxAvailable=Sin transacciones disponibles funds.tx.revert=Revertir funds.tx.txSent=Transacción enviada exitosamente a una nueva dirección en la billetera Bisq local. funds.tx.direction.self=Enviado a usted mismo -funds.tx.daoTxFee=Comisión de minería para la tx DAO +funds.tx.daoTxFee=Comisión de minería para la tx BSQ funds.tx.reimbursementRequestTxFee=Solicitud de reembolso funds.tx.compensationRequestTxFee=Solicitud de compensación funds.tx.dustAttackTx=Dust recibido funds.tx.dustAttackTx.popup=Esta transacción está enviando una cantidad de BTC muy pequeña a su monedero y puede ser un intento de compañías de análisis de cadenas para espiar su monedero.\n\nSi usa este output para gastar en una transacción, conocerán que probablemente usted sea el propietario de sus otras direcciones (fusión de monedas).\n\nPara proteger su privacidad el monedero Bisq ignora estos outputs para propósitos de gasto y en el balance mostrado. Puede establecer el umbral en el que un output es considerado dust en ajustes. - #################################################################### # Support #################################################################### @@ -943,6 +957,7 @@ support.error=El receptor no pudo procesar el mensaje. Error: {0} support.buyerAddress=Dirección del comprador de BTC support.sellerAddress=Dirección del vendedor de BTC support.role=Rol +support.agent=Support agent support.state=Estado support.closed=Cerrado support.open=Abierto @@ -986,10 +1001,10 @@ setting.preferences.autoConfirmRequiredConfirmations=Confirmaciones requeridas setting.preferences.autoConfirmMaxTradeSize=Cantidad máxima de intecambio (BTC) setting.preferences.autoConfirmServiceAddresses=Explorador de URLs Monero (usa Tor, excepto para localhost, direcciones LAN IP, y hostnames *.local) setting.preferences.deviationToLarge=No se permiten valores superiores a {0}% -setting.preferences.txFee=Withdrawal transaction fee (satoshis/vbyte) +setting.preferences.txFee=Tasa de transacción de retiro (satoshis/vbyte) setting.preferences.useCustomValue=Usar valor personalizado -setting.preferences.txFeeMin=Transaction fee must be at least {0} satoshis/vbyte -setting.preferences.txFeeTooLarge=Your input is above any reasonable value (>5000 satoshis/vbyte). Transaction fee is usually in the range of 50-400 satoshis/vbyte. +setting.preferences.txFeeMin=La tasa de transacción debe ser al menos de {0} sat/vbyte +setting.preferences.txFeeTooLarge=El valor introducido está muy por encima de lo razonable (>5000 satoshis/vbyte). La tasa de transacción normalmente está en el rango de 50-400 satoshis/vbyte. setting.preferences.ignorePeers=Pares ignorados [dirección onion:puerto] setting.preferences.ignoreDustThreshold=Valor mínimo de output que no sea dust setting.preferences.currenciesInList=Monedas en lista para precio de mercado @@ -1052,6 +1067,7 @@ settings.net.creationDateColumn=Establecido settings.net.connectionTypeColumn=Dentro/Fuera settings.net.sentDataLabel=Estadísticas de datos enviados settings.net.receivedDataLabel=Estadísticas de datos recibidos +settings.net.chainHeightLabel=Altura del último bloque BTC settings.net.roundTripTimeColumn=Tiempo de ida y vuelta settings.net.sentBytesColumn=Enviado settings.net.receivedBytesColumn=Recibido @@ -1066,6 +1082,7 @@ settings.net.needRestart=Necesita reiniciar la aplicación para aplicar ese camb settings.net.notKnownYet=Aún no conocido... settings.net.sentData=Datos enviados: {0}, mensajes {1}, mensajes {2} mensajes por segundo settings.net.receivedData=Datos recibidos: {0}, mensajes {1}, mensajes por segundo {2} +settings.net.chainHeight=Bisq: {0} | Pares: {1} settings.net.ips=[Dirección IP:puerto | host:puerto | dirección onion:puerto] (separado por coma). El puerto puede ser omitido si se utiliza el predeterminado (8333). settings.net.seedNode=Nodo semilla settings.net.directPeer=Par (directo) @@ -1074,7 +1091,7 @@ settings.net.inbound=entrante settings.net.outbound=saliente settings.net.reSyncSPVChainLabel=Resincronizar cadena SPV settings.net.reSyncSPVChainButton=Borrar archivo SPV y resincronizar -settings.net.reSyncSPVSuccess=El archivo de cadena SPV se borrará en el siguiente inicio. Necesita reiniciar la aplicación ahora.\n\nDespués del reinicio puede llevar un rato resincronizar con la red y verá todas las transacciones una vez completada la resincronización.\n\nDependiendo de el número de transacciones y la edad de su monedero la resincronización puede llevar unas horas y consume el 100% de la CPU. No interrumpa el proceso o tendrá que repetirlo. +settings.net.reSyncSPVSuccess=Está seguro de quere hacer una resincronización SPV? Si procede, la cadena SPV se borrará al siguiente inicio.\n\nDespués de reiniciar puede llevarle un rato resincronizar con la red y solo verá las transacciones una vez se haya completado la resincronización.\n\nDependiendo del número de transacciones y la edad de su monedero, la resincronización puede llevarle hasta algunas horas y consumir el 100% de su CPU. No interrumpa el proceso o tendrá que repetirlo. settings.net.reSyncSPVAfterRestart=La cadena SPV ha sido borrada. Por favor, sea paciente. Puede llevar un tiempo resincronizar con la red. settings.net.reSyncSPVAfterRestartCompleted=La resincronización se ha completado. Por favor, reinicie la aplicación. settings.net.reSyncSPVFailed=No se pudo borrar el archivo de cadena SPV\nError: {0} @@ -1161,9 +1178,19 @@ account.menu.paymentAccount=Cuentas de moneda nacional account.menu.altCoinsAccountView=Cuentas de altcoin account.menu.password=Contraseña de monedero account.menu.seedWords=Semilla del monedero +account.menu.walletInfo=Información de monedero account.menu.backup=Copia de seguridad account.menu.notifications=Notificaciones +account.menu.walletInfo.balance.headLine=Balances de monedero +account.menu.walletInfo.balance.info=Esto muestrta el balance interno del monedero, incluyendo transacciones no confirmadas.\nPara BTC, el balance interno de monedero mostrado abajo debe cuadrar con la suma de balances 'Disponible' y 'Reservado' mostrado arriba a la derecha de esta ventana. +account.menu.walletInfo.xpub.headLine=Claves centinela (xpub keys) +account.menu.walletInfo.walletSelector={0} {1} monedero +account.menu.walletInfo.path.headLine=ruta HD keychain +account.menu.walletInfo.path.info=Si importa las palabras semilla en otro monedero (como Electru), tendrá que definir la ruta. Esto debería hacerse solo en casos de emergencia, cuando pierda acceso a el monedero Bisq y el directorio de datos.\nTenga en cuenta que gastar fondos desde un monedero no-Bisq puede estropear la estructura de datos interna de Bisq asociado a los datos de monedero, lo que puede llevar a intercambios fallidos.\n\nNUNCA envíe BSQ desde un monedero no-Bisq, ya que probablemente llevará a una transacción inválida de BSQ y le hará perder sus BSQ. + +account.menu.walletInfo.openDetails=Mostrar detalles en bruto y claves privadas + ## TODO should we rename the following to a gereric name? account.arbitratorRegistration.pubKey=Llave pública @@ -1498,9 +1525,9 @@ dao.bond.reputation.salt=Salt dao.bond.reputation.hash=Hash dao.bond.reputation.lockupButton=Bloquear dao.bond.reputation.lockup.headline=Confirmar transacción de bloqueo -dao.bond.reputation.lockup.details=Lockup amount: {0}\nUnlock time: {1} block(s) (≈{2})\n\nMining fee: {3} ({4} Satoshis/vbyte)\nTransaction vsize: {5} Kb\n\nAre you sure you want to proceed? +dao.bond.reputation.lockup.details=Cantidad bloqueada: {0}\nTiempo de desbloqueo: {1} bloque(s) (≈{2})\n\nComisión de minado: {3} ({4} Satoshis/vbyte)\nTamaño de la transacción: {5} Kb\n\n¿Seguro que quiere proceder? dao.bond.reputation.unlock.headline=Confirmar desbloqueo de transacción -dao.bond.reputation.unlock.details=Unlock amount: {0}\nUnlock time: {1} block(s) (≈{2})\n\nMining fee: {3} ({4} Satoshis/vbyte)\nTransaction vsize: {5} Kb\n\nAre you sure you want to proceed? +dao.bond.reputation.unlock.details=Cantidad de desbloqueo: {0}\nTiempo de desbloqueo: {1} bloque(s) (≈{2})\n\nComisión de minado: {3} ({4} Satoshis/vbyte)\nTamaño de transacción: {5} Kb\n\n¿Seguro que quiere proceder? dao.bond.allBonds.header=Todas las garantías @@ -1796,7 +1823,7 @@ dao.wallet.send.setDestinationAddress=Introduzca su dirección de destino dao.wallet.send.send=Enviar fondos BSQ dao.wallet.send.sendBtc=Enviar fondos BTC dao.wallet.send.sendFunds.headline=Confirme la petición de retiro -dao.wallet.send.sendFunds.details=Sending: {0}\nTo receiving address: {1}.\nRequired transaction fee is: {2} ({3} satoshis/vbyte)\nTransaction vsize: {4} vKb\n\nThe recipient will receive: {5}\n\nAre you sure you want to withdraw that amount? +dao.wallet.send.sendFunds.details=Enviando: {0}\nA la dirección receptora: {1}.\nLa tasa de minado requerida es: {2} ({3} satoshis/vbyte)\nTamaño de la transacción: {4} Kb\n\nEl receptor recibirá: {5}\n\nEstá seguro de que quiere retirar esa cantidad? dao.wallet.chainHeightSynced=Último bloque verificado: {0} dao.wallet.chainHeightSyncing=Esperando bloques... {0} bloques verificados de {1} dao.wallet.tx.type=Tipo @@ -1854,9 +1881,9 @@ dao.proposal.create.missingMinerFeeFunds=No tiene suficientes fondos BTC para cr dao.proposal.create.missingIssuanceFunds=No tiene suficientes fondos BTC para crear la transacción de propuesta. Todas las transacciones BSQ requieren una comisión de minado en BTC, y la emisión de transacciones también requieren BTC para la cantidad de BSQ solicitada ({0} Satoshis/BSQ).\nNecesarios: {1} dao.feeTx.confirm=Confirmar transacción {0} -dao.feeTx.confirm.details={0} fee: {1}\nMining fee: {2} ({3} Satoshis/vbyte)\nTransaction vsize: {4} vKb\n\nAre you sure you want to publish the {5} transaction? +dao.feeTx.confirm.details={0} comisión: {1}\nComisión de minado: {2} ({3} Satoshis/vbyte)\nTamaño de la transacción: {4} Kb\n\n¿Está seguro de que quiere publicar la transacción {5}? -dao.feeTx.issuanceProposal.confirm.details={0} fee: {1}\nBTC needed for BSQ issuance: {2} ({3} Satoshis/BSQ)\nMining fee: {4} ({5} Satoshis/vbyte)\nTransaction vsize: {6} vKb\n\nIf your request is approved, you will receive the amount you requested net of the 2 BSQ proposal fee.\n\nAre you sure you want to publish the {7} transaction? +dao.feeTx.issuanceProposal.confirm.details={0} comisión: {1}\nBTC necesarios para emisión BSQ: {2} ({3} Satoshis/BSQ)\nTasa de minado: {4} ({5} Satoshis/vbyte)\nTamaño de transacción: {6} Kb\n\nSi la solicitud se aprueba, recibirá la cantidad neta que ha solicitado de las 2 BSQ de comisión de propuesta.\n¿Está seguro de que quiere publicar la transacción de {7}? dao.news.bisqDAO.title=LA DAO BISQ dao.news.bisqDAO.description=Tal como el exchange Bisq es descentralizado y resistente a la censura, lo es su modelo de governanza - y la DAO BISQ y el token BSQ son herramientas que lo hacen posible. @@ -1928,9 +1955,9 @@ dao.factsAndFigures.menuItem.transactions=Transacciones BSQ dao.factsAndFigures.dashboard.avgPrice90=Medía de 90 días del precio de intercambio BSQ/BTC dao.factsAndFigures.dashboard.avgPrice30=Medía de 30 días del precio de intercambio BSQ/BTC -dao.factsAndFigures.dashboard.avgUSDPrice90=Media ponderada de 90 días del precio de intercambio USD/BSQ -dao.factsAndFigures.dashboard.avgUSDPrice30=Media ponderada de 30 días del precio de intercambio USD / BSQ -dao.factsAndFigures.dashboard.marketCap=Capitalización de mercado (basado en el precio de intercambio) +dao.factsAndFigures.dashboard.avgUSDPrice90=Media ponderada por volumen de 90 días del precio de USD/BSQ +dao.factsAndFigures.dashboard.avgUSDPrice30=Media ponderada por volumen de 30 días del precio de USD/BSQ +dao.factsAndFigures.dashboard.marketCap=Capitalización de mercado (basado en la media de 30 días del precio USD/BSQ) dao.factsAndFigures.dashboard.availableAmount=BSQ totales disponibles dao.factsAndFigures.supply.issuedVsBurnt=BSQ emitidos v. BSQ quemados @@ -2000,7 +2027,7 @@ disputeSummaryWindow.openDate=Fecha de apertura de ticket disputeSummaryWindow.role=Rol del trader disputeSummaryWindow.payout=Pago de la cantidad de intercambio disputeSummaryWindow.payout.getsTradeAmount=BTC {0} obtiene la cantidad de pago de intercambio -disputeSummaryWindow.payout.getsAll=El {0} BTC obtiene todo +disputeSummaryWindow.payout.getsAll=Cantidad máxima de pago BTC {0} disputeSummaryWindow.payout.custom=Pago personalizado disputeSummaryWindow.payoutAmount.buyer=Cantidad de pago del comprador disputeSummaryWindow.payoutAmount.seller=Cantidad de pago del vendedor @@ -2052,7 +2079,7 @@ disputeSummaryWindow.close.txDetails.headline=Publicar transacción de devoluci disputeSummaryWindow.close.txDetails.buyer=El comprador recibe {0} en la dirección: {1}\n # suppress inspection "TrailingSpacesInProperty" disputeSummaryWindow.close.txDetails.seller=El vendedor recibe {0} en la dirección: {1}\n -disputeSummaryWindow.close.txDetails=Spending: {0}\n{1}{2}Transaction fee: {3} ({4} satoshis/vbyte)\nTransaction vsize: {5} vKb\n\nAre you sure you want to publish this transaction? +disputeSummaryWindow.close.txDetails=Gastando: {0}\n{1}{2}Tasa de transacción: {3} ({4} satoshis/vbyte)\nTamaño virtual de transacción: {5} vKb\n\n¿Está seguro de que quiere publicar esta transacción?\n disputeSummaryWindow.close.noPayout.headline=Cerrar sin realizar algún pago disputeSummaryWindow.close.noPayout.text=¿Quiere cerrar sin realizar algún pago? @@ -2154,6 +2181,7 @@ tradeDetailsWindow.tradingPeersOnion=Dirección onion de par de intercambio tradeDetailsWindow.tradingPeersPubKeyHash=Hash de las llaves públicas de pares de intercambio tradeDetailsWindow.tradeState=Estado del intercambio tradeDetailsWindow.agentAddresses=Árbitro/Mediador +tradeDetailsWindow.detailData=Detallar datos walletPasswordWindow.headline=Introducir contraseña para desbloquear @@ -2183,6 +2211,8 @@ feeOptionWindow.info=Puede elegir pagar la tasa de intercambio en BSQ o BTC. Si feeOptionWindow.optionsLabel=Elija moneda para el pago de comisiones de intercambio feeOptionWindow.useBTC=Usar BTC feeOptionWindow.fee={0} (≈ {1}) +feeOptionWindow.btcFeeWithFiatAndPercentage={0} (≈ {1} / {2}) +feeOptionWindow.btcFeeWithPercentage={0} ({1}) #################################################################### @@ -2192,7 +2222,7 @@ feeOptionWindow.fee={0} (≈ {1}) popup.headline.notification=Notificación popup.headline.instruction=Por favor, tenga en cuenta: popup.headline.attention=Atención -popup.headline.backgroundInfo=Información de fondo +popup.headline.backgroundInfo=Información general popup.headline.feedback=Completado popup.headline.confirmation=Confirmación popup.headline.information=Información @@ -2226,6 +2256,7 @@ popup.warning.noMediatorsAvailable=No hay mediadores disponibles. popup.warning.notFullyConnected=Necesita esperar hasta que esté completamente conectado a la red.\nPuede llevar hasta 2 minutos al inicio. popup.warning.notSufficientConnectionsToBtcNetwork=Necesita esperar hasta que tenga al menos {0} conexiones a la red Bitcoin. popup.warning.downloadNotComplete=Tiene que esperar hasta que finalice la descarga de los bloques Bitcoin que faltan. +popup.warning.chainNotSynced=La cadena de bloques del monedero Bisq no está sincronizada correctamente. Si ha iniciado la aplicación recientemente, espere a que se haya publicado al menos un bloque Bitcoin.\n\nPuede comprobar la altura de la cadena de bloques en Configuración/Información de red. Si se encuentra más de un bloque y el problema persiste podría estar estancado, en cuyo caso deberá hacer una resincronización SPV.\n[HYPERLINK:https://bisq.wiki/Resyncing_SPV_file] popup.warning.removeOffer=¿Está seguro que quiere eliminar la oferta?\nLa comisión de creador de {0} se perderá si elimina la oferta. popup.warning.tooLargePercentageValue=No puede establecer un porcentaje del 100% o superior. popup.warning.examplePercentageValue=Por favor, introduzca un número de porcentaje como \"5.4\" para 5.4% @@ -2264,14 +2295,15 @@ popup.info.cashDepositInfo=Por favor asegúrese de que tiene una oficina bancari popup.info.cashDepositInfo.confirm=Confirmo que puedo hacer el depósito popup.info.shutDownWithOpenOffers=Bisq se está cerrando, pero hay ofertas abiertas.\n\nEstas ofertas no estarán disponibles en la red P2P mientras Bisq esté cerrado, pero serán re-publicadas a la red P2P la próxima vez que inicie Bisq.\n\nPara mantener sus ofertas en línea, mantenga Bisq ejecutándose y asegúrese de que la computadora permanece en línea también (Ej. asegúrese de que no se pone en modo standby... el monitor en espera no es un problema). popup.info.qubesOSSetupInfo=Parece que está ejecutando Bisq en Qubes OS\n\nAsegúrese de que su Bisq qube esté configurado de acuerdo con nuestra Guía de configuración en [HYPERLINK:https://bisq.wiki/Running_Bisq_on_Qubes] +popup.warn.downGradePrevention=Degradar desde la versión {0} a la versión {1} no está soportado. Por favor use la última versión de Bisq. +popup.warn.daoRequiresRestart=Hubo un problema sincronizando el estado de la DAO. Tiene que reiniciar la aplicación para solucionar el problema. popup.privateNotification.headline=Notificación privada importante! popup.securityRecommendation.headline=Recomendación de seguridad importante popup.securityRecommendation.msg=Nos gustaría recordarle que considere usar protección por contraseña para su cartera, si no la ha activado ya.\n\nTambién es muy recomendable que escriba en un papel las palabras semilla del monedero. Esas palabras semilla son como una contraseña maestra para recuperar su cartera Bitcoin.\nEn la sección \"Semilla de cartera\" encontrará más información.\n\nAdicionalmente, debería hacer una copia de seguridad completa del directorio de aplicación en la sección \"Copia de seguridad\" -popup.bitcoinLocalhostNode.msg=Bisq detectó un nodo Bitcoin Core operando localmente (en localhost).\nPor favor asegúrese de que este nodo esté completamente sincronizado antes de iniciar Bisq y que no esté operando en modo poda (pruned mode). -popup.bitcoinLocalhostNode.additionalRequirements=\n\nPara un nodo bien configurado, los requisitos son que el nodo tenga la poda desactivada y los filtros bloom habilitados. +popup.bitcoinLocalhostNode.msg=Bisq ha detectado un nodo de Bitcoin Core ejecutándose en esta máquina (en local).\n\nPor favor, asegúrese de:\n- que el nodo está completamente sincronizado al iniciar Bisq\n- que el podado está desabilitado ('prune=0' en bitcoin.conf)\n- que los filtros bloom están deshabilitados ('peerbloomfilters=1' in bitcoin.conf) popup.shutDownInProgress.headline=Cerrando aplicación... popup.shutDownInProgress.msg=Cerrar la aplicación puede llevar unos segundos.\nPor favor no interrumpa el proceso. @@ -2303,15 +2335,12 @@ popup.accountSigning.signedByPeer=Una de sus cuentas de pago ha sido verificada popup.accountSigning.peerLimitLifted=El límite inicial para una de sus cuentas se ha elevado.\n\n{0} popup.accountSigning.peerSigner=Una de sus cuentas es suficiente antigua para firmar otras cuentas de pago y el límite inicial para una de sus cuentas se ha elevado.\n\n{0} -popup.accountSigning.singleAccountSelect.headline=Seleccionar el testigo de edad de cuenta -popup.accountSigning.singleAccountSelect.description=Buscar un testigo de edad de cuenta -popup.accountSigning.singleAccountSelect.datePicker=Seleccionar un punto en el tiempo para el firmadoº +popup.accountSigning.singleAccountSelect.headline=Importar edad de cuenta de testigos no firmados popup.accountSigning.confirmSingleAccount.headline=Confirmar el testigo de cuenta seleccionado popup.accountSigning.confirmSingleAccount.selectedHash=Hash del testigo seleccionado popup.accountSigning.confirmSingleAccount.button=Firmar testigo de edad de cuenta popup.accountSigning.successSingleAccount.description=Se seleccionón el testigo {0} popup.accountSigning.successSingleAccount.success.headline=Éxito -popup.accountSigning.successSingleAccount.signError=Error al firmar el testigo, {0} popup.accountSigning.unsignedPubKeys.headline=Claves públicas no firmadas popup.accountSigning.unsignedPubKeys.sign=Firmar claves públicas @@ -2354,7 +2383,7 @@ systemTray.tooltip=Bisq: Una red de intercambio de bitcoin descentralizada # GUI Util #################################################################### -guiUtil.miningFeeInfo=Please be sure that the mining fee used by your external wallet is at least {0} satoshis/vbyte. Otherwise the trade transactions may not be confirmed in time and the trade will end up in a dispute. +guiUtil.miningFeeInfo=Por favor asegúrese de que la comisión de minado usada en su monedero externo es de al menos {0} sat/vbyte. De lo contrario, las transacciones de intercambio podrían no confirmarse y el intercambio acabaría en disputa. guiUtil.accountExport.savedToPath=Las cuentas de intercambio se han guardado en el directorio:\n{0} guiUtil.accountExport.noAccountSetup=No tiene cuentas de intercambio configuradas para exportar. @@ -2447,8 +2476,8 @@ navigation.dao.wallet.receive=\"DAO/Monedero BSQ/Recibir\" formatter.formatVolumeLabel={0} cantidad{1} formatter.makerTaker=Creador como {0} {1} / Tomador como {2} {3} -formatter.youAreAsMaker=Usted está {0} {1} como creador / Tomador está {2} {3} -formatter.youAreAsTaker=Usted está {0} {1} como tomador / Creador está {2} {3} +formatter.youAreAsMaker=Usted es: {1} {0} (creador) / El tomador es: {3} {2} +formatter.youAreAsTaker=Usted es: {1} {0} (tomador) / Creador es: {3} {2} formatter.youAre=Usted es {0} {1} ({2} {3}) formatter.youAreCreatingAnOffer.fiat=Está creando una oferta a {0} {1} formatter.youAreCreatingAnOffer.altcoin=Está creando una oferta a {0} {1} ({2} {3}) @@ -2561,6 +2590,7 @@ payment.venmo.venmoUserName=Nombre de usuario Venmo payment.popmoney.accountId=Correo electrónico o núm. de telefóno payment.promptPay.promptPayId=Citizen ID/Tax ID o número de teléfono payment.supportedCurrencies=Monedas soportadas +payment.supportedCurrenciesForReceiver=Monedas para recibir fondos payment.limitations=Límitaciones: payment.salt="Salt" de la verificación de edad de la cuenta. payment.error.noHexSalt=El "salt" necesitar estar en formato HEX.\nSolo se recomienda editar el "salt" si quiere transferir el "salt" desde una cuenta antigua para mantener su edad de cuenta. La edad de cuenta se verifica usando el "salt" de la cuenta y datos de identificación de cuenta (Ej. IBAN). @@ -2634,8 +2664,9 @@ payment.japan.account=Cuenta payment.japan.recipient=Nombre payment.australia.payid=PayID payment.payid=PayID conectado a una institución financiera. Como la dirección email o el número de móvil. -payment.payid.info=A PayID like a phone number, email address or an Australian Business Number (ABN), that you can securely link to your bank, credit union or building society account. You need to have already created a PayID with your Australian financial institution. Both sending and receiving financial institutions must support PayID. For more information please check [HYPERLINK:https://payid.com.au/faqs/] -payment.amazonGiftCard.info=To pay with Amazon eGift Card you need to purchase an Amazon eGift Card at your Amazon account and use the BTC seller''s email or mobile nr. as receiver. Amazon sends then an email or text message to the receiver. Use the trade ID for the message field.\n\nAmazon eGift Cards can only be redeemed by Amazon accounts with the same currency.\n\nFor more information visit the Amazon eGift Card webpage. [HYPERLINK:https://www.amazon.com/Amazon-1_US_Email-eGift-Card/dp/B004LLIKVU] +payment.payid.info=Un PayID como un número de teléfono, dirección email o Australian Business Number (ABN), que puede conectar con seguridad a su banco, unión de crédito o cuenta de construcción de sociedad. Necesita haber creado una PayID con su institución financiera australiana. Tanto para enviar y recibir las instituciones financieras deben soportar PayID. Para más información por favor compruebe [HYPERLINK:https://payid.com.au/faqs/] +payment.amazonGiftCard.info=To pay with Amazon eGift Card, you will need to send an Amazon eGift Card to the BTC seller via your Amazon account. \n\nBisq will show the BTC seller''s email address or phone number where the gift card should be sent, and you must include the trade ID in the gift card''s message field. Please see the wiki [HYPERLINK:https://bisq.wiki/Amazon_eGift_card] for further details and best practices. \n\nThree important notes:\n- try to send gift cards with amounts of 100 USD or smaller, as Amazon is known to flag larger gift cards as fraudulent\n- try to use creative, believable text for the gift card''s message (e.g., "Happy birthday Susan!") along with the trade ID (and use trader chat to tell your trading peer the reference text you picked so they can verify your payment)\n- Amazon eGift Cards can only be redeemed on the Amazon website they were purchased on (e.g., a gift card purchased on amazon.it can only be redeemed on amazon.it) + # We use constants from the code so we do not use our normal naming convention # dynamic values are not recognized by IntelliJ @@ -2713,7 +2744,7 @@ ADVANCED_CASH=Advanced Cash # suppress inspection "UnusedProperty" TRANSFERWISE=TransferWise # suppress inspection "UnusedProperty" -AMAZON_GIFT_CARD=Amazon eGift Card +AMAZON_GIFT_CARD=Tarjeta Amazon eGift # suppress inspection "UnusedProperty" BLOCK_CHAINS_INSTANT=Altcoins instant @@ -2765,7 +2796,7 @@ ADVANCED_CASH_SHORT=Advanced Cash # suppress inspection "UnusedProperty" TRANSFERWISE_SHORT=TransferWise # suppress inspection "UnusedProperty" -AMAZON_GIFT_CARD_SHORT=Amazon eGift Card +AMAZON_GIFT_CARD_SHORT=Tarjeta Amazon eGift # suppress inspection "UnusedProperty" BLOCK_CHAINS_INSTANT_SHORT=Altcoins instant diff --git a/core/src/main/resources/i18n/displayStrings_fa.properties b/core/src/main/resources/i18n/displayStrings_fa.properties index 89eb68de41..d617d8976c 100644 --- a/core/src/main/resources/i18n/displayStrings_fa.properties +++ b/core/src/main/resources/i18n/displayStrings_fa.properties @@ -71,6 +71,7 @@ shared.amountWithCur=مقدار در {0} shared.volumeWithCur=حجم در {0} shared.currency=ارز shared.market=بازار +shared.deviation=Deviation shared.paymentMethod=نحوه پرداخت shared.tradeCurrency=ارز معامله shared.offerType=نوع پیشنهاد @@ -104,7 +105,6 @@ shared.selectTradingAccount=حساب معاملات را انتخاب کنید shared.fundFromSavingsWalletButton=انتقال وجه از کیف Bisq shared.fundFromExternalWalletButton=برای تهیه پول، کیف پول بیرونی خود را باز کنید shared.openDefaultWalletFailed=Failed to open a Bitcoin wallet application. Are you sure you have one installed? -shared.distanceInPercent=فاصله در ٪ از قیمت بازار shared.belowInPercent= ٪ زیر قیمت بازار shared.aboveInPercent= ٪ بالای قیمت بازار shared.enterPercentageValue=ارزش ٪ را وارد کنید @@ -191,7 +191,7 @@ shared.tradeWalletBalance=موجودی کیف‌پول معاملات shared.makerTxFee=سفارش گذار: {0} shared.takerTxFee=پذیرنده سفارش: {0} shared.iConfirm=تایید می‌کنم -shared.tradingFeeInBsqInfo=equivalent to {0} used as trading fee +shared.tradingFeeInBsqInfo=≈ {0} shared.openURL=باز {0} shared.fiat=فیات shared.crypto=کریپتو @@ -218,6 +218,9 @@ shared.refundAgentForSupportStaff=Refund agent shared.delayedPayoutTxId=Delayed payout transaction ID shared.delayedPayoutTxReceiverAddress=Delayed payout transaction sent to shared.unconfirmedTransactionsLimitReached=You have too many unconfirmed transactions at the moment. Please try again later. +shared.numItemsLabel=Number of entries: {0} +shared.filter=Filter +shared.enabled=Enabled #################################################################### @@ -248,14 +251,14 @@ mainView.balance.locked=قفل شده در معاملات mainView.balance.reserved.short=اندوخته mainView.balance.locked.short=قفل شده -mainView.footer.usingTor=(استفاده از Tor) +mainView.footer.usingTor=(via Tor) mainView.footer.localhostBitcoinNode=(لوکال هاست) -mainView.footer.btcInfo={0} {1} {2} -mainView.footer.btcFeeRate=/ Current fee rate: {0} sat/vB +mainView.footer.btcInfo={0} {1} +mainView.footer.btcFeeRate=/ Fee rate: {0} sat/vB mainView.footer.btcInfo.initializing=در حال ارتباط با شبکه بیت‌کوین mainView.footer.bsqInfo.synchronizing=/ همگام‌سازی DAO -mainView.footer.btcInfo.synchronizingWith=در حال همگام شدن با -mainView.footer.btcInfo.synchronizedWith=Synced with +mainView.footer.btcInfo.synchronizingWith=Synchronizing with {0} at block: {1} / {2} +mainView.footer.btcInfo.synchronizedWith=Synced with {0} at block {1} mainView.footer.btcInfo.connectingTo=در حال ایجاد ارتباط با mainView.footer.btcInfo.connectionFailed=Connection failed to mainView.footer.p2pInfo=Bitcoin network peers: {0} / Bisq network peers: {1} @@ -336,10 +339,10 @@ offerbook.offerersAcceptedBankSeats=بانک‌های کشورهای پذیرف offerbook.availableOffers=پیشنهادهای موجود offerbook.filterByCurrency=فیلتر بر اساس ارز offerbook.filterByPaymentMethod=فیلتر بر اساس روش پرداخت -offerbook.timeSinceSigning=Signed since +offerbook.timeSinceSigning=Account info offerbook.timeSinceSigning.info=This account was verified and {0} offerbook.timeSinceSigning.info.arbitrator=signed by an arbitrator and can sign peer accounts -offerbook.timeSinceSigning.info.peer=signed by a peer, waiting for limits to be lifted +offerbook.timeSinceSigning.info.peer=signed by a peer, waiting %d days for limits to be lifted offerbook.timeSinceSigning.info.peerLimitLifted=signed by a peer and limits were lifted offerbook.timeSinceSigning.info.signer=signed by peer and can sign peer accounts (limits lifted) offerbook.timeSinceSigning.info.banned=account was banned @@ -349,9 +352,12 @@ offerbook.xmrAutoConf=Is auto-confirm enabled offerbook.timeSinceSigning.help=When you successfully complete a trade with a peer who has a signed payment account, your payment account is signed.\n{0} days later, the initial limit of {1} is lifted and your account can sign other peers'' payment accounts. offerbook.timeSinceSigning.notSigned=Not signed yet +offerbook.timeSinceSigning.notSigned.ageDays={0} روز offerbook.timeSinceSigning.notSigned.noNeed=بدون پاسخ -shared.notSigned=This account hasn't been signed yet -shared.notSigned.noNeed=This account type doesn't use signing +shared.notSigned=This account has not been signed yet and was created {0} days ago +shared.notSigned.noNeed=This account type does not require signing +shared.notSigned.noNeedDays=This account type does not require signing and was created {0} days ago +shared.notSigned.noNeedAlts=Altcoin accounts do not feature signing or aging offerbook.nrOffers=تعداد پیشنهادها: {0} offerbook.volume={0} (حداقل - حداکثر) @@ -435,11 +441,15 @@ createOffer.warning.sellBelowMarketPrice=شما همیشه {0}% کمتر از ن createOffer.warning.buyAboveMarketPrice=شما همیشه {0}% کمتر از نرخ روز فعلی بازار پرداخت خواهید کرد، زیرا قیمت پیشنهادتان به طور مداوم به روز رسانی خواهد شد. createOffer.tradeFee.descriptionBTCOnly=کارمزد معامله createOffer.tradeFee.descriptionBSQEnabled=انتخاب ارز برای کارمزد معامله -createOffer.tradeFee.fiatAndPercent=≈ {1} / {0} از مبلغ معامله + +createOffer.triggerPrice.prompt=Set optional trigger price +createOffer.triggerPrice.label=Deactivate offer if market price is {0} +createOffer.triggerPrice.tooltip=As protecting against drastic price movements you can set a trigger price which deactivates the offer if the market price reaches that value. +createOffer.triggerPrice.invalid.tooLow=Value must be higher than {0} +createOffer.triggerPrice.invalid.tooHigh=Value must be lower than {0} # new entries createOffer.placeOfferButton=بررسی: پیشنهاد را برای {0} بیتکوین بگذارید -createOffer.alreadyFunded=در حال حاضر آن پیشنهاد را تامین وجه کرده‌اید.\nوجوه شما به کیف پول محلی Bisq منتقل شده و برای برداشت در صفحه \"وجوه/ارسال وجوه\" در دسترس است. createOffer.createOfferFundWalletInfo.headline=پیشنهاد خود را تامین وجه نمایید # suppress inspection "TrailingSpacesInProperty" createOffer.createOfferFundWalletInfo.tradeAmount=مقدار معامله:{0}\n @@ -496,7 +506,6 @@ takeOffer.error.message=هنگام قبول کردن پیشنهاد، اتفاق # new entries takeOffer.takeOfferButton=بررسی: برای {0} بیتکوین پیشنهاد بگذارید. takeOffer.noPriceFeedAvailable=امکان پذیرفتن پیشنهاد وجود ندارد. پیشنهاد از قیمت درصدی مبتنی بر قیمت روز بازار استفاده می‌کند و قیمت‌های بازار هم‌اکنون در دسترس نیست. -takeOffer.alreadyFunded.movedFunds=شما در حال حاضر آن پیشنهاد را تامین وجه کرده‌اید.\nوجوه شما به کیف پول محلی Bisq منتقل شده و برای برداشت در صفحه \"وجوه/ارسال وجوه\" در دسترس است. takeOffer.takeOfferFundWalletInfo.headline=معامله خود را تأمین وجه نمایید # suppress inspection "TrailingSpacesInProperty" takeOffer.takeOfferFundWalletInfo.tradeAmount=مقدار معامله: {0}\n @@ -524,6 +533,10 @@ takeOffer.tac=با پذیرفتن این پیشنهاد، من قبول می‌ # Offerbook / Edit offer #################################################################### +openOffer.header.triggerPrice=قیمت نشان‌شده +openOffer.triggerPrice=Trigger price {0} +openOffer.triggered=The offer has been deactivated because the market price reached your trigger price.\nPlease edit the offer to define a new trigger price + editOffer.setPrice=تنظیم قیمت editOffer.confirmEdit=تأیید: ویرایش پیشنهاد editOffer.publishOffer=انتشار پیشنهاد شما. @@ -541,6 +554,8 @@ portfolio.tab.history=تاریخچه portfolio.tab.failed=ناموفق portfolio.tab.editOpenOffer=ویرایش پیشنهاد +portfolio.closedTrades.deviation.help=Percentage price deviation from market + portfolio.pending.invalidDelayedPayoutTx=There is an issue with a missing or invalid transaction.\n\nPlease do NOT send the fiat or altcoin payment. Contact Bisq developers on Keybase [HYPERLINK:https://keybase.io/team/bisq] or on the forum [HYPERLINK:https://bisq.community] for further assistance.\n\nError message: {0} portfolio.pending.step1.waitForConf=برای تأییدیه بلاک چین منتظر باشید @@ -886,13 +901,12 @@ funds.tx.noTxAvailable=هیچ تراکنشی موجود نیست funds.tx.revert=عودت funds.tx.txSent=تراکنش به طور موفقیت آمیز به یک آدرس جدید در کیف پول محلی Bisq ارسال شد. funds.tx.direction.self=ارسال شده به خودتان -funds.tx.daoTxFee=کارمزد اسخراج برای تراکنش DAO +funds.tx.daoTxFee=کارمزد استخراج برای تراکنش BSQ funds.tx.reimbursementRequestTxFee=درخواست بازپرداخت funds.tx.compensationRequestTxFee=درخواست خسارت funds.tx.dustAttackTx=Received dust funds.tx.dustAttackTx.popup=This transaction is sending a very small BTC amount to your wallet and might be an attempt from chain analysis companies to spy on your wallet.\n\nIf you use that transaction output in a spending transaction they will learn that you are likely the owner of the other address as well (coin merge).\n\nTo protect your privacy the Bisq wallet ignores such dust outputs for spending purposes and in the balance display. You can set the threshold amount when an output is considered dust in the settings. - #################################################################### # Support #################################################################### @@ -943,6 +957,7 @@ support.error=گیرنده نتوانست پیام را پردازش کند. خ support.buyerAddress=آدرس خریدار بیتکوین support.sellerAddress=آدرس فروشنده بیتکوین support.role=نقش +support.agent=Support agent support.state=حالت support.closed=بسته support.open=باز @@ -1052,6 +1067,7 @@ settings.net.creationDateColumn=تثبیت شده settings.net.connectionTypeColumn=درون/بیرون settings.net.sentDataLabel=Sent data statistics settings.net.receivedDataLabel=Received data statistics +settings.net.chainHeightLabel=Latest BTC block height settings.net.roundTripTimeColumn=تاخیر چرخشی settings.net.sentBytesColumn=ارسال شده settings.net.receivedBytesColumn=دریافت شده @@ -1066,6 +1082,7 @@ settings.net.needRestart=به منظور اعمال آن تغییر باید ب settings.net.notKnownYet=هنوز شناخته شده نیست ... settings.net.sentData=Sent data: {0}, {1} messages, {2} messages/sec settings.net.receivedData=Received data: {0}, {1} messages, {2} messages/sec +settings.net.chainHeight=Bisq: {0} | Peers: {1} settings.net.ips=[آدرس آی پی: پورت | نام میزبان: پورت | آدرس Onion : پورت] (جدا شده با ویرگول). اگر از پیش فرض (8333) استفاده می شود، پورت می تواند حذف شود. settings.net.seedNode=گره ی اصلی settings.net.directPeer=همتا (مستقیم) @@ -1074,7 +1091,7 @@ settings.net.inbound=وارد شونده settings.net.outbound=خارج شونده settings.net.reSyncSPVChainLabel=همگام سازی مجدد زنجیره SPV  settings.net.reSyncSPVChainButton=حذف فایل SPV  و همگام سازی مجدد -settings.net.reSyncSPVSuccess=The SPV chain file will be deleted on the next startup. You need to restart your application now.\n\nAfter the restart it can take a while to resync with the network and you will only see all transactions once the resync is completed.\n\nDepending on the number of transactions and the age of your wallet the resync can take up to a few hours and consumes 100% of CPU. Do not interrupt the process otherwise you have to repeat it. +settings.net.reSyncSPVSuccess=Are you sure you want to do an SPV resync? If you proceed, the SPV chain file will be deleted on the next startup.\n\nAfter the restart it can take a while to resync with the network and you will only see all transactions once the resync is completed.\n\nDepending on the number of transactions and the age of your wallet the resync can take up to a few hours and consumes 100% of CPU. Do not interrupt the process otherwise you have to repeat it. settings.net.reSyncSPVAfterRestart=فایل زنجیره SPV حذف شده است. لطفاً صبور باشید، همگام سازی مجدد با شبکه کمی طول خواهد کشید. settings.net.reSyncSPVAfterRestartCompleted=همگام سازی مجدد هم اکنون تکمیل شده است. لطفاً برنامه را مجدداً راه اندازی نمایید. settings.net.reSyncSPVFailed=حذف فایل زنجیره SPV امکان پذیر نیست. \nخطا: {0} @@ -1161,9 +1178,19 @@ account.menu.paymentAccount=حساب های ارز ملی account.menu.altCoinsAccountView=حساب های آلت کوین account.menu.password=رمز کیف پول account.menu.seedWords=رمز پشتیبان کیف پول +account.menu.walletInfo=Wallet info account.menu.backup=پشتیبان account.menu.notifications=اعلان‌ها +account.menu.walletInfo.balance.headLine=Wallet balances +account.menu.walletInfo.balance.info=This shows the internal wallet balance including unconfirmed transactions.\nFor BTC, the internal wallet balance shown below should match the sum of the 'Available' and 'Reserved' balances shown in the top right of this window. +account.menu.walletInfo.xpub.headLine=Watch keys (xpub keys) +account.menu.walletInfo.walletSelector={0} {1} wallet +account.menu.walletInfo.path.headLine=HD keychain paths +account.menu.walletInfo.path.info=If you import seed words into another wallet (like Electrum), you'll need to define the path. This should only be done in emergency cases when you lose access to the Bisq wallet and data directory.\nKeep in mind that spending funds from a non-Bisq wallet can bungle the internal Bisq data structures associated with the wallet data, which can lead to failed trades.\n\nNEVER send BSQ from a non-Bisq wallet, as it will probably lead to an invalid BSQ transaction and losing your BSQ. + +account.menu.walletInfo.openDetails=Show raw wallet details and private keys + ## TODO should we rename the following to a gereric name? account.arbitratorRegistration.pubKey=کلید عمومی @@ -1796,7 +1823,7 @@ dao.wallet.send.setDestinationAddress=آدرس مقصد خود را پر کنی dao.wallet.send.send=ارسال وجوه BSQ  dao.wallet.send.sendBtc=ارسال وجوه BTC dao.wallet.send.sendFunds.headline=تأیید درخواست برداشت -dao.wallet.send.sendFunds.details=Sending: {0}\nTo receiving address: {1}.\nRequired transaction fee is: {2} ({3} satoshis/vbyte)\nTransaction vsize: {4} vKb\n\nThe recipient will receive: {5}\n\nAre you sure you want to withdraw that amount? +dao.wallet.send.sendFunds.details=Sending: {0}\nTo receiving address: {1}.\nRequired mining fee is: {2} ({3} satoshis/vbyte)\nTransaction vsize: {4} vKb\n\nThe recipient will receive: {5}\n\nAre you sure you want to withdraw that amount? dao.wallet.chainHeightSynced=آخرین بلاک تایید شده: {0} dao.wallet.chainHeightSyncing=منتظر بلاک‌ها... {0} تا از {1} بلاک تایید شده است dao.wallet.tx.type=نوع @@ -1928,9 +1955,9 @@ dao.factsAndFigures.menuItem.transactions=تراکنش‌های BSQ dao.factsAndFigures.dashboard.avgPrice90=90 days average BSQ/BTC trade price dao.factsAndFigures.dashboard.avgPrice30=30 days average BSQ/BTC trade price -dao.factsAndFigures.dashboard.avgUSDPrice90=90 days volume weighted average USD/BSQ trade price -dao.factsAndFigures.dashboard.avgUSDPrice30=30 days volume weighted average USD/BSQ trade price -dao.factsAndFigures.dashboard.marketCap=ارزش بازار (بر مبنای قیمت معاملاتی) +dao.factsAndFigures.dashboard.avgUSDPrice90=90 days volume weighted average USD/BSQ price +dao.factsAndFigures.dashboard.avgUSDPrice30=30 days volume weighted average USD/BSQ price +dao.factsAndFigures.dashboard.marketCap=Market capitalisation (based on 30 days average USD/BSQ price) dao.factsAndFigures.dashboard.availableAmount=مجموع BSQ در دسترس dao.factsAndFigures.supply.issuedVsBurnt=BSQ issued v. BSQ burnt @@ -2000,7 +2027,7 @@ disputeSummaryWindow.openDate=تاریخ ایجاد تیکت disputeSummaryWindow.role=نقش معامله گر disputeSummaryWindow.payout=پرداختی مقدار معامله disputeSummaryWindow.payout.getsTradeAmount=BTC {0} پرداختی مبلغ معامله را دریافت می کند -disputeSummaryWindow.payout.getsAll=BTC {0} همه را دریافت می کند +disputeSummaryWindow.payout.getsAll=Max. payout to BTC {0} disputeSummaryWindow.payout.custom=پرداخت سفارشی disputeSummaryWindow.payoutAmount.buyer=مقدار پرداختی خریدار disputeSummaryWindow.payoutAmount.seller=مقدار پرداختی فروشنده @@ -2154,6 +2181,7 @@ tradeDetailsWindow.tradingPeersOnion=آدرس Onion همتایان معامله: tradeDetailsWindow.tradingPeersPubKeyHash=Trading peers pubkey hash tradeDetailsWindow.tradeState=وضعیت معامله tradeDetailsWindow.agentAddresses=Arbitrator/Mediator +tradeDetailsWindow.detailData=Detail data walletPasswordWindow.headline=وارد کردن رمز عبور به منظور باز کردن @@ -2183,6 +2211,8 @@ feeOptionWindow.info=شما می توانید انتخاب کنید که هزی feeOptionWindow.optionsLabel=انتخاب ارز برای پرداخت کارمزد معامله feeOptionWindow.useBTC=استفاده از BTC feeOptionWindow.fee={0} (≈ {1}) +feeOptionWindow.btcFeeWithFiatAndPercentage={0} (≈ {1} / {2}) +feeOptionWindow.btcFeeWithPercentage={0} ({1}) #################################################################### @@ -2226,6 +2256,7 @@ popup.warning.noMediatorsAvailable=There are no mediators available. popup.warning.notFullyConnected=شما باید منتظر بمانید تا به طور کامل به شبکه متصل شوید. \nاین ممکن است در هنگام راه اندازی حدود 2 دقیقه طول بکشد. popup.warning.notSufficientConnectionsToBtcNetwork=شما باید منتظر بمانید تا حداقل {0} اتصال به شبکه بیتکوین داشته باشید. popup.warning.downloadNotComplete=شما باید منتظر بمانید تا بارگیری بلاک های بیتکوین باقیمانده کامل شود. +popup.warning.chainNotSynced=The Bisq wallet blockchain height is not synced correctly. If you recently started the application, please wait until one Bitcoin block has been published.\n\nYou can check the blockchain height in Settings/Network Info. If more than one block passes and this problem persists it may be stalled, in which case you should do an SPV resync. [HYPERLINK:https://bisq.wiki/Resyncing_SPV_file] popup.warning.removeOffer=آیا شما مطمئن هستید که می خواهید این پیشنهاد را حذف کنید؟\nاگر آن پیشنهاد را حذف کنید، هزینه سفارش گذار {0} از دست خواهد رفت . popup.warning.tooLargePercentageValue=شما نمیتوانید درصد 100٪ یا بیشتر را تنظیم کنید. popup.warning.examplePercentageValue=لطفا یک عدد درصد مانند \"5.4\" برای 5.4% وارد کنید @@ -2254,7 +2285,7 @@ popup.warning.openOffer.makerFeeTxRejected=The maker fee transaction for offer w popup.warning.trade.txRejected.tradeFee=trade fee popup.warning.trade.txRejected.deposit=deposit -popup.warning.trade.txRejected=The {0} transaction for trade with ID {1} was rejected by the Bitcoin network.\nTransaction ID={2}}\nThe trade has been moved to failed trades.\nPlease go to \"Settings/Network info\" and do a SPV resync.\nFor further help please contact the Bisq support channel at the Bisq Keybase team. +popup.warning.trade.txRejected=The {0} transaction for trade with ID {1} was rejected by the Bitcoin network.\nTransaction ID={2}\nThe trade has been moved to failed trades.\nPlease go to \"Settings/Network info\" and do a SPV resync.\nFor further help please contact the Bisq support channel at the Bisq Keybase team. popup.warning.openOfferWithInvalidMakerFeeTx=The maker fee transaction for offer with ID {0} is invalid.\nTransaction ID={1}.\nPlease go to \"Settings/Network info\" and do a SPV resync.\nFor further help please contact the Bisq support channel at the Bisq Keybase team. @@ -2264,14 +2295,15 @@ popup.info.cashDepositInfo=لطفا مطمئن شوید که شما یک شعب popup.info.cashDepositInfo.confirm=تأیید می کنم که می توانم سپرده را ایجاد کنم popup.info.shutDownWithOpenOffers=Bisq در حال خاموش شدن است ولی پیشنهاداتی وجود دارند که باز هستند.\n\nزمانی که Bisq بسته باشد این پیشنهادات در شبکه P2P در دسترس نخواهند بود، ولی هر وقت دوباره Bisq را باز کنید این پیشنهادات دوباره در شبکه P2P منتشر خواهند شد.\n\n برای اینکه پیشنهادات شما برخط بمانند، بگذارید Bisq در حال اجرابماند و همچنین مطمئن شوید که این کامپیوتر به اینترنت متصل است. (به عنوان مثال مطمئن شوید که به حالت آماده باش نمی‌رود.. البته حالت آماده باش برای نمایشگر ایرادی ندارد). popup.info.qubesOSSetupInfo=It appears you are running Bisq on Qubes OS. \n\nPlease make sure your Bisq qube is setup according to our Setup Guide at [HYPERLINK:https://bisq.wiki/Running_Bisq_on_Qubes]. +popup.warn.downGradePrevention=Downgrade from version {0} to version {1} is not supported. Please use the latest Bisq version. +popup.warn.daoRequiresRestart=There was a problem with synchronizing the DAO state. You have to restart the application to fix the issue. popup.privateNotification.headline=اعلان خصوصی مهم! popup.securityRecommendation.headline=توصیه امنیتی مهم popup.securityRecommendation.msg=ما می خواهیم به شما یادآوری کنیم که استفاده از رمز محافظت برای کیف پول خود را در نظر بگیرید اگر از قبل آن را فعال نکرده اید.\n\nهمچنین شدیداً توصیه می شود که کلمات رمز خصوصی کیف پول را بنویسید. این کلمات رمز خصوصی مانند یک رمزعبور اصلی برای بازیابی کیف پول بیتکوین شما هستند. \nدر قسمت \"کلمات رمز خصوصی کیف پول\" اطلاعات بیشتری کسب می کنید.\n\n علاوه بر این شما باید از پوشه داده های کامل نرم افزار در بخش \"پشتیبان گیری\" پشتیبان تهیه کنید. -popup.bitcoinLocalhostNode.msg=Bisq یک گره بیتکوین هسته محلی در حال اجرا را (در لوکا هاست) شناسایی کرد.\n لطفا اطمینان حاصل کنید که این گره قبل از شروع Bisq به طور کامل همگام سازی شده و در حالت هرس شده اجرا نمی شود. -popup.bitcoinLocalhostNode.additionalRequirements=\n\nFor a well configured node, the requirements are for the node to have pruning disabled and bloom filters enabled. +popup.bitcoinLocalhostNode.msg=Bisq detected a Bitcoin Core node running on this machine (at localhost).\n\nPlease ensure:\n- the node is fully synced before starting Bisq\n- pruning is disabled ('prune=0' in bitcoin.conf)\n- bloom filters are enabled ('peerbloomfilters=1' in bitcoin.conf) popup.shutDownInProgress.headline=خاموش شدن در حال انجام است popup.shutDownInProgress.msg=خاتمه دادن به برنامه می تواند چند ثانیه طول بکشد.\n لطفا این روند را قطع نکنید. @@ -2303,15 +2335,12 @@ popup.accountSigning.signedByPeer=One of your payment accounts has been verified popup.accountSigning.peerLimitLifted=The initial limit for one of your accounts has been lifted.\n\n{0} popup.accountSigning.peerSigner=One of your accounts is mature enough to sign other payment accounts and the initial limit for one of your accounts has been lifted.\n\n{0} -popup.accountSigning.singleAccountSelect.headline=Select account age witness -popup.accountSigning.singleAccountSelect.description=Search for account age witness. -popup.accountSigning.singleAccountSelect.datePicker=Select point of time for signing +popup.accountSigning.singleAccountSelect.headline=Import unsigned account age witness popup.accountSigning.confirmSingleAccount.headline=Confirm selected account age witness popup.accountSigning.confirmSingleAccount.selectedHash=Selected witness hash popup.accountSigning.confirmSingleAccount.button=Sign account age witness popup.accountSigning.successSingleAccount.description=Witness {0} was signed popup.accountSigning.successSingleAccount.success.headline=Success -popup.accountSigning.successSingleAccount.signError=Failed to sign witness, {0} popup.accountSigning.unsignedPubKeys.headline=Unsigned Pubkeys popup.accountSigning.unsignedPubKeys.sign=Sign Pubkeys @@ -2447,8 +2476,8 @@ navigation.dao.wallet.receive=\"DAO/کیف پول BSQ/دریافت\" formatter.formatVolumeLabel={0} مبلغ {1} formatter.makerTaker=سفارش گذار به عنوان {0} {1} / پذیرنده به عنوان {2} {3} -formatter.youAreAsMaker=شما {0} {1} به عنوان سفارش گذار هستید/ پذیرنده {2} {3} هست -formatter.youAreAsTaker=شما {0} {1} به عنوان پذیرنده هستید/ سفارش گذار {2} {3} هست +formatter.youAreAsMaker=You are: {1} {0} (maker) / Taker is: {3} {2} +formatter.youAreAsTaker=You are: {1} {0} (taker) / Maker is: {3} {2} formatter.youAre=شما {0} {1} ({2} {3}) هستید formatter.youAreCreatingAnOffer.fiat=شما در حال ایجاد یک پیشنهاد به {0} {1} هستید formatter.youAreCreatingAnOffer.altcoin=شما در حال ایجاد یک پیشنهاد به {0} {1} ({2} {3}) هستید @@ -2561,6 +2590,7 @@ payment.venmo.venmoUserName=نام کاربری Venmo payment.popmoney.accountId=ایمیل یا شماره تلفن payment.promptPay.promptPayId=شناسه شهروندی/شناسه مالیاتی یا شماره تلفن payment.supportedCurrencies=ارزهای مورد حمایت +payment.supportedCurrenciesForReceiver=Currencies for receiving funds payment.limitations=محدودیت‌ها payment.salt=داده‌های تصافی برای اعتبارسنجی سن حساب payment.error.noHexSalt=The salt needs to be in HEX format.\nIt is only recommended to edit the salt field if you want to transfer the salt from an old account to keep your account age. The account age is verified by using the account salt and the identifying account data (e.g. IBAN). @@ -2635,7 +2665,8 @@ payment.japan.recipient=نام payment.australia.payid=PayID payment.payid=PayID linked to financial institution. Like email address or mobile phone. payment.payid.info=A PayID like a phone number, email address or an Australian Business Number (ABN), that you can securely link to your bank, credit union or building society account. You need to have already created a PayID with your Australian financial institution. Both sending and receiving financial institutions must support PayID. For more information please check [HYPERLINK:https://payid.com.au/faqs/] -payment.amazonGiftCard.info=To pay with Amazon eGift Card you need to purchase an Amazon eGift Card at your Amazon account and use the BTC seller''s email or mobile nr. as receiver. Amazon sends then an email or text message to the receiver. Use the trade ID for the message field.\n\nAmazon eGift Cards can only be redeemed by Amazon accounts with the same currency.\n\nFor more information visit the Amazon eGift Card webpage. [HYPERLINK:https://www.amazon.com/Amazon-1_US_Email-eGift-Card/dp/B004LLIKVU] +payment.amazonGiftCard.info=To pay with Amazon eGift Card, you will need to send an Amazon eGift Card to the BTC seller via your Amazon account. \n\nBisq will show the BTC seller''s email address or phone number where the gift card should be sent, and you must include the trade ID in the gift card''s message field. Please see the wiki [HYPERLINK:https://bisq.wiki/Amazon_eGift_card] for further details and best practices. \n\nThree important notes:\n- try to send gift cards with amounts of 100 USD or smaller, as Amazon is known to flag larger gift cards as fraudulent\n- try to use creative, believable text for the gift card''s message (e.g., "Happy birthday Susan!") along with the trade ID (and use trader chat to tell your trading peer the reference text you picked so they can verify your payment)\n- Amazon eGift Cards can only be redeemed on the Amazon website they were purchased on (e.g., a gift card purchased on amazon.it can only be redeemed on amazon.it) + # We use constants from the code so we do not use our normal naming convention # dynamic values are not recognized by IntelliJ diff --git a/core/src/main/resources/i18n/displayStrings_fr.properties b/core/src/main/resources/i18n/displayStrings_fr.properties index 93f98cf04f..0d43edf08e 100644 --- a/core/src/main/resources/i18n/displayStrings_fr.properties +++ b/core/src/main/resources/i18n/displayStrings_fr.properties @@ -35,7 +35,7 @@ shared.no=Non shared.iUnderstand=Je comprends shared.na=N/A shared.shutDown=Éteindre -shared.reportBug=Report bug on GitHub +shared.reportBug=Signaler des bugs sur Github shared.buyBitcoin=Achat Bitcoin shared.sellBitcoin=Vendre des Bitcoins shared.buyCurrency=Achat {0} @@ -71,6 +71,7 @@ shared.amountWithCur=Montant en {0} shared.volumeWithCur=Volume en {0} shared.currency=Devise shared.market=Marché +shared.deviation=Deviation shared.paymentMethod=Mode de paiement shared.tradeCurrency=Devise d'échange shared.offerType=Type d'ordre @@ -95,21 +96,20 @@ shared.BTCMinMax=BTC (min - max) shared.removeOffer=Retirer l'ordre shared.dontRemoveOffer=Ne pas retirer l'ordre shared.editOffer=Éditer l'ordre -shared.openLargeQRWindow=Open large QR code window +shared.openLargeQRWindow=Ouvrez et agrandissez la fenêtre du code QR shared.tradingAccount=Compte de trading -shared.faq=Visit FAQ page +shared.faq=Visitez la page FAQ shared.yesCancel=Oui, annuler shared.nextStep=Étape suivante shared.selectTradingAccount=Sélectionner le compte de trading shared.fundFromSavingsWalletButton=Transférer des fonds depuis le portefeuille Bisq shared.fundFromExternalWalletButton=Ouvrez votre portefeuille externe pour provisionner -shared.openDefaultWalletFailed=Failed to open a Bitcoin wallet application. Are you sure you have one installed? -shared.distanceInPercent=Écart en % par rapport au du prix du marché +shared.openDefaultWalletFailed=L'ouverture de l'application de portefeuille Bitcoin par défaut a échoué. Êtes-vous sûr de l'avoir installée? shared.belowInPercent=% sous le prix du marché shared.aboveInPercent=% au-dessus du prix du marché shared.enterPercentageValue=Entrez la valeur en % shared.OR=OU -shared.notEnoughFunds=You don''t have enough funds in your Bisq wallet for this transaction—{0} is needed but only {1} is available.\n\nPlease add funds from an external wallet, or fund your Bisq wallet at Funds > Receive Funds. +shared.notEnoughFunds=Il n'y a pas suffisamment de fonds dans votre portefeuille Bisq pour payer cette transaction. La transaction a besoin de {0} Votre solde disponible est de {1}. \n\nVeuillez injecter des fonds à partir d'un portefeuille Bitcoin externe ou recharger votre portefeuille Bisq dans «Fonds / Dépôts». shared.waitingForFunds=En attente des fonds... shared.depositTransactionId=ID de la transaction de dépôt shared.TheBTCBuyer=L'acheteur de BTC @@ -125,15 +125,15 @@ shared.notUsedYet=Pas encore utilisé shared.date=Date shared.sendFundsDetailsWithFee=Sending: {0}\nFrom address: {1}\nTo receiving address: {2}.\nRequired mining fee is: {3} ({4} satoshis/vbyte)\nTransaction vsize: {5} vKb\n\nThe recipient will receive: {6}\n\nAre you sure you want to withdraw this amount? # suppress inspection "TrailingSpacesInProperty" -shared.sendFundsDetailsDust=Bisq detected that this transaction would create a change output which is below the minimum dust threshold (and therefore not allowed by Bitcoin consensus rules). Instead, this dust ({0} satoshi{1}) will be added to the mining fee.\n\n\n +shared.sendFundsDetailsDust=Bisq détecte que la transaction produira une sortie inférieure au seuil de fraction minimum (non autorisé par les règles de consensus Bitcoin). Au lieu de cela, ces fractions ({0} satoshi {1}) seront ajoutées aux frais de traitement minier. shared.copyToClipboard=Copier dans le presse-papiers shared.language=Langue shared.country=Pays shared.applyAndShutDown=Appliquer et éteindre shared.selectPaymentMethod=Sélectionner un mode de paiement -shared.accountNameAlreadyUsed=That account name is already used for another saved account.\nPlease choose another name. +shared.accountNameAlreadyUsed=Ce nom de compte a été utilisé par un compte enregistré. Veuillez utiliser un autre nom. shared.askConfirmDeleteAccount=Voulez-vous vraiment supprimer le compte sélectionné? -shared.cannotDeleteAccount=You cannot delete that account because it is being used in an open offer (or in an open trade). +shared.cannotDeleteAccount=Vous ne pouvez pas supprimer ce compte car il est utilisé dans des devis ou des transactions. shared.noAccountsSetupYet=Il n'y a pas encore de comptes établis. shared.manageAccounts=Gérer les comptes shared.addNewAccount=Ajouter un nouveau compte @@ -191,7 +191,7 @@ shared.tradeWalletBalance=Solde du portefeuille de trading shared.makerTxFee=Maker: {0} shared.takerTxFee=Taker: {0} shared.iConfirm=Je confirme -shared.tradingFeeInBsqInfo=Équivalent à {0} utilisé en frais de transaction +shared.tradingFeeInBsqInfo=≈ {0} shared.openURL=Ouvert {0} shared.fiat=Fiat shared.crypto=Crypto @@ -218,6 +218,9 @@ shared.refundAgentForSupportStaff=Agent de remboursement shared.delayedPayoutTxId=Delayed payout transaction ID shared.delayedPayoutTxReceiverAddress=Delayed payout transaction sent to shared.unconfirmedTransactionsLimitReached=Vous avez trop de transactions non confirmées pour le moment. Veuillez réessayer plus tard. +shared.numItemsLabel=Number of entries: {0} +shared.filter=Filter +shared.enabled=Enabled #################################################################### @@ -248,14 +251,14 @@ mainView.balance.locked=Bloqué en transactions mainView.balance.reserved.short=Réservé mainView.balance.locked.short=Vérouillé -mainView.footer.usingTor=(utilisant Tor) +mainView.footer.usingTor=(via Tor) mainView.footer.localhostBitcoinNode=(localhost) -mainView.footer.btcInfo={0} {1} {2} -mainView.footer.btcFeeRate=/ Current fee rate: {0} sat/vB +mainView.footer.btcInfo={0} {1} +mainView.footer.btcFeeRate=/ Fee rate: {0} sat/vB mainView.footer.btcInfo.initializing=Connexion au réseau Bitcoin en cours mainView.footer.bsqInfo.synchronizing=/ Synchronisation DAO en cours -mainView.footer.btcInfo.synchronizingWith=Synchronisation avec -mainView.footer.btcInfo.synchronizedWith=Synced with +mainView.footer.btcInfo.synchronizingWith=Synchronizing with {0} at block: {1} / {2} +mainView.footer.btcInfo.synchronizedWith=Synced with {0} at block {1} mainView.footer.btcInfo.connectingTo=Se connecte à mainView.footer.btcInfo.connectionFailed=Connection failed to mainView.footer.p2pInfo=Bitcoin network peers: {0} / Bisq network peers: {1} @@ -336,10 +339,10 @@ offerbook.offerersAcceptedBankSeats=Pays acceptés où se situe le siège de la offerbook.availableOffers=Ordres disponibles offerbook.filterByCurrency=Filtrer par devise offerbook.filterByPaymentMethod=Filtrer par mode de paiement -offerbook.timeSinceSigning=Signed since +offerbook.timeSinceSigning=Account info offerbook.timeSinceSigning.info=Ce compte a été vérifié et {0} offerbook.timeSinceSigning.info.arbitrator=signé par un arbitre et pouvant signer des comptes pairs -offerbook.timeSinceSigning.info.peer=signé par un pair, en attente de la levée des limites +offerbook.timeSinceSigning.info.peer=signed by a peer, waiting %d days for limits to be lifted offerbook.timeSinceSigning.info.peerLimitLifted=signé par un pair et les limites ont été levées offerbook.timeSinceSigning.info.signer=signé par un pair et pouvant signer des comptes de pairs (limites levées) offerbook.timeSinceSigning.info.banned=Ce compte a été banni @@ -349,14 +352,17 @@ offerbook.xmrAutoConf=Is auto-confirm enabled offerbook.timeSinceSigning.help=Lorsque vous effectuez avec succès une transaction avec un pair disposant d''un compte de paiement signé, votre compte de paiement est signé.\n{0} Jours plus tard, la limite initiale de {1} est levée et votre compte peut signer les comptes de paiement d''un autre pair. offerbook.timeSinceSigning.notSigned=Pas encore signé +offerbook.timeSinceSigning.notSigned.ageDays={0} jours offerbook.timeSinceSigning.notSigned.noNeed=N/A -shared.notSigned=Ce compte n'a pas encore été signé -shared.notSigned.noNeed=Ce type de compte n'utilise pas de signature +shared.notSigned=This account has not been signed yet and was created {0} days ago +shared.notSigned.noNeed=This account type does not require signing +shared.notSigned.noNeedDays=This account type does not require signing and was created {0} days ago +shared.notSigned.noNeedAlts=Altcoin accounts do not feature signing or aging offerbook.nrOffers=Nombre d''ordres: {0} offerbook.volume={0} (min - max) offerbook.deposit=Deposit BTC (%) -offerbook.deposit.help=Deposit paid by each trader to guarantee the trade. Will be returned when the trade is completed. +offerbook.deposit.help=Les deux parties à la transaction ont payé un dépôt pour assurer que la transaction se déroule normalement. Ce montant sera remboursé une fois la transaction terminée. offerbook.createOfferToBuy=Créer un nouvel ordre d''achat pour {0} offerbook.createOfferToSell=Créer un nouvel ordre de vente pour {0} @@ -377,11 +383,11 @@ offerbook.withdrawFundsHint=Vous pouvez retirer les fonds investis depuis l''éc offerbook.warning.noTradingAccountForCurrency.headline=No payment account for selected currency offerbook.warning.noTradingAccountForCurrency.msg=You don't have a payment account set up for the selected currency.\n\nWould you like to create an offer for another currency instead? offerbook.warning.noMatchingAccount.headline=No matching payment account. -offerbook.warning.noMatchingAccount.msg=This offer uses a payment method you haven't set up yet. \n\nWould you like to set up a new payment account now? +offerbook.warning.noMatchingAccount.msg=Cette offre utilise un mode de paiement que vous n'avez pas créé. \n\nVoulez-vous créer un nouveau compte de paiement maintenant? offerbook.warning.counterpartyTradeRestrictions=Cette offre ne peut être acceptée en raison de restrictions d'échange imposées par les contreparties -offerbook.warning.newVersionAnnouncement=With this version of the software, trading peers can verify and sign each others' payment accounts to create a network of trusted payment accounts.\n\nAfter successfully trading with a peer with a verified payment account, your payment account will be signed and trading limits will be lifted after a certain time interval (length of this interval is based on the verification method).\n\nFor more information on account signing, please see the documentation at [HYPERLINK:https://docs.bisq.network/payment-methods#account-signing]. +offerbook.warning.newVersionAnnouncement=Grâce à cette version du logiciel, les partenaires commerciaux peuvent confirmer et vérifier les comptes de paiement de chacun pour créer un réseau de comptes de paiement de confiance.\n\nUne fois la transaction réussie, votre compte de paiement sera vérifié et les restrictions de transaction seront levées après une certaine période de temps (cette durée est basée sur la méthode de vérification).\n\nPour plus d'informations sur la vérification de votre compte, veuillez consulter le document sur https://docs.bisq.network/payment-methods#account-signing popup.warning.tradeLimitDueAccountAgeRestriction.seller=Le montant de transaction autorisé est limité à {0} en raison des restrictions de sécurité basées sur les critères suivants:\n- Le compte de l''acheteur n''a pas été signé par un arbitre ou par un pair\n- Le délai depuis la signature du compte de l''acheteur est inférieur à 30 jours\n- Le mode de paiement pour cette offre est considéré comme présentant un risque de rétrofacturation bancaire\n\n{1} popup.warning.tradeLimitDueAccountAgeRestriction.buyer=Le montant de transaction autorisé est limité à {0} en raison des restrictions de sécurité basées sur les critères suivants:\n- Votre compte n''a pas été signé par un arbitre ou par un pair\n- Le délai depuis la signature de votre compte est inférieur à 30 jours\n- Le mode de paiement pour cette offre est considéré comme présentant un risque de rétrofacturation bancaire\n\n{1} @@ -392,8 +398,8 @@ offerbook.warning.offerBlocked=L'ordre a été bloqué par des développeurs de offerbook.warning.currencyBanned=La devise utilisée pour cet ordre a été bloquée par les développeurs de Bisq.\nVeuillez visiter le Forum Bisq pour obtenir plus d'informations. offerbook.warning.paymentMethodBanned=Le mode de paiement utilisé pour cet ordre a été bloqué par les développeurs de Bisq.\nVeuillez visiter le Forum Bisq pour obtenir plus d'informations. offerbook.warning.nodeBlocked=L'adresse onion de ce trader a été bloquée par les développeurs de Bisq.\nIl s'agit peut être d'un bug qui cause des problèmes lors de l'acceptation de cet ordre. -offerbook.warning.requireUpdateToNewVersion=Your version of Bisq is not compatible for trading anymore.\nPlease update to the latest Bisq version at [HYPERLINK:https://bisq.network/downloads]. -offerbook.warning.offerWasAlreadyUsedInTrade=You cannot take this offer because you already took it earlier. It could be that your previous take-offer attempt resulted in a failed trade. +offerbook.warning.requireUpdateToNewVersion=Votre version Bisq n'est plus compatible avec les transactions. Veuillez mettre à jour la dernière version de Bisq via https://bisq.network/downloads +offerbook.warning.offerWasAlreadyUsedInTrade=Vous ne pouvez pas prendre la commande car vous avez déjà terminé l'opération. Il se peut que votre précédente tentative de prise de commandes ait entraîné l'échec de la transaction. offerbook.info.sellAtMarketPrice=Vous vendrez au prix du marché (mis à jour chaque minute). offerbook.info.buyAtMarketPrice=Vous achèterez au prix du marché (mis à jour chaque minute). @@ -435,11 +441,15 @@ createOffer.warning.sellBelowMarketPrice=Vous obtiendrez toujours {0}% de moins createOffer.warning.buyAboveMarketPrice=Vous paierez toujours {0}% de plus que le prix actuel du marché car le prix de votre ordre sera continuellement mis à jour. createOffer.tradeFee.descriptionBTCOnly=Frais de transaction createOffer.tradeFee.descriptionBSQEnabled=Choisir la devise des frais de transaction -createOffer.tradeFee.fiatAndPercent=≈ {0} / {1} du montant de la transaction + +createOffer.triggerPrice.prompt=Set optional trigger price +createOffer.triggerPrice.label=Deactivate offer if market price is {0} +createOffer.triggerPrice.tooltip=As protecting against drastic price movements you can set a trigger price which deactivates the offer if the market price reaches that value. +createOffer.triggerPrice.invalid.tooLow=Value must be higher than {0} +createOffer.triggerPrice.invalid.tooHigh=Value must be lower than {0} # new entries createOffer.placeOfferButton=Review: Placer un ordre de {0} Bitcoin -createOffer.alreadyFunded=Vous aviez déjà financé cet ordre.\nVos fonds ont été transférés dans votre portefeuille Bisq local et peuvent être retirés dans l'onglet \"Fonds/Envoyer des fonds\" createOffer.createOfferFundWalletInfo.headline=Financer votre ordre # suppress inspection "TrailingSpacesInProperty" createOffer.createOfferFundWalletInfo.tradeAmount=Montant du trade: {0}\n\n @@ -496,7 +506,6 @@ takeOffer.error.message=Une erreur s''est produite pendant l’'acceptation de l # new entries takeOffer.takeOfferButton=Vérifier: Accepter l''ordre de {0} Bitcoin takeOffer.noPriceFeedAvailable=Vous ne pouvez pas accepter cet ordre, car celui-ci utilise un prix en pourcentage basé sur le prix du marché, mais il n'y a pas de prix de référence de disponible. -takeOffer.alreadyFunded.movedFunds=Vous aviez déjà provisionner cette ordre.\nVos fonds ont été transféré dans votre portefeuille bisq local et sont disponible dans l'onglet \"Fonds/Envoyer des fonds\" takeOffer.takeOfferFundWalletInfo.headline=Provisionner votre trade # suppress inspection "TrailingSpacesInProperty" takeOffer.takeOfferFundWalletInfo.tradeAmount=- Montant du trade: {0}\n @@ -524,6 +533,10 @@ takeOffer.tac=En acceptant cet ordre vous acceptez les conditions de transaction # Offerbook / Edit offer #################################################################### +openOffer.header.triggerPrice=Prix de déclenchement +openOffer.triggerPrice=Trigger price {0} +openOffer.triggered=The offer has been deactivated because the market price reached your trigger price.\nPlease edit the offer to define a new trigger price + editOffer.setPrice=Définir le prix editOffer.confirmEdit=Confirmation: Modification de l'ordre editOffer.publishOffer=Publication de votre ordre. @@ -541,7 +554,9 @@ portfolio.tab.history=Historique portfolio.tab.failed=Échec portfolio.tab.editOpenOffer=Éditer l'ordre -portfolio.pending.invalidDelayedPayoutTx=There is an issue with a missing or invalid transaction.\n\nPlease do NOT send the fiat or altcoin payment. Contact Bisq developers on Keybase [HYPERLINK:https://keybase.io/team/bisq] or on the forum [HYPERLINK:https://bisq.community] for further assistance.\n\nError message: {0} +portfolio.closedTrades.deviation.help=Percentage price deviation from market + +portfolio.pending.invalidDelayedPayoutTx=Il y a un problème causé par des transactions manquantes ou indisponibles. \n\nVeuillez ne pas envoyer de monnaie fiduciaire ou de monnaie numérique. Contactez les développeurs Bisq sur Keybase à https://keybase.io/team/bisq ou sur le forum [HYPERLINK:https://bisq.community] pour plus d'aide. \n\nMessage d'erreur: {0} portfolio.pending.step1.waitForConf=Attendre la confirmation de la blockchain portfolio.pending.step2_buyer.startPayment=Initier le paiement @@ -636,7 +651,7 @@ portfolio.pending.step2_buyer.confirmStart.headline=Confirmez que vous avez init portfolio.pending.step2_buyer.confirmStart.msg=Avez-vous initié le {0} paiement auprès de votre partenaire de trading? portfolio.pending.step2_buyer.confirmStart.yes=Oui, j'ai initié le paiement portfolio.pending.step2_buyer.confirmStart.proof.warningTitle=You have not provided proof of payment -portfolio.pending.step2_buyer.confirmStart.proof.noneProvided=You have not entered the transaction ID and the transaction key.\n\nBy not providing this data the peer cannot use the auto-confirm feature to release the BTC as soon the XMR has been received.\nBeside that, Bisq requires that the sender of the XMR transaction is able to provide this information to the mediator or arbitrator in case of a dispute.\nSee more details on the Bisq wiki [HYPERLINK:https://bisq.wiki/Trading_Monero#Auto-confirming_trades]. +portfolio.pending.step2_buyer.confirmStart.proof.noneProvided=Lorsque vous terminez une transaction BTC / XMR, vous pouvez utiliser la fonction de confirmation automatique pour vérifier si le montant correct de XMR a été envoyé à votre portefeuille, afin que Bisq puisse automatiquement marquer la transaction comme terminée et pour que tout le monde puisse aller plus vite. \n\nConfirmez automatiquement que les transactions XMR sont vérifiées sur au moins 2 nœuds d'explorateur de blocs XMR à l'aide de la clé de transaction fournie par l'expéditeur XMR. Par défaut, Bisq utilise un nœud d'explorateur de blocs exécuté par des contributeurs Bisq, mais nous vous recommandons d'exécuter votre propre nœud d'explorateur de blocs XMR pour maximiser la confidentialité et la sécurité. \n\nVous pouvez également définir le nombre maximum de BTC par transaction dans «Paramètres» pour confirmer automatiquement et le nombre de confirmations requises. \n\nPlus de détails sur Bisq Wiki (y compris comment configurer votre propre nœud d'explorateur de blocs): [HYPERLINK:https://bisq.wiki/Trading_Monero#Auto-confirming_trades] portfolio.pending.step2_buyer.confirmStart.proof.invalidInput=Input is not a 32 byte hexadecimal value portfolio.pending.step2_buyer.confirmStart.warningButton=Ignore and continue anyway portfolio.pending.step2_seller.waitPayment.headline=En attende du paiement @@ -781,21 +796,21 @@ portfolio.pending.mediationResult.info.peerAccepted=Votre pair de trading a acce portfolio.pending.mediationResult.button=Voir la résolution proposée portfolio.pending.mediationResult.popup.headline=Résultat de la médiation pour la transaction avec l''ID: {0} portfolio.pending.mediationResult.popup.headline.peerAccepted=Votre pair de trading a accepté la suggestion du médiateur pour la transaction {0} -portfolio.pending.mediationResult.popup.info=The mediator has suggested the following payout:\nYou receive: {0}\nYour trading peer receives: {1}\n\nYou can accept or reject this suggested payout.\n\nBy accepting, you sign the proposed payout transaction. If your trading peer also accepts and signs, the payout will be completed, and the trade will be closed.\n\nIf one or both of you reject the suggestion, you will have to wait until {2} (block {3}) to open a second-round dispute with an arbitrator who will investigate the case again and do a payout based on their findings.\n\nThe arbitrator may charge a small fee (fee maximum: the trader''s security deposit) as compensation for their work. Both traders agreeing to the mediator''s suggestion is the happy path—requesting arbitration is meant for exceptional circumstances, such as if a trader is sure the mediator did not make a fair payout suggestion (or if the other peer is unresponsive).\n\nMore details about the new arbitration model: [HYPERLINK:https://docs.bisq.network/trading-rules.html#arbitration] -portfolio.pending.mediationResult.popup.selfAccepted.lockTimeOver=You have accepted the mediator''s suggested payout but it seems that your trading peer has not accepted it.\n\nOnce the lock time is over on {0} (block {1}), you can open a second-round dispute with an arbitrator who will investigate the case again and do a payout based on their findings.\n\nYou can find more details about the arbitration model at:[HYPERLINK:https://docs.bisq.network/trading-rules.html#arbitration] +portfolio.pending.mediationResult.popup.info=Les frais recommandés par le médiateur sont les suivants: \nVous paierez: {0} \nVotre partenaire commercial paiera: {1} \n\nVous pouvez accepter ou refuser ces frais de médiation. \n\nEn acceptant, vous avez vérifié l'opération de paiement du contrat. Si votre partenaire commercial accepte et vérifie également, le paiement sera effectué et la transaction sera clôturée. \n\nSi l'un de vous ou les deux refusent la proposition, vous devrez attendre le {2} (bloc {3}) pour commencer le deuxième tour de discussion sur le différend avec l'arbitre, et ce dernier étudiera à nouveau le cas. Le paiement sera fait en fonction de ses résultats. \n\nL'arbitre peut facturer une somme modique (la limite supérieure des honoraires: la marge de la transaction) en compensation de son travail. Les deux commerçants conviennent que la suggestion du médiateur est une voie agréable. La demande d'arbitrage concerne des circonstances particulières, par exemple si un professionnel est convaincu que le médiateur n'a pas fait une recommandation de d'indemnisation équitable (ou si l'autre partenaire n'a pas répondu). \n\nPlus de détails sur le nouveau modèle d'arbitrage: [HYPERLINK:https://docs.bisq.network/trading-rules.html#arbitration] +portfolio.pending.mediationResult.popup.selfAccepted.lockTimeOver=Vous avez accepté la proposition de paiement du médiateur, mais il semble que votre contrepartie ne l'ait pas acceptée. \n\nUne fois que le temps de verrouillage atteint {0} (bloc {1}), vous pouvez ouvrir le second tour de litige pour que l'arbitre réétudie le cas et prend une nouvelle décision de dépenses. \n\nVous pouvez trouver plus d'informations sur le modèle d'arbitrage sur:[HYPERLINK:https://docs.bisq.network/trading-rules.html#arbitration] portfolio.pending.mediationResult.popup.openArbitration=Refuser et demander un arbitrage portfolio.pending.mediationResult.popup.alreadyAccepted=Vous avez déjà accepté portfolio.pending.failedTrade.taker.missingTakerFeeTx=The taker fee transaction is missing.\n\nWithout this tx, the trade cannot be completed. No funds have been locked and no trade fee has been paid. You can move this trade to failed trades. portfolio.pending.failedTrade.maker.missingTakerFeeTx=The peer's taker fee transaction is missing.\n\nWithout this tx, the trade cannot be completed. No funds have been locked. Your offer is still available to other traders, so you have not lost the maker fee. You can move this trade to failed trades. -portfolio.pending.failedTrade.missingDepositTx=The deposit transaction (the 2-of-2 multisig transaction) is missing.\n\nWithout this tx, the trade cannot be completed. No funds have been locked but your trade fee has been paid. You can make a request to be reimbursed the trade fee here: [HYPERLINK:https://github.com/bisq-network/support/issues]\n\nFeel free to move this trade to failed trades. +portfolio.pending.failedTrade.missingDepositTx=Cette transaction de marge (transaction multi-signature de 2 à 2) est manquante.\n\nSans ce tx, la transaction ne peut pas être complétée. Aucun fonds n'est bloqué, mais vos frais de transaction sont toujours payés. Vous pouvez lancer une demande de compensation des frais de transaction ici: [HYPERLINK:https://github.com/bisq-network/support/issues] \nN'hésitez pas à déplacer la transaction vers la transaction échouée. portfolio.pending.failedTrade.buyer.existingDepositTxButMissingDelayedPayoutTx=The delayed payout transaction is missing, but funds have been locked in the deposit transaction.\n\nPlease do NOT send the fiat or altcoin payment to the BTC seller, because without the delayed payout tx, arbitration cannot be opened. Instead, open a mediation ticket with Cmd/Ctrl+o. The mediator should suggest that both peers each get back the the full amount of their security deposits (with seller receiving full trade amount back as well). This way, there is no security risk, and only trade fees are lost. \n\nYou can request a reimbursement for lost trade fees here: [HYPERLINK:https://github.com/bisq-network/support/issues] portfolio.pending.failedTrade.seller.existingDepositTxButMissingDelayedPayoutTx=The delayed payout transaction is missing but funds have been locked in the deposit transaction.\n\nIf the buyer is also missing the delayed payout transaction, they will be instructed to NOT send the payment and open a mediation ticket instead. You should also open a mediation ticket with Cmd/Ctrl+o. \n\nIf the buyer has not sent payment yet, the mediator should suggest that both peers each get back the full amount of their security deposits (with seller receiving full trade amount back as well). Otherwise the trade amount should go to the buyer. \n\nYou can request a reimbursement for lost trade fees here: [HYPERLINK:https://github.com/bisq-network/support/issues] portfolio.pending.failedTrade.errorMsgSet=There was an error during trade protocol execution.\n\nError: {0}\n\nIt might be that this error is not critical, and the trade can be completed normally. If you are unsure, open a mediation ticket to get advice from Bisq mediators. \n\nIf the error was critical and the trade cannot be completed, you might have lost your trade fee. Request a reimbursement for lost trade fees here: [HYPERLINK:https://github.com/bisq-network/support/issues] portfolio.pending.failedTrade.missingContract=The trade contract is not set.\n\nThe trade cannot be completed and you might have lost your trade fee. If so, you can request a reimbursement for lost trade fees here: [HYPERLINK:https://github.com/bisq-network/support/issues] portfolio.pending.failedTrade.info.popup=The trade protocol encountered some problems.\n\n{0} portfolio.pending.failedTrade.txChainInvalid.moveToFailed=The trade protocol encountered a serious problem.\n\n{0}\n\nDo you want to move the trade to failed trades?\n\nYou cannot open mediation or arbitration from the failed trades view, but you can move a failed trade back to the open trades screen any time. -portfolio.pending.failedTrade.txChainValid.moveToFailed=The trade protocol encountered some problems.\n\n{0}\n\nThe trade transactions have been published and funds are locked. Only move the trade to failed trades if you are really sure. It might prevent options to resolve the problem.\n\nDo you want to move the trade to failed trades?\n\nYou cannot open mediation or arbitration from the failed trades view, but you can move a failed trade back to the open trades screen any time. +portfolio.pending.failedTrade.txChainValid.moveToFailed=Il y a des problèmes avec cet accord de transaction. \n\n{0}\n\nLa transaction de devis a été validée et les fonds ont été bloqués. Déplacer la transaction vers une transaction échouée uniquement si elle est certaine. Cela peut empêcher les options disponibles pour résoudre le problème. \n\nÊtes-vous sûr de vouloir déplacer cette transaction vers la transaction échouée? \n\nVous ne pouvez pas ouvrir une médiation ou un arbitrage dans une transaction échouée, mais vous pouvez déplacer une transaction échouée vers la transaction incomplète à tout moment. portfolio.pending.failedTrade.moveTradeToFailedIcon.tooltip=Move trade to failed trades portfolio.pending.failedTrade.warningIcon.tooltip=Click to open details about the issues of this trade portfolio.failed.revertToPending.popup=Do you want to move this trade to open trades? @@ -886,13 +901,12 @@ funds.tx.noTxAvailable=Pas de transactions disponibles funds.tx.revert=Revertir funds.tx.txSent=Transaction envoyée avec succès vers une nouvelle adresse dans le portefeuille local bisq. funds.tx.direction.self=Envoyé à vous même -funds.tx.daoTxFee=Frais de minage du tx de la DAO +funds.tx.daoTxFee=Frais de minage du tx BSQ funds.tx.reimbursementRequestTxFee=Demande de remboursement funds.tx.compensationRequestTxFee=Requête de compensation funds.tx.dustAttackTx=dust reçues funds.tx.dustAttackTx.popup=Cette transaction va envoyer un faible montant en BTC sur votre portefeuille ce qui pourrait constituer une tentative d'espionnage de la part de sociétés qui analyse la chaine.\n\nSi vous utilisez cette transaction de sortie des données dans le cadre d'une transaction représentant une dépense il sera alors possible de comprendre que vous êtes probablement aussi le propriétaire de l'autre adresse (coin merge).\n\nAfin de protéger votre vie privée, le portefeuille Bisq ne tient pas compte de ces "dust outputs" dans le cadre des transactions de vente et dans l'affichage de la balance. Vous pouvez définir une quantité seuil lorsqu'une "output" est considérée comme poussière dans les réglages. - #################################################################### # Support #################################################################### @@ -943,6 +957,7 @@ support.error=Le destinataire n''a pas pu traiter le message. Erreur : {0} support.buyerAddress=Adresse de l'acheteur BTC support.sellerAddress=Adresse du vendeur BTC support.role=Rôle +support.agent=Support agent support.state=État support.closed=Fermé support.open=Ouvert @@ -962,7 +977,7 @@ support.peerOpenedDispute=Votre pair de trading a fait une demande de litige.\n\ support.peerOpenedDisputeForMediation=Votre pair de trading a demandé une médiation.\n\n{0}\n\nVersion de Bisq: {1} support.mediatorsDisputeSummary=System message: Mediator''s dispute summary:\n{0} support.mediatorsAddress=Adresse du nœud du médiateur: {0} -support.warning.disputesWithInvalidDonationAddress=The delayed payout transaction has used an invalid receiver address. It does not match any of the DAO parameter values for the valid donation addresses.\n\nThis might be a scam attempt. Please inform the developers about that incident and do not close that case before the situation is resolved!\n\nAddress used in the dispute: {0}\n\nAll DAO param donation addresses: {1}\n\nTrade ID: {2}{3} +support.warning.disputesWithInvalidDonationAddress=La transaction de paiement différé a été utilisée pour une adresse de destinataire indisponible. Il ne correspond aux paramètres dans aucun DAO de l'adresse de donation valide. \n\nCela peut être une escroquerie. Veuillez informer le développeur et ne fermez pas le dossier jusqu'à ce que le problème est résolu! \n\nAdresse pour les litiges: {0} \n\nAdresse de donation dans tous les paramètres DAO: {1} \n\nTransaction: {2} {3} support.warning.disputesWithInvalidDonationAddress.mediator=\n\nDo you still want to close the dispute? support.warning.disputesWithInvalidDonationAddress.refundAgent=\n\nYou must not do the payout. @@ -1013,7 +1028,7 @@ setting.preferences.daoOptions=Options DAO setting.preferences.dao.resyncFromGenesis.label=Reconstituer l'état de la DAO à partir du tx genesis setting.preferences.dao.resyncFromResources.label=Rebuild DAO state from resources setting.preferences.dao.resyncFromResources.popup=After an application restart the Bisq network governance data will be reloaded from the seed nodes and the BSQ consensus state will be rebuilt from the latest resource files. -setting.preferences.dao.resyncFromGenesis.popup=A resync from genesis transaction can take considerable time and CPU resources. Are you sure you want to do that? Mostly a resync from latest resource files is sufficient and much faster.\n\nIf you proceed, after an application restart the Bisq network governance data will be reloaded from the seed nodes and the BSQ consensus state will be rebuilt from the genesis transaction. +setting.preferences.dao.resyncFromGenesis.popup=La synchronisation à partir de la transaction d'origine consomme beaucoup de temps et de ressources CPU. Êtes-vous sûr de vouloir resynchroniser ? En général, la resynchronisation à partir du dernier fichier de ressources est suffisante et plus rapide. \n\nAprès le redémarrage de l'application, les données de gestion du réseau Bisq seront rechargées à partir du nœud d'amorçage et l'état de synchronisation BSQ sera reconstruit à partir de la transaction initiale. setting.preferences.dao.resyncFromGenesis.resync=Resync from genesis and shutdown setting.preferences.dao.isDaoFullNode=Exécuter la DAO de Bisq en tant que full node setting.preferences.dao.rpcUser=Nom d'utilisateur RPC @@ -1040,7 +1055,7 @@ settings.net.bitcoinNodesLabel=Nœuds Bitcoin Core pour se connecter à settings.net.useProvidedNodesRadio=Utiliser les nœuds Bitcoin Core fournis settings.net.usePublicNodesRadio=Utiliser le réseau Bitcoin public settings.net.useCustomNodesRadio=Utiliser des nœuds Bitcoin Core personnalisés -settings.net.warn.usePublicNodes=If you use the public Bitcoin network you are exposed to a severe privacy problem caused by the broken bloom filter design and implementation which is used for SPV wallets like BitcoinJ (used in Bisq). Any full node you are connected to could find out that all your wallet addresses belong to one entity.\n\nPlease read more about the details at [HYPERLINK:https://bisq.network/blog/privacy-in-bitsquare].\n\nAre you sure you want to use the public nodes? +settings.net.warn.usePublicNodes=Si vous utilisez le réseau public Bitcoin, vous serez confronté à de sérieux problèmes de confidentialité. Ceci est dû à la conception et à la mise en œuvre du bloom filter cassé. Il convient aux portefeuilles SPV comme BitcoinJ (utilisé dans Bisq). Tout nœud complet que vous connectez peut découvrir que toutes les adresses de votre portefeuille appartiennent à une seule entité. \n\nPour plus d'informations, veuillez visiter: [HYPERLINK:https://bisq.network/blog/privacy-in-bitsquare] \n\nÊtes-vous sûr de vouloir utiliser un nœud public? settings.net.warn.usePublicNodes.useProvided=Non, utiliser les nœuds fournis. settings.net.warn.usePublicNodes.usePublic=Oui, utiliser un réseau public settings.net.warn.useCustomNodes.B2XWarning=Veuillez vous assurer que votre nœud Bitcoin est un nœud Bitcoin Core de confiance !\n\nLa connexion à des nœuds qui ne respectent pas les règles du consensus de Bitcoin Core peut corrompre votre portefeuille et causer des problèmes dans le processus de trading.\n\nLes utilisateurs qui se connectent à des nœuds qui ne respectent pas les règles du consensus sont responsables des dommages qui en résultent. Tout litige qui en résulte sera tranché en faveur de l'autre pair. Aucune assistance technique ne sera apportée aux utilisateurs qui ignorent ces mécanismes d'alertes et de protections ! @@ -1052,6 +1067,7 @@ settings.net.creationDateColumn=Établi settings.net.connectionTypeColumn=In/Out settings.net.sentDataLabel=Sent data statistics settings.net.receivedDataLabel=Received data statistics +settings.net.chainHeightLabel=Latest BTC block height settings.net.roundTripTimeColumn=Roundtrip settings.net.sentBytesColumn=Envoyé settings.net.receivedBytesColumn=Reçu @@ -1066,6 +1082,7 @@ settings.net.needRestart=Vous devez redémarrer l'application pour appliquer cet settings.net.notKnownYet=Pas encore connu... settings.net.sentData=Sent data: {0}, {1} messages, {2} messages/sec settings.net.receivedData=Received data: {0}, {1} messages, {2} messages/sec +settings.net.chainHeight=Bisq: {0} | Peers: {1} settings.net.ips=[IP address:port | host name:port | onion address:port] (séparés par des virgules). Le port peut être ignoré si utilisé par défaut (8333). settings.net.seedNode=Seed node settings.net.directPeer=Pair (direct) @@ -1074,7 +1091,7 @@ settings.net.inbound=inbound settings.net.outbound=outbound settings.net.reSyncSPVChainLabel=Resynchronisation de la chaîne SPV settings.net.reSyncSPVChainButton=Supprimer le fichier SPV et resynchroniser -settings.net.reSyncSPVSuccess=Le fichier de la chaîne SPV sera supprimé au prochain démarrage. Vous devez redémarrer votre application maintenant.\n\nAprès le redémarrage, la resynchronisation avec le réseau peut prendre un certain temps, vous serez en mesure de voir toutes les transactions seulement une fois que la resynchronisation sera terminée.\n\nSelon le nombre de transactions et l"ancienneté de votre portefeuille, la resynchronisation peut prendre jusqu"à quelques heures et consomme 100% du CPU. N'interrompez pas le processus, sinon vous devez le recommencer. +settings.net.reSyncSPVSuccess=Are you sure you want to do an SPV resync? If you proceed, the SPV chain file will be deleted on the next startup.\n\nAfter the restart it can take a while to resync with the network and you will only see all transactions once the resync is completed.\n\nDepending on the number of transactions and the age of your wallet the resync can take up to a few hours and consumes 100% of CPU. Do not interrupt the process otherwise you have to repeat it. settings.net.reSyncSPVAfterRestart=Le fichier de la chaîne SPV a été supprimé. Veuillez s'il vous plaît patienter. La resynchronisation avec le réseau peut nécessiter un certain temps. settings.net.reSyncSPVAfterRestartCompleted=La resynchronisation est maintenant terminée. Veuillez redémarrer l'application. settings.net.reSyncSPVFailed=Impossible de supprimer le fichier de la chaîne SPV.\nErreur: {0} @@ -1146,7 +1163,7 @@ setting.about.shortcuts.sendPrivateNotification=Envoyer une notification privée setting.about.shortcuts.sendPrivateNotification.value=Open peer info at avatar and press: {0} setting.info.headline=New XMR auto-confirm Feature -setting.info.msg=When selling BTC for XMR you can use the auto-confirm feature to verify that the correct amount of XMR was sent to your wallet so that Bisq can automatically mark the trade as complete, making trades quicker for everyone.\n\nAuto-confirm checks the XMR transaction on at least 2 XMR explorer nodes using the private transaction key provided by the XMR sender. By default, Bisq uses explorer nodes run by Bisq contributors, but we recommend running your own XMR explorer node for maximum privacy and security.\n\nYou can also set the maximum amount of BTC per trade to auto-confirm as well as the number of required confirmations here in Settings.\n\nSee more details (including how to set up your own explorer node) on the Bisq wiki [HYPERLINK:https://bisq.wiki/Trading_Monero#Auto-confirming_trades] +setting.info.msg=Vous n'avez pas saisi l'ID et la clé de transaction. \n\nSi vous ne fournissez pas ces données, votre partenaire commercial ne peut pas utiliser la fonction de confirmation automatique pour libérer rapidement le BTC après avoir reçu le XMR.\nEn outre, Bisq demande aux expéditeurs XMR de fournir ces informations aux médiateurs et aux arbitres en cas de litige.\nPlus de détails sont dans Bisq Wiki: [HYPERLINK:https://bisq.wiki/Trading_Monero#Auto-confirming_trades] #################################################################### # Account #################################################################### @@ -1161,9 +1178,19 @@ account.menu.paymentAccount=Comptes en devise nationale account.menu.altCoinsAccountView=Compte Altcoins account.menu.password=Mot de passe du portefeuille account.menu.seedWords=Seed du portefeuille +account.menu.walletInfo=Wallet info account.menu.backup=Sauvegarde account.menu.notifications=Notifications +account.menu.walletInfo.balance.headLine=Wallet balances +account.menu.walletInfo.balance.info=This shows the internal wallet balance including unconfirmed transactions.\nFor BTC, the internal wallet balance shown below should match the sum of the 'Available' and 'Reserved' balances shown in the top right of this window. +account.menu.walletInfo.xpub.headLine=Watch keys (xpub keys) +account.menu.walletInfo.walletSelector={0} {1} wallet +account.menu.walletInfo.path.headLine=HD keychain paths +account.menu.walletInfo.path.info=If you import seed words into another wallet (like Electrum), you'll need to define the path. This should only be done in emergency cases when you lose access to the Bisq wallet and data directory.\nKeep in mind that spending funds from a non-Bisq wallet can bungle the internal Bisq data structures associated with the wallet data, which can lead to failed trades.\n\nNEVER send BSQ from a non-Bisq wallet, as it will probably lead to an invalid BSQ transaction and losing your BSQ. + +account.menu.walletInfo.openDetails=Show raw wallet details and private keys + ## TODO should we rename the following to a gereric name? account.arbitratorRegistration.pubKey=Clé publique @@ -1181,23 +1208,23 @@ account.altcoin.yourAltcoinAccounts=Vos comptes altcoin account.altcoin.popup.wallet.msg=Veuillez vous assurer que vous respectez les exigences relatives à l''utilisation des {0} portefeuilles, selon les conditions présentées sur la page {1} du site.\nL''utilisation des portefeuilles provenant de plateformes de trading centralisées où (a) vous ne contrôlez pas vos clés ou (b) qui ne disposent pas d''un portefeuille compatible est risquée : cela peut entraîner la perte des fonds échangés!\nLe médiateur et l''arbitre ne sont pas des spécialistes {2} et ne pourront pas intervenir dans ce cas. account.altcoin.popup.wallet.confirm=Je comprends et confirme que je sais quel portefeuille je dois utiliser. # suppress inspection "UnusedProperty" -account.altcoin.popup.upx.msg=Trading UPX on Bisq requires that you understand and fulfill the following requirements:\n\nFor sending UPX, you need to use either the official uPlexa GUI wallet or uPlexa CLI wallet with the store-tx-info flag enabled (default in new versions). Please be sure you can access the tx key as that would be required in case of a dispute.\nuplexa-wallet-cli (use the command get_tx_key)\nuplexa-wallet-gui (go to history tab and click on the (P) button for payment proof)\n\nAt normal block explorers the transfer is not verifiable.\n\nYou need to provide the arbitrator the following data in case of a dispute:\n- The tx private key\n- The transaction hash\n- The recipient's public address\n\nFailure to provide the above data, or if you used an incompatible wallet, will result in losing the dispute case. The UPX sender is responsible for providing verification of the UPX transfer to the arbitrator in case of a dispute.\n\nThere is no payment ID required, just the normal public address.\nIf you are not sure about that process visit uPlexa discord channel (https://discord.gg/vhdNSrV) or the uPlexa Telegram Chat (https://t.me/uplexaOfficial) to find more information. +account.altcoin.popup.upx.msg=Pour échanger UPX sur Bisq, vous devez comprendre et respecter les exigences suivantes: \n\nPour envoyer UPX, vous devez utiliser le portefeuille officiel UPXmA GUI ou le portefeuille UPXmA CLI avec le logo store-tx-info activé (valeur par défaut dans la nouvelle version) . Assurez-vous d'avoir accès à la clé tx, car elle est nécessaire dans l'état du litige. monero-wallet-cli (à l'aide de la commande get_Tx_key) monero-wallet-gui: sur la page Avancé> Preuve / Vérification. \n\nCes transactions ne sont pas vérifiables dans le navigateur blockchain ordinaire. \n\nEn cas de litige, vous devez fournir à l'arbitre les informations suivantes: \n\n- Clé privée Tx- hachage de transaction- adresse publique du destinataire \n\nSi vous ne fournissez pas les informations ci-dessus ou si vous utilisez un portefeuille incompatible, vous perdrez le litige. En cas de litige, l'expéditeur UPX est responsable de fournir la vérification du transfert UPX à l'arbitre. \n\nAucun paiement d'identité n'est requis, juste une adresse publique commune. \n\nSi vous n'êtes pas sûr du processus, veuillez visiter le canal UPXmA Discord (https://discord.gg/vhdNSrV) ou le groupe d'échanges Telegram (https://t.me/uplexaOfficial) pour plus d'informations. # suppress inspection "UnusedProperty" account.altcoin.popup.arq.msg=Le trading d'ARQ sur Bisq exige que vous compreniez et remplissiez les exigences suivantes:\n\nPour envoyer des ARQ, vous devez utiliser soit le portefeuille officiel ArQmA GUI soit le portefeuille ArQmA CLI avec le flag store-tx-info activé (par défaut dans les nouvelles versions). Veuillez vous assurer que vous pouvez accéder à la tx key car cela pourrait être nécessaire en cas de litige.\narqma-wallet-cli (utiliser la commande get_tx_key)\narqma-wallet-gui (allez dans l'onglet historique et cliquez sur le bouton (P) pour accéder à la preuve de paiement).\n\nAvec un l'explorateur de bloc normal, le transfert n'est pas vérifiable.\n\nVous devez fournir au médiateur ou à l'arbitre les données suivantes en cas de litige:\n- Le tx de la clé privée\n- Le hash de la transaction\n- L'adresse publique du destinataire\n\nSi vous manquez de communiquer les données ci-dessus ou si vous utilisez un portefeuille incompatible, vous perdrez le litige. L'expéditeur des ARQ est responsable de la transmission au médiateur ou à l'arbitre de la vérification du transfert ces informations relatives au litige.\n\nIl n'est pas nécessaire de fournir l'ID du paiement, seulement l'adresse publique normale.\nSi vous n'êtes pas sûr de ce processus, visitez le canal discord ArQmA (https://discord.gg/s9BQpJT) ou le forum ArQmA (https://labs.arqma.com) pour obtenir plus d'informations. # suppress inspection "UnusedProperty" -account.altcoin.popup.xmr.msg=Trading XMR on Bisq requires that you understand the following requirement.\n\nIf selling XMR, you must be able to provide the following information to a mediator or arbitrator in case of a dispute:\n- the transaction key (Tx Key, Tx Secret Key or Tx Private Key)\n- the transaction ID (Tx ID or Tx Hash)\n- the destination address (recipient's address)\n\nSee the wiki for details on where to find this information on popular Monero wallets [HYPERLINK:https://bisq.wiki/Trading_Monero#Proving_payments].\nFailure to provide the required transaction data will result in losing disputes.\n\nAlso note that Bisq now offers automatic confirming for XMR transactions to make trades quicker, but you need to enable it in Settings.\n\nSee the wiki for more information about the auto-confirm feature: [HYPERLINK:https://bisq.wiki/Trading_Monero#Auto-confirming_trades]. +account.altcoin.popup.xmr.msg=Pour échanger XMR sur Bisq, vous devez comprendre et respecter les exigences suivantes: \n\nSi vous vendez XMR, en cas de litige, vous devez fournir au médiateur ou à l'arbitre les informations suivantes: - clé de transaction (clé publique Tx, clé Tx, clé privée Tx) - ID de transaction (ID Tx Ou hachage Tx) - Adresse de destination de la transaction (adresse du destinataire) \n\nConsultez plus d'informations sur le portefeuille Monero dans le wiki: https: //bisq.wiki/Trading_Monero#Proving_payments \n\nSi vous ne fournissez pas les données de transaction requises, vous serez directement jugé échoue dans le litige. \n\nNotez également que Bisq fournit désormais la fonction de confirmation automatique des transactions XMR pour effectuer plus rapidement des transactions, mais vous devez l'activer dans les paramètres. \n\nPour plus d'informations sur la fonction de confirmation automatique, veuillez consulter le Wiki: [HYPERLINK:https://bisq.wiki/Trading_Monero#Auto-confirming_trades] # suppress inspection "UnusedProperty" -account.altcoin.popup.msr.msg=Trading MSR on Bisq requires that you understand and fulfill the following requirements:\n\nFor sending MSR, you need to use either the official Masari GUI wallet, Masari CLI wallet with the store-tx-info flag enabled (enabled by default) or the Masari web wallet (https://wallet.getmasari.org). Please be sure you can access the tx key as that would be required in case of a dispute.\nmasari-wallet-cli (use the command get_tx_key)\nmasari-wallet-gui (go to history tab and click on the (P) button for payment proof)\n\nMasari Web Wallet (goto Account -> transaction history and view details on your sent transaction)\n\nVerification can be accomplished in-wallet.\nmasari-wallet-cli : using command (check_tx_key).\nmasari-wallet-gui : on the Advanced > Prove/Check page.\nVerification can be accomplished in the block explorer \nOpen block explorer (https://explorer.getmasari.org), use the search bar to find your transaction hash.\nOnce transaction is found, scroll to bottom to the 'Prove Sending' area and fill in details as needed.\nYou need to provide the mediator or arbitrator the following data in case of a dispute:\n- The tx private key\n- The transaction hash\n- The recipient's public address\n\nFailure to provide the above data, or if you used an incompatible wallet, will result in losing the dispute case. The MSR sender is responsible for providing verification of the MSR transfer to the mediator or arbitrator in case of a dispute.\n\nThere is no payment ID required, just the normal public address.\nIf you are not sure about that process, ask for help on the Official Masari Discord (https://discord.gg/sMCwMqs). +account.altcoin.popup.msr.msg=Le navigateur blockchain pour échanger MSR sur Bisq vous oblige à comprendre et à respecter les exigences suivantes: \n\nLors de l'envoi de MSR, vous devez utiliser le portefeuille officiel Masari GUI, le portefeuille Masari CLI avec le logo store-tx-info activé (activé par défaut) ou le portefeuille web Masari (https://wallet.getmasari.org). Assurez-vous d'avoir accès à la clé tx, car cela est nécessaire en cas de litige. monero-wallet-cli (à l'aide de la commande get_Tx_key) monero-wallet-gui: sur la page Avancé> Preuve / Vérification. \n\nLe portefeuille web Masari (accédez à Compte-> Historique des transactions et vérifiez les détails de la transaction que vous avez envoyés) \n\nLa vérification peut être effectuée dans le portefeuille. monero-wallet-cli: utilisez la commande (check_tx_key). monero-wallet-gui: sur la page Avancé> Preuve / Vérification La vérification peut être effectuée dans le navigateur blockchain. Ouvrez le navigateur blockchain (https://explorer.getmasari.org) et utilisez la barre de recherche pour trouver votre hachage de transaction. Une fois que vous avez trouvé la transaction, faites défiler jusqu'à la zone «certificat à envoyer» en bas et remplissez les détails requis. En cas de litige, vous devez fournir les informations suivantes au médiateur ou à l'arbitre: - Clé privée Tx- Hachage de transaction- Adresse publique du destinataire \n\nAucun ID de transaction n'est requis, seule une adresse publique normale est requise. Si vous ne fournissez pas les informations ci-dessus ou si vous utilisez un portefeuille incompatible, vous perdrez le litige. En cas de litige, l'expéditeur XMR est responsable de fournir la vérification du transfert XMR au médiateur ou un arbitre. \n\nSi vous n'êtes pas sûr du processus, veuillez visiter le Masari Discord officiel (https://discord.gg/sMCwMqs) pour obtenir de l'aide. # suppress inspection "UnusedProperty" -account.altcoin.popup.blur.msg=Trading BLUR on Bisq requires that you understand and fulfill the following requirements:\n\nTo send BLUR you must use the Blur Network CLI or GUI Wallet. \n\nIf you are using the CLI wallet, a transaction hash (tx ID) will be displayed after a transfer is sent. You must save this information. Immediately after sending the transfer, you must use the command 'get_tx_key' to retrieve the transaction private key. If you fail to perform this step, you may not be able to retrieve the key later. \n\nIf you are using the Blur Network GUI Wallet, the transaction private key and transaction ID can be found conveniently in the "History" tab. Immediately after sending, locate the transaction of interest. Click the "?" symbol in the lower-right corner of the box containing the transaction. You must save this information. \n\nIn the event that arbitration is necessary, you must present the following to an mediator or arbitrator: 1.) the transaction ID, 2.) the transaction private key, and 3.) the recipient's address. The mediator or arbitrator will then verify the BLUR transfer using the Blur Transaction Viewer (https://blur.cash/#tx-viewer).\n\nFailure to provide the required information to the mediator or arbitrator will result in losing the dispute case. In all cases of dispute, the BLUR sender bears 100% of the burden of responsibility in verifying transactions to an mediator or arbitrator. \n\nIf you do not understand these requirements, do not trade on Bisq. First, seek help at the Blur Network Discord (https://discord.gg/dMWaqVW). +account.altcoin.popup.blur.msg=ntes: \n\nPour envoyer des informations anonymes, vous devez utiliser un portefeuille CLI ou GUI de réseau anonyme. Si vous utilisez un portefeuille CLI, le hachage de la transaction (tx ID) sera affiché après la transmission. Vous devez enregistrer ces informations. Après l'envoi de la transmission, vous devez immédiatement utiliser la commande «get_tx_key» pour récupérer la clé privée de la transaction. Si vous ne parvenez pas à effectuer cette étape, vous ne pourrez peut-être pas récupérer la clé ultérieurement. \n\nSi vous utilisez le portefeuille Blur Network GUI, vous pouvez facilement trouver la clé privée de transaction et l'ID de transaction dans l'onglet «Historique». Localisez la transaction d'intérêt immédiatement après l'envoi. Cliquez sur le symbole «?» dans le coin inférieur droit de la boîte contenant la transaction. Vous devez enregistrer ces informations. \n\nSi un arbitrage est nécessaire, vous devez fournir les informations suivantes au médiateur ou à l'arbitre: 1.) ID de transaction, 2.) clé privée de transaction, 3.) adresse du destinataire. Le processus de médiation ou d'arbitrage utilisera le visualiseur de transactions BLUR (https://blur.cash/#tx-viewer) pour vérifier les transferts BLUR. \n\nLe défaut de fournir les informations nécessaires au médiateur ou à l'arbitre entraînera la perte du litige. Dans tous les litiges, l'expéditeur anonyme porte à 100% la responsabilité de vérifier la transaction avec le médiateur ou l'arbitre. \n\nSi vous ne comprenez pas ces exigences, n'échangez pas sur Bisq. Tout d'abord, demandez de l'aide dans Blur Network Discord (https://discord.gg/dMWaqVW). # suppress inspection "UnusedProperty" -account.altcoin.popup.solo.msg=Trading Solo on Bisq requires that you understand and fulfill the following requirements:\n\nTo send Solo you must use the Solo Network CLI Wallet. \n\nIf you are using the CLI wallet, a transaction hash (tx ID) will be displayed after a transfer is sent. You must save this information. Immediately after sending the transfer, you must use the command 'get_tx_key' to retrieve the transaction private key. If you fail to perform this step, you may not be able to retrieve the key later. \n\nIn the event that arbitration is necessary, you must present the following to an mediator or arbitrator: 1.) the transaction ID, 2.) the transaction private key, and 3.) the recipient's address. The mediator or arbitrator will then verify the Solo transfer using the Solo Block Explorer by searching for the transaction and then using the "Prove sending" function (https://explorer.minesolo.com/).\n\nfailure to provide the required information to the mediator or arbitrator will result in losing the dispute case. In all cases of dispute, the Solo sender bears 100% of the burden of responsibility in verifying transactions to an mediator or arbitrator. \n\nIf you do not understand these requirements, do not trade on Bisq. First, seek help at the Solo Network Discord (https://discord.minesolo.com/). +account.altcoin.popup.solo.msg=Echanger Solo sur Bisq nécessite que vous compreniez et remplissiez les conditions suivantes: \n\nPour envoyer Solo, vous devez utiliser la version 5.1.3 ou supérieure du portefeuille Web Solo CLI. \n\nSi vous utilisez un portefeuille CLI, après l'envoi de la transaction, ID de transaction sera affiché. Vous devez enregistrer ces informations. Après avoir envoyé la transaction, vous devez immédiatement utiliser la commande «get_tx_key» pour récupérer la clé de transaction. Si vous ne parvenez pas à effectuer cette étape, vous ne pourrez peut-être pas récupérer la clé ultérieurement. \n\nSi un arbitrage est nécessaire, vous devez fournir les informations suivantes au médiateur ou à l'arbitre: 1) ID de transaction, 2) clé de transaction, 3) adresse du destinataire. Le médiateur ou l'arbitre utilisera l’explorateur de blocs Solo (https://explorer.Solo.org) pour rechercher des transactions puis utilisera la fonction «envoyer une preuve» (https://explorer.minesolo.com/). \n\nLe défaut de fournir les informations nécessaires au médiateur ou à l'arbitre entraînera la perte de l'affaire. Dans tous les cas de litige, l'expéditeur de QWC assume à 100% la responsabilité lors de la vérification de la transaction avec le médiateur ou l'arbitre. \n\nSi vous ne comprenez pas ces exigences, n'échangez pas sur Bisq. Tout d'abord, demandez de l'aide dans Solo Discord (https://discord.minesolo.com/). # suppress inspection "UnusedProperty" -account.altcoin.popup.cash2.msg=Trading CASH2 on Bisq requires that you understand and fulfill the following requirements:\n\nTo send CASH2 you must use the Cash2 Wallet version 3 or higher. \n\nAfter a transaction is sent, the transaction ID will be displayed. You must save this information. Immediately after sending the transaction, you must use the command 'getTxKey' in simplewallet to retrieve the transaction secret key. \n\nIn the event that arbitration is necessary, you must present the following to an mediator or arbitrator: 1) the transaction ID, 2) the transaction secret key, and 3) the recipient's Cash2 address. The mediator or arbitrator will then verify the CASH2 transfer using the Cash2 Block Explorer (https://blocks.cash2.org).\n\nFailure to provide the required information to the mediator or arbitrator will result in losing the dispute case. In all cases of dispute, the CASH2 sender bears 100% of the burden of responsibility in verifying transactions to an mediator or arbitrator. \n\nIf you do not understand these requirements, do not trade on Bisq. First, seek help at the Cash2 Discord (https://discord.gg/FGfXAYN). +account.altcoin.popup.cash2.msg=Pour échanger CASH2 sur Bisq, vous devez comprendre et respecter les exigences suivantes: \n\nPour envoyer CASH2, vous devez utiliser la version 3 ou supérieure du portefeuille CASH2. \n\nAprès l'envoi de la transaction, ID de la transaction s'affiche. Vous devez enregistrer ces informations. Après avoir envoyé la transaction, vous devez utiliser la commande «getTxKey» dans simplewallet pour récupérer immédiatement la clé de transaction.\n\nSi un arbitrage est nécessaire, vous devez fournir les informations suivantes au médiateur ou à l'arbitre: 1) ID de transaction, 2) clé de transaction, 3) adresse CASH2 du destinataire. Le médiateur ou l'arbitre utilisera l’explorateur de blocs CASH2 (https://blocks.cash2.org) pour vérifier le transfert CASH2. \n\nLe défaut de fournir les informations nécessaires au médiateur ou à l'arbitre entraînera la perte de l'affaire. Dans tous les cas de litige, l'expéditeur de CASH2 assume à 100% la responsabilité lors de la vérification de la transaction avec le médiateur ou l'arbitre. \n\nSi vous ne comprenez pas ces exigences, n'échangez pas sur Bisq. Tout d'abord, demandez de l'aide dans le Discord Cash2 (https://discord.gg/FGfXAYN). # suppress inspection "UnusedProperty" -account.altcoin.popup.qwertycoin.msg=Trading Qwertycoin on Bisq requires that you understand and fulfill the following requirements:\n\nTo send QWC you must use the official QWC Wallet version 5.1.3 or higher. \n\nAfter a transaction is sent, the transaction ID will be displayed. You must save this information. Immediately after sending the transaction, you must use the command 'get_Tx_Key' in simplewallet to retrieve the transaction secret key. \n\nIn the event that arbitration is necessary, you must present the following to an mediator or arbitrator: 1) the transaction ID, 2) the transaction secret key, and 3) the recipient's QWC address. The mediator or arbitrator will then verify the QWC transfer using the QWC Block Explorer (https://explorer.qwertycoin.org).\n\nFailure to provide the required information to the mediator or arbitrator will result in losing the dispute case. In all cases of dispute, the QWC sender bears 100% of the burden of responsibility in verifying transactions to an mediator or arbitrator. \n\nIf you do not understand these requirements, do not trade on Bisq. First, seek help at the QWC Discord (https://discord.gg/rUkfnpC). +account.altcoin.popup.qwertycoin.msg=Pour échanger Qwertycoin sur Bisq, vous devez comprendre et respecter les exigences suivantes: \n\nPour envoyer Qwertycoin, vous devez utiliser la version 5.1.3 ou supérieure du portefeuille Qwertycoin. \n\nAprès l'envoi de la transaction, ID de la transaction s'affiche. Vous devez enregistrer ces informations. Après avoir envoyé la transaction, vous devez utiliser la commande «get_Tx_Key» dans simplewallet pour récupérer immédiatement la clé de transaction. \n\nSi un arbitrage est nécessaire, vous devez fournir les informations suivantes au médiateur ou à l'arbitre: 1) ID de transaction, 2) clé de transaction, 3) adresse QWC du destinataire. Le médiateur ou l'arbitre utilisera l’explorateur de blocs QWC (https://explorer.qwertycoin.org) pour vérifier les transferts QWC. \n\nLe défaut de fournir les informations nécessaires au médiateur ou à l'arbitre entraînera la perte de l'affaire. Dans tous les cas de litige, l'expéditeur de QWC assume à 100% la responsabilité lors de la vérification de la transaction avec le médiateur ou l'arbitre. \n\nSi vous ne comprenez pas ces exigences, n'échangez pas sur Bisq. Tout d'abord, demandez de l'aide dans QWC Discord (https://discord.gg/rUkfnpC). # suppress inspection "UnusedProperty" -account.altcoin.popup.drgl.msg=Trading Dragonglass on Bisq requires that you understand and fulfill the following requirements:\n\nBecause of the privacy Dragonglass provides, a transaction is not verifiable on the public blockchain. If required, you can prove your payment through the use of your TXN-Private-Key.\nThe TXN-Private Key is a one-time key automatically generated for every transaction that can only be accessed from within your DRGL wallet.\nEither by DRGL-wallet GUI (inside transaction details dialog) or by the Dragonglass CLI simplewallet (using command "get_tx_key").\n\nDRGL version 'Oathkeeper' and higher are REQUIRED for both.\n\nIn case of a dispute, you must provide the mediator or arbitrator the following data:\n- The TXN-Private key\n- The transaction hash\n- The recipient's public address\n\nVerification of payment can be made using the above data as inputs at (http://drgl.info/#check_txn).\n\nFailure to provide the above data, or if you used an incompatible wallet, will result in losing the dispute case. The Dragonglass sender is responsible for providing verification of the DRGL transfer to the mediator or arbitrator in case of a dispute. Use of PaymentID is not required.\n\nIf you are unsure about any part of this process, visit Dragonglass on Discord (http://discord.drgl.info) for help. +account.altcoin.popup.drgl.msg=Echanger Dragonglass sur Bisq vous oblige à comprendre et à respecter les exigences suivantes: ~\n\nComme Dragonglass offre une protection de la confidentialité, les transactions ne peuvent pas être vérifiées sur la blockchain publique. Si nécessaire, vous pouvez prouver votre paiement en utilisant votre TXN-Private-Key. TXN-Private est une clé d'un temps générée automatiquement, utilisée pour chaque transaction qui est accessible uniquement à partir du portefeuille DESP. Soit via DRGL-wallet GUI (boîte de dialogue des détails de transaction interne), soit via Dragonglass CLI simplewallet (en utilisant la commande "get_tx_key"). \n\nLes deux nécessitent la version DRGL de «Oathkeeper» ou supérieure. \n\nEn cas de litige, vous devez fournir les informations suivantes au médiateur ou à l'arbitre: \n\n- txn-Privite-ket- hachage de transaction- adresse publique du destinataire ~\n\nLa vérification du paiement peut utiliser les données ci-dessus comme entrée (http://drgl.info/#check_txn).\n\nSi vous ne fournissez pas les informations ci-dessus ou si vous utilisez un portefeuille incompatible, vous perdrez le litige. L'expéditeur Dragonglass est responsable de fournir la vérification de transfert DRGL au médiateur ou à l'arbitre en cas de litige. Aucun ID de paiement n'est requis. \n\nSi vous n'êtes pas sûr d'une partie de ce processus, veuillez visiter Dragonglass sur (http://discord.drgl.info) pour obtenir de l'aide. # suppress inspection "UnusedProperty" account.altcoin.popup.ZEC.msg=Lors de l'utilisation de Zcash, vous ne pouvez utiliser que les adresses transparentes (commençant par t), et non les z-adresses (privées), car le médiateur ou l'arbitre ne seraient pas en mesure de vérifier la transaction avec les z-adresses. # suppress inspection "UnusedProperty" @@ -1207,13 +1234,13 @@ account.altcoin.popup.grin.msg=GRIN nécessite un échange interactif entre l'é # suppress inspection "UnusedProperty" account.altcoin.popup.beam.msg=BEAM nécessite un processus interactif entre l'émetteur et le récepteur pour créer la transaction.\n\nAssurez-vous de suivre les instructions de la page Web du projet BEAM pour envoyer et recevoir les BEAM de façon fiable (le récepteur doit être en ligne pendant au moins un certain temps).\n\nL'expéditeur de BEAM est tenu de fournir la preuve qu'il a envoyé BEAM avec succès. Assurez-vous d'utiliser un portefeuille qui peut produire une telle preuve. Si le portefeuille ne peut fournir la preuve, un litige potentiel sera résolu en faveur du récepteur des BEAM. # suppress inspection "UnusedProperty" -account.altcoin.popup.pars.msg=Trading ParsiCoin on Bisq requires that you understand and fulfill the following requirements:\n\nTo send PARS you must use the official ParsiCoin Wallet version 3.0.0 or higher. \n\nYou can Check your Transaction Hash and Transaction Key on Transactions Section on your GUI Wallet (ParsiPay) You need to right Click on the Transaction and then click on show details. \n\nIn the event that arbitration is necessary, you must present the following to an mediator or arbitrator: 1) the Transaction Hash, 2) the Transaction Key, and 3) the recipient's PARS address. The mediator or arbitrator will then verify the PARS transfer using the ParsiCoin Block Explorer (http://explorer.parsicoin.net/#check_payment).\n\nFailure to provide the required information to the mediator or arbitrator will result in losing the dispute case. In all cases of dispute, the ParsiCoin sender bears 100% of the burden of responsibility in verifying transactions to an mediator or arbitrator. \n\nIf you do not understand these requirements, do not trade on Bisq. First, seek help at the ParsiCoin Discord (https://discord.gg/c7qmFNh). +account.altcoin.popup.pars.msg=Echanger ParsiCoin sur Bisq nécessite que vous compreniez et remplissiez les conditions suivantes: \n\nPour envoyer PARS, vous devez utiliser la version 3.0.0 ou supérieure du portefeuille ParsiCoin officiel. \n\nVous pouvez vérifier votre hachage de transaction et votre clé de transaction dans la section transaction du portefeuille GUI (ParsiPay). Vous devez cliquer avec le bouton droit de la souris sur «Transaction» puis cliquer sur «Afficher les détails». \n\nSi l'arbitrage est à 100% nécessaire, vous devez fournir au médiateur ou à l'arbitre les éléments suivants: 1) hachage de transaction, 2) clé de transaction et 3) adresse PARS du destinataire. Le médiateur ou l'arbitre utilisera l’explorateur de blocs ParsiCoin (http://explorer.parsicoin.net/#check_payment) pour vérifier les transmissions PARS. \n\nSi vous ne comprenez pas ces exigences, n'échangez pas sur Bisq. Tout d'abord, demandez de l'aide sur le ParsiCoin Discord (https://discord.gg/c7qmFNh). # suppress inspection "UnusedProperty" -account.altcoin.popup.blk-burnt.msg=To trade burnt blackcoins, you need to know the following:\n\nBurnt blackcoins are unspendable. To trade them on Bisq, output scripts need to be in the form: OP_RETURN OP_PUSHDATA, followed by associated data bytes which, after being hex-encoded, constitute addresses. For example, burnt blackcoins with an address 666f6f (“foo” in UTF-8) will have the following script:\n\nOP_RETURN OP_PUSHDATA 666f6f\n\nTo create burnt blackcoins, one may use the “burn” RPC command available in some wallets.\n\nFor possible use cases, one may look at https://ibo.laboratorium.ee .\n\nAs burnt blackcoins are unspendable, they can not be reselled. “Selling” burnt blackcoins means burning ordinary blackcoins (with associated data equal to the destination address).\n\nIn case of a dispute, the BLK seller needs to provide the transaction hash. +account.altcoin.popup.blk-burnt.msg=Pour échanger les monnaies brûlées, vous devez savoir ce qui suit: \n\nLes monnaies brûlées ne peuvent pas être dépensée. Pour les échanger sur Bisq, le script de sortie doit prendre la forme suivante: OP_RETURN OP_PUSHDATA, suivi des octets de données pertinents, ces octets forment l'adresse après le codage hexadécimal. Par exemple, une devise brûlée avec l'adresse 666f6f ("foo" en UTF-8) aura le script suivant: \n\nOP_RETURN OP_PUSHDATA 666f6f \n\nPour créer de la monnaie brûlée, vous pouvez utiliser la commande RPC «brûler», disponible dans certains portefeuilles. \n\nPour d'éventuelles situations, vous pouvez vérifier https://ibo.laboratorium.ee \n\nPuisque la monnaie brûlée ne peut pas être utilisée, elle ne peut pas être revendue. «Vendre» une devise brûlée signifie brûler la devise d'origine (données associées à l'adresse de destination). \n\nEn cas de litige, le vendeur BLK doit fournir le hachage de la transaction. # suppress inspection "UnusedProperty" -account.altcoin.popup.liquidbitcoin.msg=Trading L-BTC on Bisq requires that you understand the following:\n\nWhen receiving L-BTC for a trade on Bisq, you cannot use the mobile Blockstream Green Wallet app or a custodial/exchange wallet. You must only receive L-BTC into the Liquid Elements Core wallet, or another L-BTC wallet which allows you to obtain the blinding key for your blinded L-BTC address.\n\nIn the event mediation is necessary, or if a trade dispute arises, you must disclose the blinding key for your receiving L-BTC address to the Bisq mediator or refund agent so they can verify the details of your Confidential Transaction on their own Elements Core full node.\n\nFailure to provide the required information to the mediator or refund agent will result in losing the dispute case. In all cases of dispute, the L-BTC receiver bears 100% of the burden of responsibility in providing cryptographic proof to the mediator or refund agent.\n\nIf you do not understand these requirements, do not trade L-BTC on Bisq. +account.altcoin.popup.liquidbitcoin.msg=Pour échanger L-BTC sur Bisq, vous devez comprendre les termes suivants: \n\nLorsque vous acceptez des transactions L-BTC sur Bisq, vous ne pouvez pas utiliser Blockstream Green Wallet sur le téléphone mobile ou un portefeuille de dépôt / commercial. Vous ne devez recevoir du L-BTC que dans le portefeuille Liquid Elements Core ou un autre portefeuille L-BTC avec une adresse L-BTC et une clé de sécurité qui vous permettre d'être anonyme. \n\nEn cas de médiation ou en cas de litige de transaction, vous devez divulguer la clé de sécurité de l'adresse L-BTC au médiateur Bisq ou à l'agent de remboursement afin qu'ils puissent vérifier les détails de votre transaction anonyme sur leur propre nœud complet Elements Core. \n\nSi vous ne comprenez pas ou ne comprenez pas ces exigences, n'échangez pas de L-BTC sur Bisq. account.fiat.yourFiatAccounts=Vos comptes en devise nationale @@ -1235,7 +1262,7 @@ account.password.info=Avec la protection par mot de passe, vous devrez entrer vo account.seed.backup.title=Sauvegarder les mots composant la seed de votre portefeuille account.seed.info=Veuillez noter les mots de la seed du portefeuille ainsi que la date! Vous pouvez récupérer votre portefeuille à tout moment avec les mots de la seed et la date.\nLes mêmes mots-clés de la seed sont utilisés pour les portefeuilles BTC et BSQ.\n\nVous devriez écrire les mots de la seed sur une feuille de papier. Ne les enregistrez pas sur votre ordinateur.\n\nVeuillez noter que les mots de la seed ne remplacent PAS une sauvegarde.\nVous devez créer une sauvegarde de l'intégralité du répertoire de l'application à partir de l'écran \"Compte/Sauvergarde\" pour restaurer correctement les données de l'application.\nL'importation de mots de la seed n'est recommandée qu'en cas d'urgence. L'application ne sera pas fonctionnelle sans une sauvegarde adéquate des fichiers et des clés de la base de données ! -account.seed.backup.warning=Please note that the seed words are NOT a replacement for a backup.\nYou need to create a backup of the whole application directory from the \"Account/Backup\" screen to recover application state and data.\nImporting seed words is only recommended for emergency cases. The application will not be functional without a proper backup of the database files and keys!\n\nSee the wiki page [HYPERLINK:https://bisq.wiki/Backing_up_application_data] for extended info. +account.seed.backup.warning=Veuillez noter que les mots de départ ne peuvent pas remplacer les sauvegardes. Vous devez sauvegarder tout le répertoire de l'application (dans l'onglet «Compte / Sauvegarde») pour restaurer l'état et les données de l'application. L'importation de mots de départ n'est recommandée qu'en cas d'urgence. Si le fichier de base de données et la clé ne sont pas correctement sauvegardés, l'application ne fonctionnera pas! \n\nVoir plus d'informations sur le wiki Bisq: [HYPERLINK:https://bisq.wiki/Backing_up_application_data] account.seed.warn.noPw.msg=Vous n'avez pas configuré un mot de passe de portefeuille qui protégerait l'affichage des mots composant la seed.\n\nVoulez-vous afficher les mots composant la seed? account.seed.warn.noPw.yes=Oui, et ne me le demander plus à l'avenir account.seed.enterPw=Entrer le mot de passe afficher les mots composant la seed @@ -1796,7 +1823,7 @@ dao.wallet.send.setDestinationAddress=Remplissez votre adresse de destination dao.wallet.send.send=Envoyer des fonds en BSQ dao.wallet.send.sendBtc=Envoyer des fonds en BTC dao.wallet.send.sendFunds.headline=Confirmer la demande de retrait -dao.wallet.send.sendFunds.details=Sending: {0}\nTo receiving address: {1}.\nRequired transaction fee is: {2} ({3} satoshis/vbyte)\nTransaction vsize: {4} vKb\n\nThe recipient will receive: {5}\n\nAre you sure you want to withdraw that amount? +dao.wallet.send.sendFunds.details=Sending: {0}\nTo receiving address: {1}.\nRequired mining fee is: {2} ({3} satoshis/vbyte)\nTransaction vsize: {4} vKb\n\nThe recipient will receive: {5}\n\nAre you sure you want to withdraw that amount? dao.wallet.chainHeightSynced=Dernier bloc vérifié: {0} dao.wallet.chainHeightSyncing=En attente des blocs.... {0} Blocs vérifiés sur {1}. dao.wallet.tx.type=Type @@ -1928,9 +1955,9 @@ dao.factsAndFigures.menuItem.transactions=Transactions BSQ dao.factsAndFigures.dashboard.avgPrice90=Moyenne sur 90 jours du prix d'échange BSQ/BTC dao.factsAndFigures.dashboard.avgPrice30=Moyenne sur 30 jours du prix d'échange BSQ/BTC -dao.factsAndFigures.dashboard.avgUSDPrice90=90 days volume weighted average USD/BSQ trade price -dao.factsAndFigures.dashboard.avgUSDPrice30=30 days volume weighted average USD/BSQ trade price -dao.factsAndFigures.dashboard.marketCap=Capitalisation boursière (basé sur la valeur d'échange) +dao.factsAndFigures.dashboard.avgUSDPrice90=90 days volume weighted average USD/BSQ price +dao.factsAndFigures.dashboard.avgUSDPrice30=30 days volume weighted average USD/BSQ price +dao.factsAndFigures.dashboard.marketCap=Market capitalisation (based on 30 days average USD/BSQ price) dao.factsAndFigures.dashboard.availableAmount=BSQ disponible au total dao.factsAndFigures.supply.issuedVsBurnt=BSQ issued v. BSQ burnt @@ -1989,9 +2016,9 @@ displayUpdateDownloadWindow.button.downloadLater=Télécharger plus tard displayUpdateDownloadWindow.button.ignoreDownload=Ignorer cette version displayUpdateDownloadWindow.headline=Une nouvelle mise à jour Bisq est disponible ! displayUpdateDownloadWindow.download.failed.headline=Echec du téléchargement -displayUpdateDownloadWindow.download.failed=Download failed.\nPlease download and verify manually at [HYPERLINK:https://bisq.network/downloads] -displayUpdateDownloadWindow.installer.failed=Unable to determine the correct installer. Please download and verify manually at [HYPERLINK:https://bisq.network/downloads] -displayUpdateDownloadWindow.verify.failed=Verification failed.\nPlease download and verify manually at [HYPERLINK:https://bisq.network/downloads] +displayUpdateDownloadWindow.download.failed=Téléchargement échoué. Veuillez télécharger et vérifier via [HYPERLINK:https://bisq.network/downloads] +displayUpdateDownloadWindow.installer.failed=Impossible de déterminer le bon programme d'installation. Veuillez télécharger et vérifier manuellement via [HYPERLINK:https://bisq.network/downloads] . +displayUpdateDownloadWindow.verify.failed=Vérification échouée. Veuillez télécharger et vérifier manuellement via [HYPERLINK:https://bisq.network/downloads] displayUpdateDownloadWindow.success=La nouvelle version a été téléchargée avec succès et la signature vérifiée.\n\nVeuillez ouvrir le répertoire de téléchargement, fermer l'application et installer la nouvelle version. displayUpdateDownloadWindow.download.openDir=Ouvrir le répertoire de téléchargement @@ -2000,7 +2027,7 @@ disputeSummaryWindow.openDate=Date d'ouverture du ticket disputeSummaryWindow.role=Rôle du trader disputeSummaryWindow.payout=Versement du montant de l'opération disputeSummaryWindow.payout.getsTradeAmount=BTC {0} obtient le montant du versement de la transaction -disputeSummaryWindow.payout.getsAll=BTC {0} à reçu l''intégralité +disputeSummaryWindow.payout.getsAll=Max. payout to BTC {0} disputeSummaryWindow.payout.custom=Versement personnalisé disputeSummaryWindow.payoutAmount.buyer=Montant du versement de l'acheteur disputeSummaryWindow.payoutAmount.seller=Montant du versement au vendeur @@ -2023,15 +2050,15 @@ disputeSummaryWindow.reason.OTHER=Autre # suppress inspection "UnusedProperty" disputeSummaryWindow.reason.BANK_PROBLEMS=Banque # suppress inspection "UnusedProperty" -disputeSummaryWindow.reason.OPTION_TRADE=Option trade +disputeSummaryWindow.reason.OPTION_TRADE=Transaction facultative # suppress inspection "UnusedProperty" -disputeSummaryWindow.reason.SELLER_NOT_RESPONDING=Seller not responding +disputeSummaryWindow.reason.SELLER_NOT_RESPONDING=Le vendeur n'a pas répondu. # suppress inspection "UnusedProperty" -disputeSummaryWindow.reason.WRONG_SENDER_ACCOUNT=Wrong sender account +disputeSummaryWindow.reason.WRONG_SENDER_ACCOUNT=Mauvais compte d'expéditeur # suppress inspection "UnusedProperty" -disputeSummaryWindow.reason.PEER_WAS_LATE=Peer was late +disputeSummaryWindow.reason.PEER_WAS_LATE=Le partenaire commercial a expiré. # suppress inspection "UnusedProperty" -disputeSummaryWindow.reason.TRADE_ALREADY_SETTLED=Trade already settled +disputeSummaryWindow.reason.TRADE_ALREADY_SETTLED=La transaction s'est stabilisée. disputeSummaryWindow.summaryNotes=Notes de synthèse disputeSummaryWindow.addSummaryNotes=Ajouter des notes de synthèse @@ -2039,13 +2066,13 @@ disputeSummaryWindow.close.button=Fermer le ticket # Do no change any line break or order of tokens as the structure is used for signature verification # suppress inspection "TrailingSpacesInProperty" -disputeSummaryWindow.close.msg=Ticket closed on {0}\n{1} node address: {2}\n\nSummary:\nTrade ID: {3}\nCurrency: {4}\nTrade amount: {5}\nPayout amount for BTC buyer: {6}\nPayout amount for BTC seller: {7}\n\nReason for dispute: {8}\n\nSummary notes:\n{9}\n +disputeSummaryWindow.close.msg=Le ticket a été fermé {0}\n {1} Adresse du nœud: {2} \n\nRésumé: \nID de transaction: {3} \nMonnaie: {4} \n Montant de la transaction: {5} \nMontant du paiement de l'acheteur BTC: {6} \nMontant du paiement du vendeur BTC: {7} \n\nRaison du litige: {8} \n\nRésumé: {9} \n\n # Do no change any line break or order of tokens as the structure is used for signature verification disputeSummaryWindow.close.msgWithSig={0}{1}{2}{3} -disputeSummaryWindow.close.nextStepsForMediation=\nNext steps:\nOpen trade and accept or reject suggestion from mediator -disputeSummaryWindow.close.nextStepsForRefundAgentArbitration=\nNext steps:\nNo further action is required from you. If the arbitrator decided in your favor, you'll see a "Refund from arbitration" transaction in Funds/Transactions +disputeSummaryWindow.close.nextStepsForMediation=\n\nÉtape suivante:\nOuvrez la transaction inachevée, acceptez ou rejetez la suggestion du médiateur +disputeSummaryWindow.close.nextStepsForRefundAgentArbitration=\n\nÉtape suivante: \nAucune autre action n'est requise de votre part. Si l'arbitre rend une décision en votre faveur, vous verrez la transaction «Remboursement d'arbitrage» sur la page Fonds / Transactions disputeSummaryWindow.close.closePeer=Vous devez également clore le ticket des pairs de trading ! disputeSummaryWindow.close.txDetails.headline=Publier la transaction de remboursement # suppress inspection "TrailingSpacesInProperty" @@ -2054,8 +2081,8 @@ disputeSummaryWindow.close.txDetails.buyer=L''acheteur reçoit {0} à l''adresse disputeSummaryWindow.close.txDetails.seller=Le vendeur reçoit {0} à l''adresse: {1}\n disputeSummaryWindow.close.txDetails=Spending: {0}\n{1}{2}Transaction fee: {3} ({4} satoshis/vbyte)\nTransaction vsize: {5} vKb\n\nAre you sure you want to publish this transaction? -disputeSummaryWindow.close.noPayout.headline=Close without any payout -disputeSummaryWindow.close.noPayout.text=Do you want to close without doing any payout? +disputeSummaryWindow.close.noPayout.headline=Fermé sans paiement +disputeSummaryWindow.close.noPayout.text=Voulez-vous fermer sans paiement ? emptyWalletWindow.headline={0} Outil de secours du portefeuille emptyWalletWindow.info=Veuillez utiliser ceci qu'en cas d'urgence si vous ne pouvez pas accéder à vos fonds à partir de l'interface utilisateur.\n\nVeuillez remarquer que touts les ordres en attente seront automatiquement fermés lors de l'utilisation de cet outil.\n\nAvant d'utiliser cet outil, veuillez sauvegarder votre répertoire de données. Vous pouvez le faire sur \"Compte/sauvegarde\".\n\nVeuillez nous signaler votre problème et déposer un rapport de bug sur GitHub ou sur le forum Bisq afin que nous puissions enquêter sur la source du problème. @@ -2076,8 +2103,8 @@ filterWindow.onions=Adresses onion filtrées (virgule de sep.) filterWindow.accounts=Données filtrées du compte de trading:\nFormat: séparer par une virgule liste des [ID du mode de paiement | champ de données | valeur]. filterWindow.bannedCurrencies=Codes des devises filtrées (séparer avec une virgule.) filterWindow.bannedPaymentMethods=IDs des modes de paiements filtrés (séparer avec une virgule.) -filterWindow.bannedAccountWitnessSignerPubKeys=Filtered account witness signer pub keys (comma sep. hex of pub keys) -filterWindow.bannedPrivilegedDevPubKeys=Filtered privileged dev pub keys (comma sep. hex of pub keys) +filterWindow.bannedAccountWitnessSignerPubKeys=Clé publique filtrée du signataire du témoin de compte (clé publique hexadécimale séparée par des virgules) +filterWindow.bannedPrivilegedDevPubKeys=Clé publique filtrée de développeur privilégiée (clé publique hexadécimale séparée par des virgules) filterWindow.arbitrators=Arbitres filtrés (adresses onion séparées par une virgule) filterWindow.mediators=Médiateurs filtrés (adresses onion sep. par une virgule) filterWindow.refundAgents=Agents de remboursement filtrés (adresses onion sep. par virgule) @@ -2086,13 +2113,13 @@ filterWindow.priceRelayNode=Nœuds relais avec prix filtrés (adresses onion sé filterWindow.btcNode=Nœuds Bitcoin filtrés (adresses séparées par une virgule + port) filterWindow.preventPublicBtcNetwork=Empêcher l'utilisation du réseau public Bitcoin filterWindow.disableDao=Désactiver la DAO -filterWindow.disableAutoConf=Disable auto-confirm +filterWindow.disableAutoConf=Désactiver la confirmation automatique filterWindow.autoConfExplorers=Filtered auto-confirm explorers (comma sep. addresses) filterWindow.disableDaoBelowVersion=Version minimale requise pour la DAO filterWindow.disableTradeBelowVersion=Version min. nécessaire pour pouvoir échanger filterWindow.add=Ajouter le filtre filterWindow.remove=Retirer le filtre -filterWindow.btcFeeReceiverAddresses=BTC fee receiver addresses +filterWindow.btcFeeReceiverAddresses=Adresse de réception des frais Bitcoin offerDetailsWindow.minBtcAmount=Montant BTC min. offerDetailsWindow.min=(min. {0}) @@ -2111,7 +2138,7 @@ offerDetailsWindow.creationDate=Date de création offerDetailsWindow.makersOnion=Adresse onion du maker qRCodeWindow.headline=QR Code -qRCodeWindow.msg=Please use this QR code for funding your Bisq wallet from your external wallet. +qRCodeWindow.msg=Veuillez utiliser le code QR pour recharger du portefeuille externe au portefeuille Bisq. qRCodeWindow.request=Demande de paiement:\n{0} selectDepositTxWindow.headline=Sélectionner la transaction de dépôt en cas de litige @@ -2134,10 +2161,10 @@ sendPrivateNotificationWindow.send=Envoyer une notification privée showWalletDataWindow.walletData=Données du portefeuille showWalletDataWindow.includePrivKeys=Inclure les clés privées -setXMRTxKeyWindow.headline=Prove sending of XMR -setXMRTxKeyWindow.note=Adding tx info below enables auto-confirm for quicker trades. See more: https://bisq.wiki/Trading_Monero -setXMRTxKeyWindow.txHash=Transaction ID (optional) -setXMRTxKeyWindow.txKey=Transaction key (optional) +setXMRTxKeyWindow.headline=La preuve XMR a été envoyée. +setXMRTxKeyWindow.note=Ajoutez les informations tx au-dessous pour confirmer automatiquement les transactions plus rapidement. Plus d'informations: https://bisq.wiki/Trading_Monero +setXMRTxKeyWindow.txHash=ID de transaction (en option) +setXMRTxKeyWindow.txKey=Clé de transaction (en option) # We do not translate the tac because of the legal nature. We would need translations checked by lawyers # in each language which is too expensive atm. @@ -2151,9 +2178,10 @@ tradeDetailsWindow.disputedPayoutTxId=ID de la transaction de versement contest tradeDetailsWindow.tradeDate=Date de l'échange tradeDetailsWindow.txFee=Frais de minage tradeDetailsWindow.tradingPeersOnion=Adresse onion du pair de trading -tradeDetailsWindow.tradingPeersPubKeyHash=Trading peers pubkey hash +tradeDetailsWindow.tradingPeersPubKeyHash=Valeur de hachage de la clé publique du partenaire commercial tradeDetailsWindow.tradeState=État du trade tradeDetailsWindow.agentAddresses=Arbitre/Médiateur +tradeDetailsWindow.detailData=Detail data walletPasswordWindow.headline=Entrer le mot de passe pour déverouiller @@ -2183,6 +2211,8 @@ feeOptionWindow.info=Vous pouvez choisir de payer les frais de transaction en BS feeOptionWindow.optionsLabel=Choisissez la devise pour le paiement des frais de transaction feeOptionWindow.useBTC=Utiliser BTC feeOptionWindow.fee={0} (≈ {1}) +feeOptionWindow.btcFeeWithFiatAndPercentage={0} (≈ {1} / {2}) +feeOptionWindow.btcFeeWithPercentage={0} ({1}) #################################################################### @@ -2213,9 +2243,9 @@ error.closedTradeWithUnconfirmedDepositTx=La transaction de dépôt de l''échan error.closedTradeWithNoDepositTx=La transaction de dépôt de l'échange fermé avec l''ID d'échange {0} est nulle.\n\nVeuillez redémarrer l''application pour nettoyer la liste des transactions fermées. popup.warning.walletNotInitialized=Le portefeuille n'est pas encore initialisé -popup.warning.osxKeyLoggerWarning=Due to stricter security measures in macOS 10.14 and above, launching a Java application (Bisq uses Java) causes a popup warning in macOS ('Bisq would like to receive keystrokes from any application').\n\nTo avoid that issue please open your 'macOS Settings' and go to 'Security & Privacy' -> 'Privacy' -> 'Input Monitoring' and Remove 'Bisq' from the list on the right side.\n\nBisq will upgrade to a newer Java version to avoid that issue as soon the technical limitations (Java packager for the required Java version is not shipped yet) are resolved. +popup.warning.osxKeyLoggerWarning=En raison de mesures de sécurité plus strictes dans MacOS 10.14 et dans la version supérieure, le lancement d'une application Java (Bisq utilise Java) provoquera un avertissement pop-up dans MacOS (« Bisq souhaite recevoir les frappes de toute application »). \n\nPour éviter ce problème, veuillez ouvrir «Paramètres MacOS», puis allez dans «Sécurité et confidentialité» -> «Confidentialité» -> «Surveillance des entrées», puis supprimez «Bisq» de la liste de droite. \n\nUne fois les limitations techniques résolues (le packager Java de la version Java requise n'a pas été livré), Bisq effectuera une mise à niveau vers la nouvelle version Java pour éviter ce problème. popup.warning.wrongVersion=Vous avez probablement une mauvaise version de Bisq sur cet ordinateur.\nL''architecture de votre ordinateur est: {0}.\nLa binary Bisq que vous avez installé est: {1}.\nVeuillez éteindre et réinstaller une bonne version ({2}). -popup.warning.incompatibleDB=We detected incompatible data base files!\n\nThose database file(s) are not compatible with our current code base:\n{0}\n\nWe made a backup of the corrupted file(s) and applied the default values to a new database version.\n\nThe backup is located at:\n{1}/db/backup_of_corrupted_data.\n\nPlease check if you have the latest version of Bisq installed.\nYou can download it at: [HYPERLINK:https://bisq.network/downloads].\n\nPlease restart the application. +popup.warning.incompatibleDB=Nous avons détecté un fichier de base de données incompatible!\n\nCes fichiers de base de données ne sont pas compatibles avec notre base de code actuelle: {0}\n\nNous avons sauvegardé les fichiers endommagés et appliqué les valeurs par défaut à la nouvelle version de la base de données.\n\nLa sauvegarde se trouve dans: \n\n{1} / db / backup_of_corrupted_data. \n\nVeuillez vérifier si vous avez installé la dernière version de Bisq. \n\nVous pouvez télécharger: \n\n[HYPERLINK:https://bisq.network/downloads] \n\nVeuillez redémarrer l'application. popup.warning.startupFailed.twoInstances=Bisq est déjà lancé. Vous ne pouvez pas lancer deux instances de bisq. popup.warning.tradePeriod.halfReached=Votre transaction avec ID {0} a atteint la moitié de la période de trading maximale autorisée et n''est toujours pas terminée.\n\nLa période de trade se termine le {1}.\n\nVeuillez vérifier l''état de votre transaction dans \"Portfolio/échanges en cours\" pour obtenir de plus amples informations. popup.warning.tradePeriod.ended=Votre échange avec l''ID {0} a atteint la période de trading maximale autorisée et n''est pas terminé.\n\nLa période d''échange s''est terminée le {1}.\n\nVeuillez vérifier votre transaction sur \"Portfolio/Echanges en cours\" pour contacter le médiateur. @@ -2226,6 +2256,7 @@ popup.warning.noMediatorsAvailable=Il n'y a pas de médiateurs disponibles. popup.warning.notFullyConnected=Vous devez attendre d'être complètement connecté au réseau.\nCela peut prendre jusqu'à 2 minutes au démarrage. popup.warning.notSufficientConnectionsToBtcNetwork=Vous devez attendre d''avoir au minimum {0} connexions au réseau Bitcoin. popup.warning.downloadNotComplete=Vous devez attendre que le téléchargement des blocs Bitcoin manquants soit terminé. +popup.warning.chainNotSynced=The Bisq wallet blockchain height is not synced correctly. If you recently started the application, please wait until one Bitcoin block has been published.\n\nYou can check the blockchain height in Settings/Network Info. If more than one block passes and this problem persists it may be stalled, in which case you should do an SPV resync. [HYPERLINK:https://bisq.wiki/Resyncing_SPV_file] popup.warning.removeOffer=Vous êtes certain de vouloir retirer cet ordre?\nLes frais du maker de {0} seront perdus si vous retirez cet ordre. popup.warning.tooLargePercentageValue=Vous ne pouvez pas définir un pourcentage de 100% ou plus grand. popup.warning.examplePercentageValue=Merci de saisir un nombre sous la forme d'un pourcentage tel que \"5.4\" pour 5.4% @@ -2235,7 +2266,7 @@ popup.warning.insufficientBtcFundsForBsqTx=Vous ne disposez pas de suffisamment popup.warning.bsqChangeBelowDustException=Cette transaction crée une BSQ change output qui est inférieure à la dust limit (5,46 BSQ) et serait rejetée par le réseau Bitcoin.\n\nVous devez soit envoyer un montant plus élevé pour éviter la change output (par exemple en ajoutant le montant de dust à votre montant d''envoi), soit ajouter plus de fonds BSQ à votre portefeuille pour éviter de générer une dust output.\n\nLa dust output est {0}. popup.warning.btcChangeBelowDustException=Cette transaction crée une change output qui est inférieure à la dust limit (546 Satoshi) et serait rejetée par le réseau Bitcoin.\n\nVous devez ajouter la quantité de dust à votre montant envoyé pour éviter de générer une dust output.\n\nLa dust output est {0}. -popup.warning.insufficientBsqFundsForBtcFeePayment=You''ll need more BSQ to do this transaction—the last 5.46 BSQ in your wallet cannot be used to pay trade fees because of dust limits in the Bitcoin protocol.\n\nYou can either buy more BSQ or pay trade fees with BTC.\n\nMissing funds: {0} +popup.warning.insufficientBsqFundsForBtcFeePayment=Vous avez besoin de plus de BSQ pour effectuer cette transaction - le dernier 5,46 BSQ restant dans le portefeuille ne sera pas utilisé pour payer les frais de transaction en raison de la limite fractionnaire dans l'accord BTC. \n\nVous pouvez acheter plus de BSQ ou utiliser BTC pour payer les frais de transaction\n\nManque de fonds BSQ: {0} popup.warning.noBsqFundsForBtcFeePayment=Votre portefeuille BSQ ne dispose pas de suffisamment de fonds pour payer les frais de transaction en BSQ. popup.warning.messageTooLong=Votre message dépasse la taille maximale autorisée. Veuillez l'envoyer en plusieurs parties ou le télécharger depuis un service comme https://pastebin.com. popup.warning.lockedUpFunds=Vous avez des fonds bloqués d''une transaction qui a échoué.\nSolde bloqué: {0}\nAdresse de la tx de dépôt: {1}\nID de l''échange: {2}.\n\nVeuillez ouvrir un ticket de support en sélectionnant la transaction dans l'écran des transactions ouvertes et en appuyant sur \"alt + o\" ou \"option + o\". @@ -2254,7 +2285,7 @@ popup.warning.openOffer.makerFeeTxRejected=La transaction de frais de maker pour popup.warning.trade.txRejected.tradeFee=frais de transaction popup.warning.trade.txRejected.deposit=dépôt -popup.warning.trade.txRejected=La transaction {0} pour l''échange avec ID {1} a été rejetée par le réseau Bitcoin.\nID de transaction={2}.\nL''échange a été déplacé vers les échanges en échec.\nAllez dans \"Paramètres/Info sur le réseau réseau\" et faites une resynchronisation SPV.\nPour obtenir de l''aide, le canal support de l''équipe Bisq est disponible sur Keybase. +popup.warning.trade.txRejected=The {0} transaction for trade with ID {1} was rejected by the Bitcoin network.\nTransaction ID={2}\nThe trade has been moved to failed trades.\nPlease go to \"Settings/Network info\" and do a SPV resync.\nFor further help please contact the Bisq support channel at the Bisq Keybase team. popup.warning.openOfferWithInvalidMakerFeeTx=La transaction de frais de maker pour l''offre avec ID {0} n''est pas valide.\nID de transaction={1}.\nAllez dans \"Paramètres/Info sur le réseau réseau\" et faites une resynchronisation SPV.\nPour obtenir de l''aide, le canal support de l''équipe Bisq est disponible sur Keybase. @@ -2264,14 +2295,15 @@ popup.info.cashDepositInfo=Veuillez vous assurer d''avoir une succursale de l'' popup.info.cashDepositInfo.confirm=Je confirme que je peux effectuer le dépôt. popup.info.shutDownWithOpenOffers=Bisq est en cours de fermeture, mais des ordres sont en attente.\n\nCes ordres ne seront pas disponibles sur le réseau P2P si Bisq est éteint, mais ils seront republiés sur le réseau P2P la prochaine fois que vous lancerez Bisq.\n\nPour garder vos ordres en ligne, laissez Bisq en marche et assurez-vous que cet ordinateur reste aussi en ligne (pour cela, assurez-vous qu'il ne passe pas en mode veille...la veille du moniteur ne pose aucun problème). popup.info.qubesOSSetupInfo=It appears you are running Bisq on Qubes OS. \n\nPlease make sure your Bisq qube is setup according to our Setup Guide at [HYPERLINK:https://bisq.wiki/Running_Bisq_on_Qubes]. +popup.warn.downGradePrevention=Downgrade from version {0} to version {1} is not supported. Please use the latest Bisq version. +popup.warn.daoRequiresRestart=There was a problem with synchronizing the DAO state. You have to restart the application to fix the issue. popup.privateNotification.headline=Notification privée importante! popup.securityRecommendation.headline=Recommendation de sécurité importante popup.securityRecommendation.msg=Nous vous rappelons d'envisager d'utiliser la protection par mot de passe pour votre portefeuille si vous ne l'avez pas déjà activé.\n\nIl est également fortement recommandé d'écrire les mots de la seed de portefeuille. Ces mots de la seed sont comme un mot de passe principal pour récupérer votre portefeuille Bitcoin.\nVous trouverez plus d'informations à ce sujet dans l'onglet \"seed du portefeuille\".\n\nDe plus, il est recommandé de sauvegarder le dossier complet des données de l'application dans l'onglet \"Sauvegarde". -popup.bitcoinLocalhostNode.msg=Bisq a détecté un noeud Bitcoin Core fonctionnant localement (sur localhost).\nVeuillez vous assurer que ce nœud est entièrement synchronisé avant de lancer Bisq et qu'il ne fonctionne pas en mode restreint. -popup.bitcoinLocalhostNode.additionalRequirements=\n\nFor a well configured node, the requirements are for the node to have pruning disabled and bloom filters enabled. +popup.bitcoinLocalhostNode.msg=Bisq detected a Bitcoin Core node running on this machine (at localhost).\n\nPlease ensure:\n- the node is fully synced before starting Bisq\n- pruning is disabled ('prune=0' in bitcoin.conf)\n- bloom filters are enabled ('peerbloomfilters=1' in bitcoin.conf) popup.shutDownInProgress.headline=Fermeture en cours popup.shutDownInProgress.msg=La fermeture de l'application nécessite quelques secondes.\nVeuillez ne pas interrompre ce processus. @@ -2303,15 +2335,12 @@ popup.accountSigning.signedByPeer=Un de vos comptes de paiement a été vérifi popup.accountSigning.peerLimitLifted=La limite initiale pour l''un de vos comptes a été levée.\n\n{0} popup.accountSigning.peerSigner=Un de vos comptes est suffisamment mature pour signer d'autres comptes de paiement et la limite initiale pour un de vos comptes a été levée.\n\n{0} -popup.accountSigning.singleAccountSelect.headline=Select account age witness -popup.accountSigning.singleAccountSelect.description=Search for account age witness. -popup.accountSigning.singleAccountSelect.datePicker=Select point of time for signing +popup.accountSigning.singleAccountSelect.headline=Import unsigned account age witness popup.accountSigning.confirmSingleAccount.headline=Confirm selected account age witness popup.accountSigning.confirmSingleAccount.selectedHash=Selected witness hash popup.accountSigning.confirmSingleAccount.button=Sign account age witness popup.accountSigning.successSingleAccount.description=Witness {0} was signed popup.accountSigning.successSingleAccount.success.headline=Success -popup.accountSigning.successSingleAccount.signError=Failed to sign witness, {0} popup.accountSigning.unsignedPubKeys.headline=Unsigned Pubkeys popup.accountSigning.unsignedPubKeys.sign=Sign Pubkeys @@ -2447,8 +2476,8 @@ navigation.dao.wallet.receive=\"DAO/BSQ Portefeuille/Recevoir\" formatter.formatVolumeLabel={0} montant{1} formatter.makerTaker=Maker comme {0} {1} / Taker comme {2} {3} -formatter.youAreAsMaker=Vous êtes {0} {1} en tant que maker / Le taker est {2} {3} -formatter.youAreAsTaker=Vous êtes {0} {1} en tant que taker/ le maker est {2} {3}. +formatter.youAreAsMaker=You are: {1} {0} (maker) / Taker is: {3} {2} +formatter.youAreAsTaker=You are: {1} {0} (taker) / Maker is: {3} {2} formatter.youAre=Vous êtes {0} {1} ({2} {3}) formatter.youAreCreatingAnOffer.fiat=Vous êtes en train de créer un ordre pour {0} {1} formatter.youAreCreatingAnOffer.altcoin=Vous êtes en train de créer un ordre pour {0} {1} ({2} {3}) @@ -2514,7 +2543,7 @@ seed.warn.walletNotEmpty.msg=Your Bitcoin wallet is not empty.\n\nYou must empty seed.warn.walletNotEmpty.restore=Je veux quand même restaurer. seed.warn.walletNotEmpty.emptyWallet=Je viderai mes portefeuilles en premier. seed.warn.notEncryptedAnymore=Vos portefeuilles sont cryptés.\n\nAprès la restauration, les portefeuilles ne seront plus cryptés et vous devrez définir un nouveau mot de passe.\n\nSouhaitez-vous continuer ? -seed.warn.walletDateEmpty=As you have not specified a wallet date, bisq will have to scan the blockchain from 2013.10.09 (the BIP39 epoch date).\n\nBIP39 wallets were first introduced in bisq on 2017.06.28 (release v0.5). So you could save time by using that date.\n\nIdeally you should specify the date your wallet seed was created.\n\n\nAre you sure you want to go ahead without specifying a wallet date? +seed.warn.walletDateEmpty=Puisque vous n'avez pas spécifié la date du portefeuille, Bisq devra scanner la blockchain après le 09/10/2013 (date de création du BIP39). \n\nLe portefeuille BIP39 a été lancé pour la première fois sur Bisq le 28/06/2017 (version v0.5). Par conséquent, vous pouvez utiliser cette date pour gagner du temps. \n\nIdéalement, vous devez indiquer la date à laquelle la graine de départ du portefeuille est créée. \n\n\nÊtes-vous sûr de vouloir continuer sans spécifier la date du portefeuille? seed.restore.success=Portefeuilles restaurés avec succès grâce aux nouveaux mots de la seed.\n\nVous devez arrêter et redémarrer l'application. seed.restore.error=Une erreur est survenue lors de la restauration des portefeuilles avec les mots composant la seed.{0} seed.restore.openOffers.warn=You have open offers which will be removed if you restore from seed words.\nAre you sure that you want to continue? @@ -2561,6 +2590,7 @@ payment.venmo.venmoUserName=Nom d'utilisateur Venmo payment.popmoney.accountId=Email ou N° de téléphone payment.promptPay.promptPayId=N° de carte d'identité/d'identification du contribuable ou numéro de téléphone payment.supportedCurrencies=Devises acceptées +payment.supportedCurrenciesForReceiver=Currencies for receiving funds payment.limitations=Restrictions payment.salt=Salage de la vérification de l'âge des comptes payment.error.noHexSalt=The salt needs to be in HEX format.\nIt is only recommended to edit the salt field if you want to transfer the salt from an old account to keep your account age. The account age is verified by using the account salt and the identifying account data (e.g. IBAN). @@ -2597,8 +2627,8 @@ payment.accountType=Type de compte payment.checking=Vérification payment.savings=Épargne payment.personalId=Pièce d'identité -payment.clearXchange.info=Zelle is a money transfer service that works best *through* another bank.\n\n1. Check this page to see if (and how) your bank works with Zelle: [HYPERLINK:https://www.zellepay.com/get-started]\n\n2. Take special note of your transfer limits—sending limits vary by bank, and banks often specify separate daily, weekly, and monthly limits.\n\n3. If your bank does not work with Zelle, you can still use it through the Zelle mobile app, but your transfer limits will be much lower.\n\n4. The name specified on your Bisq account MUST match the name on your Zelle/bank account. \n\nIf you cannot complete a Zelle transaction as specified in your trade contract, you may lose some (or all) of your security deposit.\n\nBecause of Zelle''s somewhat higher chargeback risk, sellers are advised to contact unsigned buyers through email or SMS to verify that the buyer really owns the Zelle account specified in Bisq. -payment.fasterPayments.newRequirements.info=Some banks have started verifying the receiver''s full name for Faster Payments transfers. Your current Faster Payments account does not specify a full name.\n\nPlease consider recreating your Faster Payments account in Bisq to provide future {0} buyers with a full name.\n\nWhen you recreate the account, make sure to copy the precise sort code, account number and account age verification salt values from your old account to your new account. This will ensure your existing account''s age and signing status are preserved. +payment.clearXchange.info=Zelle est un service de transfert d'argent, qui fonctionne bien pour transférer de l'argent vers d'autres banques. \n\n1. Consultez cette page pour voir si (et comment) votre banque coopère avec Zelle: \n[HYPERLINK:https://www.zellepay.com/get-started]\n\n2. Faites particulièrement attention à votre limite de transfert - les limites de versement varient d'une banque à l'autre, et les banques spécifient généralement des limites quotidiennes, hebdomadaires et mensuelles. \n\n3. Si votre banque ne peut pas utiliser Zelle, vous pouvez toujours l'utiliser via l'application mobile Zelle, mais votre limite de transfert sera bien inférieure. \n\n4. Le nom indiqué sur votre compte Bisq doit correspondre à celui du compte Zelle / bancaire. \n\nSi vous ne parvenez pas à réaliser la transaction Zelle comme stipulé dans le contrat commercial, vous risquez de perdre une partie (ou la totalité) de votre marge.\n\nComme Zelle présente un risque élevé de rétrofacturation, il est recommandé aux vendeurs de contacter les acheteurs non signés par e-mail ou SMS pour confirmer que les acheteurs ont le compte Zelle spécifié dans Bisq. +payment.fasterPayments.newRequirements.info=Certaines banques ont déjà commencé à vérifier le nom complet du destinataire du paiement rapide. Votre compte de paiement rapide actuel ne remplit pas le nom complet. \n\nPensez à recréer votre compte de paiement rapide dans Bisq pour fournir un nom complet aux futurs {0} acheteurs. \n\nLors de la recréation d'un compte, assurez-vous de copier l'indicatif bancaire, le numéro de compte et le sel de vérification de l'âge de l'ancien compte vers le nouveau compte. Cela garantira que votre âge du compte et état de signature existant sont conservés. payment.moneyGram.info=When using MoneyGram the BTC buyer has to send the Authorisation number and a photo of the receipt by email to the BTC seller. The receipt must clearly show the seller's full name, country, state and the amount. The seller's email will be displayed to the buyer during the trade process. payment.westernUnion.info=When using Western Union the BTC buyer has to send the MTCN (tracking number) and a photo of the receipt by email to the BTC seller. The receipt must clearly show the seller's full name, city, country and the amount. The seller's email will be displayed to the buyer during the trade process. payment.halCash.info=Lors de l'utilisation de HalCash, l'acheteur de BTC doit envoyer au vendeur de BTC le code HalCash par SMS depuis son téléphone portable.\n\nVeuillez vous assurer de ne pas dépasser le montant maximum que votre banque vous permet d'envoyer avec HalCash. Le montant minimum par retrait est de 10 EUR et le montant maximum est de 600 EUR. Pour les retraits récurrents, il est de 3000 EUR par destinataire par jour et 6000 EUR par destinataire par mois. Veuillez vérifier ces limites auprès de votre banque pour vous assurer qu'elles utilisent les mêmes limites que celles indiquées ici.\n\nLe montant du retrait doit être un multiple de 10 EUR car vous ne pouvez pas retirer d'autres montants à un distributeur automatique. Pendant les phases de create-offer et take-offer l'affichage de l'interface utilisateur ajustera le montant en BTC afin que le montant en euros soit correct. Vous ne pouvez pas utiliser le prix basé sur le marché, car le montant en euros varierait en fonction de l'évolution des prix.\n\nEn cas de litige, l'acheteur de BTC doit fournir la preuve qu'il a envoyé la somme en EUR. @@ -2613,7 +2643,7 @@ payment.revolut.info=Revolut requires the 'User name' as account ID not the phon payment.account.revolut.addUserNameInfo={0}\nYour existing Revolut account ({1}) does not have a ''User name''.\nPlease enter your Revolut ''User name'' to update your account data.\nThis will not affect your account age signing status. payment.revolut.addUserNameInfo.headLine=Update Revolut account -payment.usPostalMoneyOrder.info=Trading using US Postal Money Orders (USPMO) on Bisq requires that you understand the following:\n\n- BTC buyers must write the BTC Seller’s name in both the Payer and the Payee’s fields & take a high-resolution photo of the USPMO and envelope with proof of tracking before sending.\n- BTC buyers must send the USPMO to the BTC seller with Delivery Confirmation.\n\nIn the event mediation is necessary, or if there is a trade dispute, you will be required to send the photos to the Bisq mediator or refund agent, together with the USPMO Serial Number, Post Office Number, and dollar amount, so they can verify the details on the US Post Office website.\n\nFailure to provide the required information to the Mediator or Arbitrator will result in losing the dispute case.\n\nIn all dispute cases, the USPMO sender bears 100% of the burden of responsibility in providing evidence/proof to the Mediator or Arbitrator.\n\nIf you do not understand these requirements, do not trade using USPMO on Bisq. +payment.usPostalMoneyOrder.info=Pour échanger US Postal Money Orders (USPMO) sur Bisq, vous devez comprendre les termes suivants: \n\n- L'acheteur BTC doit écrire le nom du vendeur BTC dans les champs expéditeur et bénéficiaire, et prendre une photo à haute résolution de USPMO et de l'enveloppe avec une preuve de suivi avant l'envoi. \n\n- L'acheteur BTC doit envoyer USPMO avec la confirmation de livraison au vendeur BTC. \n\nSi une médiation est nécessaire, ou s'il y a un différend de transaction, vous devrez envoyer la photo avec le numéro USPMO, le numéro du bureau de poste et le montant de la transaction au médiateur Bisq ou à l'agent de remboursement afin qu'ils puissent vérifier les détails sur le site web de la poste américaine. \n\nSi vous ne fournissez pas les données de transaction requises, vous perdrez directement dans le différend. \n\nDans tous les cas de litige, l'expéditeur de l'USPMO assume à 100% la responsabilité lors de la fourniture de preuves / certification au médiateur ou à l'arbitre. \n\nSi vous ne comprenez pas ces exigences, veuillez ne pas échanger USPMO sur Bisq. payment.f2f.contact=information de contact payment.f2f.contact.prompt=How would you like to be contacted by the trading peer? (email address, phone number,...) @@ -2635,7 +2665,8 @@ payment.japan.recipient=Nom payment.australia.payid=PayID payment.payid=PayID linked to financial institution. Like email address or mobile phone. payment.payid.info=A PayID like a phone number, email address or an Australian Business Number (ABN), that you can securely link to your bank, credit union or building society account. You need to have already created a PayID with your Australian financial institution. Both sending and receiving financial institutions must support PayID. For more information please check [HYPERLINK:https://payid.com.au/faqs/] -payment.amazonGiftCard.info=To pay with Amazon eGift Card you need to purchase an Amazon eGift Card at your Amazon account and use the BTC seller''s email or mobile nr. as receiver. Amazon sends then an email or text message to the receiver. Use the trade ID for the message field.\n\nAmazon eGift Cards can only be redeemed by Amazon accounts with the same currency.\n\nFor more information visit the Amazon eGift Card webpage. [HYPERLINK:https://www.amazon.com/Amazon-1_US_Email-eGift-Card/dp/B004LLIKVU] +payment.amazonGiftCard.info=To pay with Amazon eGift Card, you will need to send an Amazon eGift Card to the BTC seller via your Amazon account. \n\nBisq will show the BTC seller''s email address or phone number where the gift card should be sent, and you must include the trade ID in the gift card''s message field. Please see the wiki [HYPERLINK:https://bisq.wiki/Amazon_eGift_card] for further details and best practices. \n\nThree important notes:\n- try to send gift cards with amounts of 100 USD or smaller, as Amazon is known to flag larger gift cards as fraudulent\n- try to use creative, believable text for the gift card''s message (e.g., "Happy birthday Susan!") along with the trade ID (and use trader chat to tell your trading peer the reference text you picked so they can verify your payment)\n- Amazon eGift Cards can only be redeemed on the Amazon website they were purchased on (e.g., a gift card purchased on amazon.it can only be redeemed on amazon.it) + # We use constants from the code so we do not use our normal naming convention # dynamic values are not recognized by IntelliJ diff --git a/core/src/main/resources/i18n/displayStrings_it.properties b/core/src/main/resources/i18n/displayStrings_it.properties index d829bd4cf5..5cb4b2862b 100644 --- a/core/src/main/resources/i18n/displayStrings_it.properties +++ b/core/src/main/resources/i18n/displayStrings_it.properties @@ -71,6 +71,7 @@ shared.amountWithCur=Importo in {0} shared.volumeWithCur=Volume in {0} shared.currency=Valuta shared.market=Mercato +shared.deviation=Deviation shared.paymentMethod=Metodo di pagamento shared.tradeCurrency=Valuta di scambio shared.offerType=Tipo di offerta @@ -104,7 +105,6 @@ shared.selectTradingAccount=Seleziona conto di trading shared.fundFromSavingsWalletButton=Trasferisci fondi dal portafoglio Bisq shared.fundFromExternalWalletButton=Apri il tuo portafoglio esterno per aggiungere fondi shared.openDefaultWalletFailed=Failed to open a Bitcoin wallet application. Are you sure you have one installed? -shared.distanceInPercent=Distanza in % dal prezzo di mercato shared.belowInPercent=Sotto % del prezzo di mercato shared.aboveInPercent=Sopra % del prezzo di mercato shared.enterPercentageValue=Immetti il valore % @@ -191,7 +191,7 @@ shared.tradeWalletBalance=Saldo del portafogli per gli scambi shared.makerTxFee=Maker: {0} shared.takerTxFee=Taker: {0} shared.iConfirm=Confermo -shared.tradingFeeInBsqInfo=equivalente a {0} utilizzato come commissione di negoziazione +shared.tradingFeeInBsqInfo=≈ {0} shared.openURL=Aperti {0} shared.fiat=Fiat shared.crypto=Crypto @@ -218,6 +218,9 @@ shared.refundAgentForSupportStaff=Agente di rimborso shared.delayedPayoutTxId=Delayed payout transaction ID shared.delayedPayoutTxReceiverAddress=Delayed payout transaction sent to shared.unconfirmedTransactionsLimitReached=Al momento, hai troppe transazioni non confermate. Per favore riprova più tardi. +shared.numItemsLabel=Number of entries: {0} +shared.filter=Filter +shared.enabled=Enabled #################################################################### @@ -248,14 +251,14 @@ mainView.balance.locked=Bloccati in scambi mainView.balance.reserved.short=Riservati mainView.balance.locked.short=Bloccati -mainView.footer.usingTor=(usando Tor) +mainView.footer.usingTor=(via Tor) mainView.footer.localhostBitcoinNode=(localhost) -mainView.footer.btcInfo={0} {1} {2} -mainView.footer.btcFeeRate=/ Current fee rate: {0} sat/vB +mainView.footer.btcInfo={0} {1} +mainView.footer.btcFeeRate=/ Fee rate: {0} sat/vB mainView.footer.btcInfo.initializing=Connessione alla rete Bitcoin mainView.footer.bsqInfo.synchronizing=/ Sincronizzando DAO -mainView.footer.btcInfo.synchronizingWith=Sincronizzazione con -mainView.footer.btcInfo.synchronizedWith=Synced with +mainView.footer.btcInfo.synchronizingWith=Synchronizing with {0} at block: {1} / {2} +mainView.footer.btcInfo.synchronizedWith=Synced with {0} at block {1} mainView.footer.btcInfo.connectingTo=Connessione a mainView.footer.btcInfo.connectionFailed=Connessione fallita mainView.footer.p2pInfo=Bitcoin network peers: {0} / Bisq network peers: {1} @@ -336,10 +339,10 @@ offerbook.offerersAcceptedBankSeats=Sede accettata dei paesi bancari (acquirente offerbook.availableOffers=Offerte disponibili offerbook.filterByCurrency=Filtra per valuta offerbook.filterByPaymentMethod=Filtra per metodo di pagamento -offerbook.timeSinceSigning=Signed since +offerbook.timeSinceSigning=Account info offerbook.timeSinceSigning.info=Questo account è stato verificato e {0} offerbook.timeSinceSigning.info.arbitrator=firmato da un arbitro e può firmare account peer -offerbook.timeSinceSigning.info.peer=firmato da un peer, in attesa che i limiti vengano alzati +offerbook.timeSinceSigning.info.peer=signed by a peer, waiting %d days for limits to be lifted offerbook.timeSinceSigning.info.peerLimitLifted=firmato da un peer e i limiti sono stati alzati offerbook.timeSinceSigning.info.signer=firmato da un peer e può firmare account peer (limiti alzati) offerbook.timeSinceSigning.info.banned= \nl'account è stato bannato @@ -349,9 +352,12 @@ offerbook.xmrAutoConf=Is auto-confirm enabled offerbook.timeSinceSigning.help=Quando completi correttamente un'operazione con un peer che ha un account di pagamento firmato, il tuo account di pagamento viene firmato.\n{0} giorni dopo, il limite iniziale di {1} viene alzato e il tuo account può firmare account di pagamento di altri peer. offerbook.timeSinceSigning.notSigned=Non ancora firmato +offerbook.timeSinceSigning.notSigned.ageDays={0} giorni offerbook.timeSinceSigning.notSigned.noNeed=N/A -shared.notSigned=Questo account non è stato ancora firmato -shared.notSigned.noNeed=Questo tipo di account non utilizza la firma +shared.notSigned=This account has not been signed yet and was created {0} days ago +shared.notSigned.noNeed=This account type does not require signing +shared.notSigned.noNeedDays=This account type does not require signing and was created {0} days ago +shared.notSigned.noNeedAlts=Altcoin accounts do not feature signing or aging offerbook.nrOffers=N. di offerte: {0} offerbook.volume={0} (min - max) @@ -435,11 +441,15 @@ createOffer.warning.sellBelowMarketPrice=Otterrai sempre il {0}% in meno rispett createOffer.warning.buyAboveMarketPrice=Pagherai sempre il {0}% in più rispetto al prezzo di mercato corrente poiché il prezzo della tua offerta verrà costantemente aggiornato. createOffer.tradeFee.descriptionBTCOnly=Commissione di scambio createOffer.tradeFee.descriptionBSQEnabled=Seleziona la valuta della commissione di scambio -createOffer.tradeFee.fiatAndPercent=≈ {0} / {1} dell'importo di scambio + +createOffer.triggerPrice.prompt=Set optional trigger price +createOffer.triggerPrice.label=Deactivate offer if market price is {0} +createOffer.triggerPrice.tooltip=As protecting against drastic price movements you can set a trigger price which deactivates the offer if the market price reaches that value. +createOffer.triggerPrice.invalid.tooLow=Value must be higher than {0} +createOffer.triggerPrice.invalid.tooHigh=Value must be lower than {0} # new entries createOffer.placeOfferButton=Revisione: piazza l'offerta a {0} bitcoin -createOffer.alreadyFunded=Hai già finanziato quell'offerta.\nI tuoi fondi sono stati spostati nel tuo portafoglio Bisq locale e sono disponibili per il prelievo nella schermata \"Fondi/Invia fondi\". createOffer.createOfferFundWalletInfo.headline=Finanzia la tua offerta # suppress inspection "TrailingSpacesInProperty" createOffer.createOfferFundWalletInfo.tradeAmount=- Importo di scambio: {0} \n @@ -496,7 +506,6 @@ takeOffer.error.message=Si è verificato un errore durante l'accettazione dell'o # new entries takeOffer.takeOfferButton=Rivedi: Accetta l'offerta per {0} bitcoin takeOffer.noPriceFeedAvailable=Non puoi accettare questa offerta poiché utilizza un prezzo in percentuale basato sul prezzo di mercato ma non è disponibile alcun feed di prezzi. -takeOffer.alreadyFunded.movedFunds=Hai già finanziato quell'offerta.\nI tuoi fondi sono stati spostati nel tuo portafoglio Bisq locale e sono disponibili per il prelievo nella schermata \"Fondi/Invia fondi\". takeOffer.takeOfferFundWalletInfo.headline=Finanzia il tuo scambio # suppress inspection "TrailingSpacesInProperty" takeOffer.takeOfferFundWalletInfo.tradeAmount=- Importo di scambio: {0} \n @@ -524,6 +533,10 @@ takeOffer.tac=Accettando questa offerta, accetto le condizioni commerciali defin # Offerbook / Edit offer #################################################################### +openOffer.header.triggerPrice=Prezzo di attivazione +openOffer.triggerPrice=Trigger price {0} +openOffer.triggered=The offer has been deactivated because the market price reached your trigger price.\nPlease edit the offer to define a new trigger price + editOffer.setPrice=Imposta prezzo editOffer.confirmEdit=Conferma: modifica offerta editOffer.publishOffer=Pubblica la tua offerta. @@ -541,6 +554,8 @@ portfolio.tab.history=Storia portfolio.tab.failed=Fallita portfolio.tab.editOpenOffer=Modifica offerta +portfolio.closedTrades.deviation.help=Percentage price deviation from market + portfolio.pending.invalidDelayedPayoutTx=There is an issue with a missing or invalid transaction.\n\nPlease do NOT send the fiat or altcoin payment. Contact Bisq developers on Keybase [HYPERLINK:https://keybase.io/team/bisq] or on the forum [HYPERLINK:https://bisq.community] for further assistance.\n\nError message: {0} portfolio.pending.step1.waitForConf=Attendi la conferma della blockchain @@ -886,13 +901,12 @@ funds.tx.noTxAvailable=Nessuna transazione disponibile funds.tx.revert=Storna funds.tx.txSent=Transazione inviata con successo ad un nuovo indirizzo nel portafoglio Bisq locale. funds.tx.direction.self=Invia a te stesso -funds.tx.daoTxFee=Commissione al miner per la tx verso la DAO +funds.tx.daoTxFee=Commissione di mining per transazioni BSQ funds.tx.reimbursementRequestTxFee=Richiesta di rimborso funds.tx.compensationRequestTxFee=Richiesta di compenso funds.tx.dustAttackTx=Polvere ricevuta funds.tx.dustAttackTx.popup=Questa transazione sta inviando un importo BTC molto piccolo al tuo portafoglio e potrebbe essere un tentativo da parte delle società di chain analysis per spiare il tuo portafoglio.\n\nSe usi quell'output della transazione in una transazione di spesa, scopriranno che probabilmente sei anche il proprietario dell'altro indirizzo (combinazione di monete).\n\nPer proteggere la tua privacy, il portafoglio Bisq ignora tali output di polvere a fini di spesa e nella visualizzazione del saldo. È possibile impostare la soglia al di sotto della quale un output è considerato polvere.\n  - #################################################################### # Support #################################################################### @@ -943,6 +957,7 @@ support.error=Il destinatario non ha potuto elaborare il messaggio. Errore: {0} support.buyerAddress=Indirizzo BTC dell'acquirente support.sellerAddress=Indirizzo BTC del venditore support.role=Ruolo +support.agent=Support agent support.state=Stato support.closed=Chiuso support.open=Aperto @@ -1052,6 +1067,7 @@ settings.net.creationDateColumn=Stabilito settings.net.connectionTypeColumn=Dentro/Fuori settings.net.sentDataLabel=Sent data statistics settings.net.receivedDataLabel=Received data statistics +settings.net.chainHeightLabel=Latest BTC block height settings.net.roundTripTimeColumn=Ritorno settings.net.sentBytesColumn=Inviato settings.net.receivedBytesColumn=Ricevuto @@ -1066,6 +1082,7 @@ settings.net.needRestart=È necessario riavviare l'applicazione per applicare ta settings.net.notKnownYet=Non ancora noto... settings.net.sentData=Sent data: {0}, {1} messages, {2} messages/sec settings.net.receivedData=Received data: {0}, {1} messages, {2} messages/sec +settings.net.chainHeight=Bisq: {0} | Peers: {1} settings.net.ips=[Indirizzo IP:porta | hostname:porta | indirizzo onion:porta] (separato da una virgola). La porta può essere omessa se è usata quella predefinita (8333). settings.net.seedNode=Nodo seme settings.net.directPeer=Peer (diretto) @@ -1074,7 +1091,7 @@ settings.net.inbound=in entrata settings.net.outbound=in uscita settings.net.reSyncSPVChainLabel=Risincronizza la catena SPV settings.net.reSyncSPVChainButton=Elimina il file SPV e risincronizza -settings.net.reSyncSPVSuccess=Il file della catena SPV verrà eliminato al successivo avvio. È necessario riavviare l'applicazione ora.\n\nDopo il riavvio, la risincronizzazione con la rete può richiedere del tempo e vedrai tutte le transazioni solo una volta completata la risincronizzazione.\n\nA seconda del numero di transazioni e dell'età del tuo portafoglio, la risincronizzazione può richiedere fino a qualche ora e consuma il 100% della CPU. Non interrompere il processo, altrimenti sarà necessario ripeterlo. +settings.net.reSyncSPVSuccess=Are you sure you want to do an SPV resync? If you proceed, the SPV chain file will be deleted on the next startup.\n\nAfter the restart it can take a while to resync with the network and you will only see all transactions once the resync is completed.\n\nDepending on the number of transactions and the age of your wallet the resync can take up to a few hours and consumes 100% of CPU. Do not interrupt the process otherwise you have to repeat it. settings.net.reSyncSPVAfterRestart=Il file della catena SPV è stato eliminato. Per favore sii paziente. La risincronizzazione con la rete può richiedere del tempo. settings.net.reSyncSPVAfterRestartCompleted=La risincronizzazione è ora completata. Si prega di riavviare l'applicazione. settings.net.reSyncSPVFailed=Impossibile eliminare il file della catena SPV.\nErrore: {0} @@ -1161,9 +1178,19 @@ account.menu.paymentAccount=Conti in valuta nazionale account.menu.altCoinsAccountView=Conti altcoin account.menu.password=Password portafoglio account.menu.seedWords=Seme portafoglio +account.menu.walletInfo=Wallet info account.menu.backup=Backup account.menu.notifications=Notifiche +account.menu.walletInfo.balance.headLine=Wallet balances +account.menu.walletInfo.balance.info=This shows the internal wallet balance including unconfirmed transactions.\nFor BTC, the internal wallet balance shown below should match the sum of the 'Available' and 'Reserved' balances shown in the top right of this window. +account.menu.walletInfo.xpub.headLine=Watch keys (xpub keys) +account.menu.walletInfo.walletSelector={0} {1} wallet +account.menu.walletInfo.path.headLine=HD keychain paths +account.menu.walletInfo.path.info=If you import seed words into another wallet (like Electrum), you'll need to define the path. This should only be done in emergency cases when you lose access to the Bisq wallet and data directory.\nKeep in mind that spending funds from a non-Bisq wallet can bungle the internal Bisq data structures associated with the wallet data, which can lead to failed trades.\n\nNEVER send BSQ from a non-Bisq wallet, as it will probably lead to an invalid BSQ transaction and losing your BSQ. + +account.menu.walletInfo.openDetails=Show raw wallet details and private keys + ## TODO should we rename the following to a gereric name? account.arbitratorRegistration.pubKey=Chiave pubblica @@ -1796,7 +1823,7 @@ dao.wallet.send.setDestinationAddress=Inserisci il tuo indirizzo di destinazione dao.wallet.send.send=Invia fondi BSQ dao.wallet.send.sendBtc=Invia fondi BTC dao.wallet.send.sendFunds.headline=Conferma richiesta di prelievo -dao.wallet.send.sendFunds.details=Sending: {0}\nTo receiving address: {1}.\nRequired transaction fee is: {2} ({3} satoshis/vbyte)\nTransaction vsize: {4} vKb\n\nThe recipient will receive: {5}\n\nAre you sure you want to withdraw that amount? +dao.wallet.send.sendFunds.details=Sending: {0}\nTo receiving address: {1}.\nRequired mining fee is: {2} ({3} satoshis/vbyte)\nTransaction vsize: {4} vKb\n\nThe recipient will receive: {5}\n\nAre you sure you want to withdraw that amount? dao.wallet.chainHeightSynced=Ultimo blocco verificato: {0} dao.wallet.chainHeightSyncing=In attesa di blocchi... Verificati {0} blocchi su {1} dao.wallet.tx.type=Tipo @@ -1928,9 +1955,9 @@ dao.factsAndFigures.menuItem.transactions=Transazioni BSQ dao.factsAndFigures.dashboard.avgPrice90=Prezzo di scambio medio BSQ/BTC di 90 giorni dao.factsAndFigures.dashboard.avgPrice30=Prezzo di scambio medio BSQ/BTC di 30 giorni -dao.factsAndFigures.dashboard.avgUSDPrice90=Prezzo medio ponderato USD/BSQ degli ultimi 90 giorni -dao.factsAndFigures.dashboard.avgUSDPrice30=Prezzo medio ponderato USD / BSQ degli ultimi 30 giorni -dao.factsAndFigures.dashboard.marketCap=Capitalizzazione di mercato (basata sul prezzo di scambio) +dao.factsAndFigures.dashboard.avgUSDPrice90=90 days volume weighted average USD/BSQ price +dao.factsAndFigures.dashboard.avgUSDPrice30=30 days volume weighted average USD/BSQ price +dao.factsAndFigures.dashboard.marketCap=Market capitalisation (based on 30 days average USD/BSQ price) dao.factsAndFigures.dashboard.availableAmount=BSQ totale disponibile dao.factsAndFigures.supply.issuedVsBurnt=BSQ emessi v. BSQ bruciati @@ -2000,7 +2027,7 @@ disputeSummaryWindow.openDate=Data di apertura del ticket disputeSummaryWindow.role=Ruolo del trader disputeSummaryWindow.payout=Pagamento dell'importo di scambio disputeSummaryWindow.payout.getsTradeAmount=BTC {0} ottiene il pagamento dell'importo commerciale -disputeSummaryWindow.payout.getsAll=BTC {0} ottiene tutto +disputeSummaryWindow.payout.getsAll=Max. payout to BTC {0} disputeSummaryWindow.payout.custom=Pagamento personalizzato disputeSummaryWindow.payoutAmount.buyer=Importo pagamento dell'acquirente disputeSummaryWindow.payoutAmount.seller=Importo pagamento del venditore @@ -2154,6 +2181,7 @@ tradeDetailsWindow.tradingPeersOnion=Indirizzi onion peer di trading tradeDetailsWindow.tradingPeersPubKeyHash=Trading peers pubkey hash tradeDetailsWindow.tradeState=Stato di scambio tradeDetailsWindow.agentAddresses=Arbitro/Mediatore +tradeDetailsWindow.detailData=Detail data walletPasswordWindow.headline=Inserisci la password per sbloccare @@ -2183,6 +2211,8 @@ feeOptionWindow.info=Puoi scegliere di pagare la commissione commerciale in BSQ feeOptionWindow.optionsLabel=Scegli la valuta per il pagamento delle commissioni commerciali feeOptionWindow.useBTC=Usa BTC feeOptionWindow.fee={0} (≈ {1}) +feeOptionWindow.btcFeeWithFiatAndPercentage={0} (≈ {1} / {2}) +feeOptionWindow.btcFeeWithPercentage={0} ({1}) #################################################################### @@ -2226,6 +2256,7 @@ popup.warning.noMediatorsAvailable=Non ci sono mediatori disponibili. popup.warning.notFullyConnected=È necessario attendere fino a quando non si è completamente connessi alla rete.\nQuesto potrebbe richiedere fino a circa 2 minuti all'avvio. popup.warning.notSufficientConnectionsToBtcNetwork=Devi aspettare fino a quando non hai almeno {0} connessioni alla rete Bitcoin. popup.warning.downloadNotComplete=Devi aspettare fino al completamento del download dei blocchi Bitcoin mancanti. +popup.warning.chainNotSynced=The Bisq wallet blockchain height is not synced correctly. If you recently started the application, please wait until one Bitcoin block has been published.\n\nYou can check the blockchain height in Settings/Network Info. If more than one block passes and this problem persists it may be stalled, in which case you should do an SPV resync. [HYPERLINK:https://bisq.wiki/Resyncing_SPV_file] popup.warning.removeOffer=Sei sicuro di voler rimuovere quell'offerta?\nLa commissione del maker di {0} andrà persa se rimuovi quell'offerta. popup.warning.tooLargePercentageValue=Non è possibile impostare una percentuale del 100% o superiore. popup.warning.examplePercentageValue=Inserisci un numero percentuale come \"5.4\" per il 5,4% @@ -2254,7 +2285,7 @@ popup.warning.openOffer.makerFeeTxRejected=La commissione della transazione del popup.warning.trade.txRejected.tradeFee=commissione di scambio popup.warning.trade.txRejected.deposit=deposita -popup.warning.trade.txRejected=La transazione {0} per lo scambio con ID {1} è stata rifiutata dalla rete Bitcoin.\nTransazione ID={2}}\nLo scambio è stato trasferito nella sezione scambi falliti.\nVai su \"Impostazioni/Informazioni di rete\" ed esegui una risincronizzazione SPV.\nPer ulteriore assistenza, contattare il canale di supporto Bisq nel team di Bisq Keybase. +popup.warning.trade.txRejected=The {0} transaction for trade with ID {1} was rejected by the Bitcoin network.\nTransaction ID={2}\nThe trade has been moved to failed trades.\nPlease go to \"Settings/Network info\" and do a SPV resync.\nFor further help please contact the Bisq support channel at the Bisq Keybase team. popup.warning.openOfferWithInvalidMakerFeeTx=La commissione della transazione del creatore dell'offerta con ID {0} non è valida.\nTransazione ID={1}.\nVai su \"Impostazioni/Informazioni di rete\" ed esegui una risincronizzazione SPV.\nPer ulteriore assistenza, contattare il canale di supporto Bisq nel team di Bisq Keybase. @@ -2264,14 +2295,15 @@ popup.info.cashDepositInfo=Assicurati di avere una filiale bancaria nella tua zo popup.info.cashDepositInfo.confirm=Confermo di poter effettuare il deposito popup.info.shutDownWithOpenOffers=Bisq viene chiuso, ma ci sono offerte aperte.\n\nQueste offerte non saranno disponibili sulla rete P2P mentre Bisq rimane chiuso, ma verranno ripubblicate sulla rete P2P al prossimo avvio di Bisq.\n\nPer mantenere le tue offerte attive è necessario che Bisq rimanga in funzione ed il computer online (assicurati che non vada in modalità standby. Il solo monitor in standby non è un problema). popup.info.qubesOSSetupInfo=It appears you are running Bisq on Qubes OS. \n\nPlease make sure your Bisq qube is setup according to our Setup Guide at [HYPERLINK:https://bisq.wiki/Running_Bisq_on_Qubes]. +popup.warn.downGradePrevention=Downgrade from version {0} to version {1} is not supported. Please use the latest Bisq version. +popup.warn.daoRequiresRestart=There was a problem with synchronizing the DAO state. You have to restart the application to fix the issue. popup.privateNotification.headline=Notifica privata importante! popup.securityRecommendation.headline=Raccomandazione di sicurezza importante popup.securityRecommendation.msg=Vorremmo ricordarti di prendere in considerazione l'utilizzo della protezione con password per il tuo portafoglio se non l'avessi già abilitato.\n\nSi consiglia inoltre di annotare le parole seme del portafoglio. Le parole seme sono come una password principale per recuperare il tuo portafoglio Bitcoin.\nNella sezione \"Wallet Seed\" trovi ulteriori informazioni.\n\nInoltre, è necessario eseguire il backup della cartella completa dei dati dell'applicazione nella sezione \"Backup\". -popup.bitcoinLocalhostNode.msg=Bisq ha rilevato un nodo Bitcoin Core in esecuzione localmente (su localhost).\nAssicurarsi che questo nodo sia completamente sincronizzato prima di avviare Bisq e che non sia in esecuzione in modalità di eliminazione. -popup.bitcoinLocalhostNode.additionalRequirements=\n\nPer un nodo ben configurato, i requisiti necessari sono che il nodo abbia il pruning disabilitato e i filtri bloom abilitati. +popup.bitcoinLocalhostNode.msg=Bisq detected a Bitcoin Core node running on this machine (at localhost).\n\nPlease ensure:\n- the node is fully synced before starting Bisq\n- pruning is disabled ('prune=0' in bitcoin.conf)\n- bloom filters are enabled ('peerbloomfilters=1' in bitcoin.conf) popup.shutDownInProgress.headline=Arresto in corso popup.shutDownInProgress.msg=La chiusura dell'applicazione può richiedere un paio di secondi.\nNon interrompere il processo. @@ -2282,7 +2314,7 @@ popup.info.multiplePaymentAccounts.headline=Disponibili più conti di pagamento popup.info.multiplePaymentAccounts.msg=Hai più account di pagamento disponibili per questa offerta. Assicurati di aver scelto quello giusto. popup.accountSigning.selectAccounts.headline=Seleziona conti di pagamento -popup.accountSigning.selectAccounts.description=In base al metodo di pagamento e al momento in cui verranno selezionati tutti i conti di pagamento collegati a una controversia in cui si è verificato un pagamento +popup.accountSigning.selectAccounts.description=In base al metodo di pagamento e al momento in cui verranno selezionati tutti i conti di pagamento collegati a una controversia in cui si è verificato un pagamento popup.accountSigning.selectAccounts.signAll=Firma tutti i metodi di pagamento popup.accountSigning.selectAccounts.datePicker=Seleziona il momento in cui verranno firmati gli account @@ -2303,15 +2335,12 @@ popup.accountSigning.signedByPeer=Uno dei tuoi conti di pagamento è stato verif popup.accountSigning.peerLimitLifted=Il limite iniziale per uno dei tuoi account è stato revocato.\n\n{0} popup.accountSigning.peerSigner=Uno dei tuoi account è abbastanza maturo per firmare altri account di pagamento e il limite iniziale per uno dei tuoi account è stato revocato.\n\n{0} -popup.accountSigning.singleAccountSelect.headline=Select account age witness -popup.accountSigning.singleAccountSelect.description=Search for account age witness. -popup.accountSigning.singleAccountSelect.datePicker=Select point of time for signing +popup.accountSigning.singleAccountSelect.headline=Import unsigned account age witness popup.accountSigning.confirmSingleAccount.headline=Confirm selected account age witness popup.accountSigning.confirmSingleAccount.selectedHash=Selected witness hash popup.accountSigning.confirmSingleAccount.button=Sign account age witness popup.accountSigning.successSingleAccount.description=Witness {0} was signed popup.accountSigning.successSingleAccount.success.headline=Success -popup.accountSigning.successSingleAccount.signError=Failed to sign witness, {0} popup.accountSigning.unsignedPubKeys.headline=Unsigned Pubkeys popup.accountSigning.unsignedPubKeys.sign=Sign Pubkeys @@ -2447,8 +2476,8 @@ navigation.dao.wallet.receive=\"Portafoglio DAO/BSQ/Ricevi\" formatter.formatVolumeLabel={0} importo{1} formatter.makerTaker=Maker come {0} {1} / Taker come {2} {3} -formatter.youAreAsMaker=Sei {0} {1} come maker / Taker è {2} {3} -formatter.youAreAsTaker=Sei {0} {1} come Taker / make è {2} {3} +formatter.youAreAsMaker=You are: {1} {0} (maker) / Taker is: {3} {2} +formatter.youAreAsTaker=You are: {1} {0} (taker) / Maker is: {3} {2} formatter.youAre=Sei {0} {1} ({2} {3}) formatter.youAreCreatingAnOffer.fiat=Stai creando un'offerta per {0} {1} formatter.youAreCreatingAnOffer.altcoin=Stai creando un'offerta per {0} {1} ({2} {3}) @@ -2561,6 +2590,7 @@ payment.venmo.venmoUserName=Nome utente Venmo payment.popmoney.accountId=Email o numero di telefono fisso payment.promptPay.promptPayId=Codice fiscale/P.IVA o n. di telefono payment.supportedCurrencies=Valute supportate +payment.supportedCurrenciesForReceiver=Currencies for receiving funds payment.limitations=Limitazioni payment.salt=Sale per la verifica dell'età dell'account payment.error.noHexSalt=The salt needs to be in HEX format.\nIt is only recommended to edit the salt field if you want to transfer the salt from an old account to keep your account age. The account age is verified by using the account salt and the identifying account data (e.g. IBAN). @@ -2635,7 +2665,8 @@ payment.japan.recipient=Nome payment.australia.payid=PayID payment.payid=PayID linked to financial institution. Like email address or mobile phone. payment.payid.info=A PayID like a phone number, email address or an Australian Business Number (ABN), that you can securely link to your bank, credit union or building society account. You need to have already created a PayID with your Australian financial institution. Both sending and receiving financial institutions must support PayID. For more information please check [HYPERLINK:https://payid.com.au/faqs/] -payment.amazonGiftCard.info=To pay with Amazon eGift Card you need to purchase an Amazon eGift Card at your Amazon account and use the BTC seller''s email or mobile nr. as receiver. Amazon sends then an email or text message to the receiver. Use the trade ID for the message field.\n\nAmazon eGift Cards can only be redeemed by Amazon accounts with the same currency.\n\nFor more information visit the Amazon eGift Card webpage. [HYPERLINK:https://www.amazon.com/Amazon-1_US_Email-eGift-Card/dp/B004LLIKVU] +payment.amazonGiftCard.info=To pay with Amazon eGift Card, you will need to send an Amazon eGift Card to the BTC seller via your Amazon account. \n\nBisq will show the BTC seller''s email address or phone number where the gift card should be sent, and you must include the trade ID in the gift card''s message field. Please see the wiki [HYPERLINK:https://bisq.wiki/Amazon_eGift_card] for further details and best practices. \n\nThree important notes:\n- try to send gift cards with amounts of 100 USD or smaller, as Amazon is known to flag larger gift cards as fraudulent\n- try to use creative, believable text for the gift card''s message (e.g., "Happy birthday Susan!") along with the trade ID (and use trader chat to tell your trading peer the reference text you picked so they can verify your payment)\n- Amazon eGift Cards can only be redeemed on the Amazon website they were purchased on (e.g., a gift card purchased on amazon.it can only be redeemed on amazon.it) + # We use constants from the code so we do not use our normal naming convention # dynamic values are not recognized by IntelliJ diff --git a/core/src/main/resources/i18n/displayStrings_ja.properties b/core/src/main/resources/i18n/displayStrings_ja.properties index 8c83fda0c8..346f7136e6 100644 --- a/core/src/main/resources/i18n/displayStrings_ja.properties +++ b/core/src/main/resources/i18n/displayStrings_ja.properties @@ -71,6 +71,7 @@ shared.amountWithCur={0}の金額 shared.volumeWithCur={0}取引高 shared.currency=通貨 shared.market=相場 +shared.deviation=Deviation shared.paymentMethod=支払い方法 shared.tradeCurrency=取引通貨 shared.offerType=オファーの種類 @@ -104,7 +105,6 @@ shared.selectTradingAccount=取引アカウントを選択 shared.fundFromSavingsWalletButton=Bisqウォレットから資金を移動する shared.fundFromExternalWalletButton=外部のwalletを開く shared.openDefaultWalletFailed=ビットコインウォレットのアプリを開けませんでした。インストールされているか確認して下さい。 -shared.distanceInPercent=市場価格から % の乖離 shared.belowInPercent=市場価格から%以下 shared.aboveInPercent=市場価格から%以上 shared.enterPercentageValue=%を入力 @@ -191,7 +191,7 @@ shared.tradeWalletBalance=トレードウォレット残高 shared.makerTxFee=メイカー: {0} shared.takerTxFee=テイカー: {0} shared.iConfirm=確認します -shared.tradingFeeInBsqInfo=トレード手数料として使用される{0}と同じ +shared.tradingFeeInBsqInfo=≈ {0} shared.openURL={0} をオープン shared.fiat=法定通貨 shared.crypto=暗号通貨 @@ -218,6 +218,9 @@ shared.refundAgentForSupportStaff=仲裁者 shared.delayedPayoutTxId=遅延支払いトランザクションID shared.delayedPayoutTxReceiverAddress=遅延支払いトランザクション送り先 shared.unconfirmedTransactionsLimitReached=現在、非確認されたトランザクションが多すぎます。しばらく待ってからもう一度試して下さい。 +shared.numItemsLabel=Number of entries: {0} +shared.filter=Filter +shared.enabled=有効されました #################################################################### @@ -248,14 +251,14 @@ mainView.balance.locked=トレードにロック中 mainView.balance.reserved.short=予約済 mainView.balance.locked.short=ロック中 -mainView.footer.usingTor=(Torを使用中) +mainView.footer.usingTor=(via Tor) mainView.footer.localhostBitcoinNode=(ローカルホスト) -mainView.footer.btcInfo={0} {1} {2} -mainView.footer.btcFeeRate=/ 現在の手数料率: {0} サトシ/vB +mainView.footer.btcInfo={0} {1} +mainView.footer.btcFeeRate=/ Fee rate: {0} sat/vB mainView.footer.btcInfo.initializing=ビットコインネットワークに接続中 mainView.footer.bsqInfo.synchronizing=/ DAOと同期中 -mainView.footer.btcInfo.synchronizingWith=同期中 -mainView.footer.btcInfo.synchronizedWith=同期されています: +mainView.footer.btcInfo.synchronizingWith=Synchronizing with {0} at block: {1} / {2} +mainView.footer.btcInfo.synchronizedWith=Synced with {0} at block {1} mainView.footer.btcInfo.connectingTo=接続中: mainView.footer.btcInfo.connectionFailed=接続失敗 mainView.footer.p2pInfo=ビットコインネットワークピア: {0} / Bisqネットワークピア: {1} @@ -336,10 +339,10 @@ offerbook.offerersAcceptedBankSeats=利用可能な銀行の国名(テイカ offerbook.availableOffers=利用可能なオファー offerbook.filterByCurrency=通貨でフィルター offerbook.filterByPaymentMethod=支払い方法でフィルター -offerbook.timeSinceSigning=署名後経過時間 +offerbook.timeSinceSigning=アカウント情報 offerbook.timeSinceSigning.info=このアカウントは認証されまして、{0} offerbook.timeSinceSigning.info.arbitrator=調停人に署名されました。ピアアカウントも署名できます -offerbook.timeSinceSigning.info.peer=ピアが署名しました。制限の解除を待ちます +offerbook.timeSinceSigning.info.peer=ピアが署名しました。%d日間後に制限の解除を待ち中 offerbook.timeSinceSigning.info.peerLimitLifted=ピアが署名しました。制限は解除されました offerbook.timeSinceSigning.info.signer=ピアが署名しました。ピアアカウントも署名できます(制限は解除されました) offerbook.timeSinceSigning.info.banned=このアカウントは禁止されました @@ -349,9 +352,12 @@ offerbook.xmrAutoConf=自動確認は有効されますか? offerbook.timeSinceSigning.help=署名された支払いアカウントを持っているピアと成功にトレードすると、自身の支払いアカウントも署名されることになります。\n{0} 日後に、{1} という初期の制限は解除され、他のピアの支払いアカウントを署名できるようになります。 offerbook.timeSinceSigning.notSigned=まだ署名されていません +offerbook.timeSinceSigning.notSigned.ageDays={0}日 offerbook.timeSinceSigning.notSigned.noNeed=N/A -shared.notSigned=このアカウントはまだ署名されていません -shared.notSigned.noNeed=この種類のアカウントは署名を使用しません +shared.notSigned=このアカウントはまだ署名されていない。{0} 日間前に作成されました +shared.notSigned.noNeed=この種類のアカウントは署名を必要しません +shared.notSigned.noNeedDays=この種類のアカウントは署名を必要しません。{0} 日間前に作成されました +shared.notSigned.noNeedAlts=アルトコインのアカウントには署名や熟成という機能がありません offerbook.nrOffers=オファー数: {0} offerbook.volume={0} (下限 - 上限) @@ -435,14 +441,18 @@ createOffer.warning.sellBelowMarketPrice=オファーの価格は継続的に更 createOffer.warning.buyAboveMarketPrice=オファーの価格は継続的に更新されるため、常に現在の市場価格より{0}%以上で支払いするでしょう。 createOffer.tradeFee.descriptionBTCOnly=取引手数料 createOffer.tradeFee.descriptionBSQEnabled=トレード手数料通貨を選択 -createOffer.tradeFee.fiatAndPercent=≈ {0} / {1} の取引額 + +createOffer.triggerPrice.prompt=Set optional trigger price +createOffer.triggerPrice.label=Deactivate offer if market price is {0} +createOffer.triggerPrice.tooltip=As protecting against drastic price movements you can set a trigger price which deactivates the offer if the market price reaches that value. +createOffer.triggerPrice.invalid.tooLow=Value must be higher than {0} +createOffer.triggerPrice.invalid.tooHigh=Value must be lower than {0} # new entries createOffer.placeOfferButton=再確認: ビットコインを{0}オファーを出す -createOffer.alreadyFunded=このオファーは既に入金済みです。\n資金はローカルのBisqウォレットに移動済みで、「資金/送金する」画面から出金可能になっています。 createOffer.createOfferFundWalletInfo.headline=あなたのオファーへ入金 # suppress inspection "TrailingSpacesInProperty" -createOffer.createOfferFundWalletInfo.tradeAmount= - 取引額: {0}\n +createOffer.createOfferFundWalletInfo.tradeAmount=- 取引額: {0}\n createOffer.createOfferFundWalletInfo.msg=このオファーに対して {0} のデポジットを送金する必要があります。\n\nこの資金はあなたのローカルウォレットに予約済として保管され、オファーが受け入れられた時にマルチシグデポジットアドレスに移動しロックされます。\n\n金額の合計は以下の通りです\n{1} - セキュリティデポジット: {2}\n- 取引手数料: {3}\n- マイニング手数料: {4}\n\nこのオファーにデポジットを送金するには、以下の2つの方法があります。\n- Bisqウォレットを使う (便利ですがトランザクションが追跡される可能性があります)\n- 外部のウォレットから送金する (機密性の高い方法です)\n\nこのポップアップを閉じると全ての送金方法について詳細な情報が表示されます。 # only first part "An error occurred when placing the offer:" has been used before. We added now the rest (need update in existing translations!) @@ -496,7 +506,6 @@ takeOffer.error.message=オファーの受け入れ時にエラーが発生し # new entries takeOffer.takeOfferButton=再確認: ビットコインを{0}オファーを申し込む takeOffer.noPriceFeedAvailable=そのオファーは市場価格に基づくパーセント値を使用していますが、使用可能な価格フィードがないため、利用することはできません。 -takeOffer.alreadyFunded.movedFunds=このオファーは既に入金済みです。\n資金はローカルのBisqウォレットに移動済みで、「資金/送金する」画面から出金可能になっています。 takeOffer.takeOfferFundWalletInfo.headline=あなたのオファーへ入金 # suppress inspection "TrailingSpacesInProperty" takeOffer.takeOfferFundWalletInfo.tradeAmount= - 取引額: {0}\n @@ -524,6 +533,10 @@ takeOffer.tac=このオファーを受けることで、この画面で定義さ # Offerbook / Edit offer #################################################################### +openOffer.header.triggerPrice=価格トリガー +openOffer.triggerPrice=Trigger price {0} +openOffer.triggered=The offer has been deactivated because the market price reached your trigger price.\nPlease edit the offer to define a new trigger price + editOffer.setPrice=価格設定 editOffer.confirmEdit=承認: オファーを編集 editOffer.publishOffer=あなたのオファーの公開。 @@ -541,6 +554,8 @@ portfolio.tab.history=履歴 portfolio.tab.failed=失敗 portfolio.tab.editOpenOffer=オファーを編集 +portfolio.closedTrades.deviation.help=Percentage price deviation from market + portfolio.pending.invalidDelayedPayoutTx=欠測あるいは無効なトランザクションに関する問題があります。\n\nこの法定通貨・アルトコイン支払いの送信しないで下さい!サポートを受けるのに、Keybase [HYPERLINK:https://keybase.io/team/bisq] あるいは掲示板 [HYPERLINK:https://bisq.community] でBisqの開発者と連絡して下さい。\n\nエラーメッセージ: {0} portfolio.pending.step1.waitForConf=ブロックチェーンの承認をお待ち下さい @@ -886,13 +901,12 @@ funds.tx.noTxAvailable=利用できるトランザクションがありません funds.tx.revert=元に戻す funds.tx.txSent=トランザクションはローカルBisqウォレットの新しいアドレスに正常に送信されました。 funds.tx.direction.self=自分自身に送信済み -funds.tx.daoTxFee=DAOのTXのマイニング手数料 +funds.tx.daoTxFee=BSQのTXのマイニング手数料 funds.tx.reimbursementRequestTxFee=払い戻しリクエスト funds.tx.compensationRequestTxFee=報酬リクエスト funds.tx.dustAttackTx=ダストを受取りました funds.tx.dustAttackTx.popup=このトランザクションはごくわずかなBTC金額をあなたのウォレットに送っているので、あなたのウォレットを盗もうとするチェーン解析会社による試みかもしれません。\n\nあなたが支払い取引でそのトランザクションアウトプットを使うならば、彼らはあなたが他のアドレスの所有者である可能性が高いことを学びます(コインマージ)。\n\nあなたのプライバシーを保護するために、Bisqウォレットは、支払い目的および残高表示において、そのようなダストアウトプットを無視します。 設定でアウトプットがダストと見なされるときのしきい値を設定できます。 - #################################################################### # Support #################################################################### @@ -943,6 +957,7 @@ support.error=受信者がメッセージを処理できませんでした。エ support.buyerAddress=BTC買い手のアドレス support.sellerAddress=BTC売り手のアドレス support.role=役割 +support.agent=Support agent support.state=状態 support.closed=クローズ support.open=オープン @@ -1052,6 +1067,7 @@ settings.net.creationDateColumn=既定 settings.net.connectionTypeColumn=イン/アウト settings.net.sentDataLabel=通信されたデータ統計 settings.net.receivedDataLabel=受信されたデータ統計 +settings.net.chainHeightLabel=BTCの最新ブロック高さ settings.net.roundTripTimeColumn=往復 settings.net.sentBytesColumn=送信済 settings.net.receivedBytesColumn=受信済 @@ -1066,6 +1082,7 @@ settings.net.needRestart=その変更を適用するには、アプリケーシ settings.net.notKnownYet=まだわかりません... settings.net.sentData=通信されたデータ: {0}, {1} メッセージ、 {2} メッセージ/秒 settings.net.receivedData=受信されたデータ: {0}, {1} メッセージ、 {2} メッセージ/秒 +settings.net.chainHeight=Bisq: {0} | ピア: {1} settings.net.ips=[IPアドレス:ポート | ホスト名:ポート | onionアドレス:ポート](コンマ区切り)。デフォルト(8333)が使用される場合、ポートは省略できます。 settings.net.seedNode=シードノード settings.net.directPeer=ピア (ダイレクト) @@ -1074,7 +1091,7 @@ settings.net.inbound=インバウンド settings.net.outbound=アウトバウンド settings.net.reSyncSPVChainLabel=SPVチェーンを再同期 settings.net.reSyncSPVChainButton=SPVファイルを削除してを再同期 -settings.net.reSyncSPVSuccess=SPVチェーンファイルは、次回の起動時に削除されます。今すぐアプリケーションを再起動する必要があります。\n\n再起動後、ネットワークとの再同期に時間がかかることがあり、再同期が完了するとすべてのトランザクションのみが表示されます。\n\nトランザクションの数そしてウォレットの時代によって、再同期は数時間かかり、CPUのリソースを100%消費します。再同期プロセスを割り込みしないで下さい。さもなければやり直す必要があります。 +settings.net.reSyncSPVSuccess=Are you sure you want to do an SPV resync? If you proceed, the SPV chain file will be deleted on the next startup.\n\nAfter the restart it can take a while to resync with the network and you will only see all transactions once the resync is completed.\n\nDepending on the number of transactions and the age of your wallet the resync can take up to a few hours and consumes 100% of CPU. Do not interrupt the process otherwise you have to repeat it. settings.net.reSyncSPVAfterRestart=SPVチェーンファイルが削除されました。しばらくお待ちください。ネットワークとの再同期には時間がかかる場合があります。 settings.net.reSyncSPVAfterRestartCompleted=再同期が完了しました。アプリケーションを再起動してください。 settings.net.reSyncSPVFailed=SPVチェーンファイルを削除できませんでした。\nエラー: {0} @@ -1161,9 +1178,19 @@ account.menu.paymentAccount=各国通貨口座 account.menu.altCoinsAccountView=アルトコインアカウント account.menu.password=ウォレットのパスワード account.menu.seedWords=ウォレットシード +account.menu.walletInfo=Wallet info account.menu.backup=バックアップ account.menu.notifications=通知 +account.menu.walletInfo.balance.headLine=Wallet balances +account.menu.walletInfo.balance.info=This shows the internal wallet balance including unconfirmed transactions.\nFor BTC, the internal wallet balance shown below should match the sum of the 'Available' and 'Reserved' balances shown in the top right of this window. +account.menu.walletInfo.xpub.headLine=Watch keys (xpub keys) +account.menu.walletInfo.walletSelector={0} {1} wallet +account.menu.walletInfo.path.headLine=HD keychain paths +account.menu.walletInfo.path.info=If you import seed words into another wallet (like Electrum), you'll need to define the path. This should only be done in emergency cases when you lose access to the Bisq wallet and data directory.\nKeep in mind that spending funds from a non-Bisq wallet can bungle the internal Bisq data structures associated with the wallet data, which can lead to failed trades.\n\nNEVER send BSQ from a non-Bisq wallet, as it will probably lead to an invalid BSQ transaction and losing your BSQ. + +account.menu.walletInfo.openDetails=Show raw wallet details and private keys + ## TODO should we rename the following to a gereric name? account.arbitratorRegistration.pubKey=パブリックキー @@ -1796,7 +1823,7 @@ dao.wallet.send.setDestinationAddress=あなたの出金先アドレスを記入 dao.wallet.send.send=BSQ残高の送信 dao.wallet.send.sendBtc=BTC残高の送信 dao.wallet.send.sendFunds.headline=出金リクエストを承認 -dao.wallet.send.sendFunds.details=送金中: {0}\n入金先アドレス: {1}\n必要なトランザクション手数料: {2} ({3} satoshis/vbyte)\nトランザクションvサイズ: {4} Kb\n\n入金先の受け取る金額: {5}\n\n本当にこの金額を出金しますか? +dao.wallet.send.sendFunds.details=Sending: {0}\nTo receiving address: {1}.\nRequired mining fee is: {2} ({3} satoshis/vbyte)\nTransaction vsize: {4} vKb\n\nThe recipient will receive: {5}\n\nAre you sure you want to withdraw that amount? dao.wallet.chainHeightSynced=最新検証済みブロック: {0} dao.wallet.chainHeightSyncing=ブロック待機中... {1}のうち{0}ブロックを検証済み dao.wallet.tx.type=タイプ @@ -1928,9 +1955,9 @@ dao.factsAndFigures.menuItem.transactions=BSQ トランザクション dao.factsAndFigures.dashboard.avgPrice90=90日間の平均BSQ/BTCのトレード価格 dao.factsAndFigures.dashboard.avgPrice30=30日間の平均BSQ/BTCのトレード価格 -dao.factsAndFigures.dashboard.avgUSDPrice90=90日間の加重平均USD/BSQトレード価格 -dao.factsAndFigures.dashboard.avgUSDPrice30=30日間の加重平均USD/BSQトレード価格 -dao.factsAndFigures.dashboard.marketCap=時価総額(トレード価格に基づく) +dao.factsAndFigures.dashboard.avgUSDPrice90=90日間の加重平均USD/BSQ価格 +dao.factsAndFigures.dashboard.avgUSDPrice30=30日間の加重平均USD/BSQ価格 +dao.factsAndFigures.dashboard.marketCap=時価総額(30日間の平均USD/BSQ価格に基づく) dao.factsAndFigures.dashboard.availableAmount=合計利用可能BSQ dao.factsAndFigures.supply.issuedVsBurnt=発行されたBSQ v. バーンされたBSQ @@ -2000,7 +2027,7 @@ disputeSummaryWindow.openDate=チケットオープン日 disputeSummaryWindow.role=取引者の役割 disputeSummaryWindow.payout=トレード金額の支払い disputeSummaryWindow.payout.getsTradeAmount=BTC {0}はトレード金額の支払いを受け取ります -disputeSummaryWindow.payout.getsAll=BTC {0} は全て受け取ります +disputeSummaryWindow.payout.getsAll=Max. payout to BTC {0} disputeSummaryWindow.payout.custom=任意の支払い disputeSummaryWindow.payoutAmount.buyer=買い手の支払額 disputeSummaryWindow.payoutAmount.seller=売り手の支払額 @@ -2154,6 +2181,7 @@ tradeDetailsWindow.tradingPeersOnion=トレード相手のonionアドレス tradeDetailsWindow.tradingPeersPubKeyHash=トレードピアのパブリックキーハッシュ tradeDetailsWindow.tradeState=トレード状態 tradeDetailsWindow.agentAddresses=仲裁者 / 調停人 +tradeDetailsWindow.detailData=Detail data walletPasswordWindow.headline=アンロックするためにパスワードを入力してください @@ -2183,6 +2211,8 @@ feeOptionWindow.info=あなたは取引手数料の支払いにBSQまたはBTC feeOptionWindow.optionsLabel=取引手数料の支払いに使用する通貨を選択してください feeOptionWindow.useBTC=BTCを使用 feeOptionWindow.fee={0} (≈ {1}) +feeOptionWindow.btcFeeWithFiatAndPercentage={0} (≈ {1} / {2}) +feeOptionWindow.btcFeeWithPercentage={0} ({1}) #################################################################### @@ -2226,6 +2256,7 @@ popup.warning.noMediatorsAvailable=利用可能な調停人がいません。 popup.warning.notFullyConnected=ネットワークへ完全に接続するまで待つ必要があります。\n起動までに約2分かかります。 popup.warning.notSufficientConnectionsToBtcNetwork=少なくとも{0}のビットコインネットワークへの接続が確立されるまでお待ちください。 popup.warning.downloadNotComplete=欠落しているビットコインブロックのダウンロードが完了するまで待つ必要があります。 +popup.warning.chainNotSynced=The Bisq wallet blockchain height is not synced correctly. If you recently started the application, please wait until one Bitcoin block has been published.\n\nYou can check the blockchain height in Settings/Network Info. If more than one block passes and this problem persists it may be stalled, in which case you should do an SPV resync. [HYPERLINK:https://bisq.wiki/Resyncing_SPV_file] popup.warning.removeOffer=本当にオファーを削除しますか?\nオファーを削除する場合、{0}のメイカー手数料が失われます。 popup.warning.tooLargePercentageValue=100%以上のパーセントを設定できません popup.warning.examplePercentageValue=パーセントの数字を入力してください。5.4%は「5.4」のように入力します。 @@ -2254,7 +2285,7 @@ popup.warning.openOffer.makerFeeTxRejected=ID{0}で識別されるオファー popup.warning.trade.txRejected.tradeFee=トレード手数料 popup.warning.trade.txRejected.deposit=デポジット -popup.warning.trade.txRejected=ID{1}で識別されるトレードのための{0}トランザクションがビットコインネットワークに拒否されました。\nトランザクションID= {2}} 。\nトレードは「失敗トレード」へ送られました。\n\"設定/ネットワーク情報\"を開いてSPV再同期を行って下さい。\nさらにサポートを受けるため、Bisq Keybaseチームのサポートチャンネルに連絡して下さい。 +popup.warning.trade.txRejected=The {0} transaction for trade with ID {1} was rejected by the Bitcoin network.\nTransaction ID={2}\nThe trade has been moved to failed trades.\nPlease go to \"Settings/Network info\" and do a SPV resync.\nFor further help please contact the Bisq support channel at the Bisq Keybase team. popup.warning.openOfferWithInvalidMakerFeeTx=ID{0}で識別されるオファーのためのメイカー手数料トランザクションが無効とされました。\nトランザクションID= {1} 。\n更なる問題を避けるため、そのオファーは削除されました。\n\"設定/ネットワーク情報\"を開いてSPV再同期を行って下さい。\nさらにサポートを受けるため、Bisq Keybaseチームのサポートチャンネルに連絡して下さい。 @@ -2264,14 +2295,15 @@ popup.info.cashDepositInfo=あなたの地域の銀行支店が現金デポジ popup.info.cashDepositInfo.confirm=デポジットを作成できるか確認します popup.info.shutDownWithOpenOffers=Bisqはシャットダウン中ですが、オファーはあります。\n\nこれらのオファーは、Bisqがシャットダウンされている間はP2Pネットワークでは利用できませんが、次回Bisqを起動したときにP2Pネットワークに再公開されます。\n\nオファーをオンラインに保つには、Bisqを実行したままにして、このコンピュータもオンラインにしたままにします(つまり、スタンバイモードにならないようにしてください。モニタースタンバイは問題ありません)。 popup.info.qubesOSSetupInfo=Qubes OS内でBisqを実行しているようです。\n\nBisqのqubeはセットアップガイドに従って設定されていることを確かめて下さい: [HYPERLINK:https://bisq.wiki/Running_Bisq_on_Qubes] +popup.warn.downGradePrevention=Downgrade from version {0} to version {1} is not supported. Please use the latest Bisq version. +popup.warn.daoRequiresRestart=There was a problem with synchronizing the DAO state. You have to restart the application to fix the issue. popup.privateNotification.headline=重要なプライベート通知! popup.securityRecommendation.headline=重要なセキュリティ勧告 popup.securityRecommendation.msg=ウォレットのパスワード保護をまだ有効にしてない場合は、使用することを検討してください。\n\nウォレットシードワードを書き留めることも強くお勧めします。 これらのシードワードは、あなたのビットコインウォレットを復元するためのマスターパスワードのようなものです。\n「ウォレットシード」セクションにてより詳細な情報を確認できます。\n\nまた、「バックアップ」セクションのアプリケーションデータフォルダ全体をバックアップするべきでしょう。 -popup.bitcoinLocalhostNode.msg=Bisqはローカルで動作するBitcoin Coreノード(ローカルホスト)を検出しました。Bisqを起動する前にこのノードが完全に同期されていることと、プルーニングモードで実行されていないことを確認してください。 -popup.bitcoinLocalhostNode.additionalRequirements=\n\n適切に設定されるノードの条件は、剪定が無効とされることそしてブルームフィルターが有効とされることです。 +popup.bitcoinLocalhostNode.msg=Bisq detected a Bitcoin Core node running on this machine (at localhost).\n\nPlease ensure:\n- the node is fully synced before starting Bisq\n- pruning is disabled ('prune=0' in bitcoin.conf)\n- bloom filters are enabled ('peerbloomfilters=1' in bitcoin.conf) popup.shutDownInProgress.headline=シャットダウン中 popup.shutDownInProgress.msg=アプリケーションのシャットダウンには数秒かかることがあります。\nこのプロセスを中断しないでください。 @@ -2303,15 +2335,12 @@ popup.accountSigning.signedByPeer=支払いアカウントの1つはトレード popup.accountSigning.peerLimitLifted=支払いアカウントの1つにおいて初期の制限は解除されました。\n\n{0} popup.accountSigning.peerSigner=支払いアカウントの1つは十分に熟成されて、初期の制限は解除されました。\n\n{0} -popup.accountSigning.singleAccountSelect.headline=アカウント年齢witnessを選択 -popup.accountSigning.singleAccountSelect.description=アカウント年齢witnessを検索 -popup.accountSigning.singleAccountSelect.datePicker=署名の時点を選択 +popup.accountSigning.singleAccountSelect.headline=Import unsigned account age witness popup.accountSigning.confirmSingleAccount.headline=選択されたアカウント年齢witnessを確認 popup.accountSigning.confirmSingleAccount.selectedHash=選択されたwitnessのハッシュ popup.accountSigning.confirmSingleAccount.button=アカウント年齢witnessを署名 popup.accountSigning.successSingleAccount.description=Witness {0} は署名された popup.accountSigning.successSingleAccount.success.headline=成功 -popup.accountSigning.successSingleAccount.signError=Witnessの署名が失敗しました, {0} popup.accountSigning.unsignedPubKeys.headline=無署名のパブリックキー popup.accountSigning.unsignedPubKeys.sign=パブリックキーを署名 @@ -2447,8 +2476,8 @@ navigation.dao.wallet.receive=「DAO/BSQウォレット/受取」 formatter.formatVolumeLabel={0} 額{1} formatter.makerTaker=メイカーは{0} {1} / テイカーは{2} {3} -formatter.youAreAsMaker=あなたは{0} {1}のメイカー / テイカーは{2} {3} -formatter.youAreAsTaker=あなたは{0} {1}のテイカー / メイカーは{2} {3} +formatter.youAreAsMaker=You are: {1} {0} (maker) / Taker is: {3} {2} +formatter.youAreAsTaker=You are: {1} {0} (taker) / Maker is: {3} {2} formatter.youAre=あなたは{0} {1} ({2} {3}) formatter.youAreCreatingAnOffer.fiat=あなたはオファーを{0} {1}に作成中です formatter.youAreCreatingAnOffer.altcoin=あなたはオファーを{0} {1} ({2} {3})に作成中です @@ -2561,6 +2590,7 @@ payment.venmo.venmoUserName=Venmo ユーザー名 payment.popmoney.accountId=メールか電話番号 payment.promptPay.promptPayId=市民ID/納税者番号または電話番号 payment.supportedCurrencies=サポートされている通貨 +payment.supportedCurrenciesForReceiver=Currencies for receiving funds payment.limitations=制限事項 payment.salt=アカウント年齢を検証するためのソルト payment.error.noHexSalt=ソルトはHEXフォーマットである必要があります。\nアカウントの年齢を維持するために古いアカウントからソルトを送金したい場合は、ソルトフィールドを編集することをお勧めします。 アカウントの年齢は、アカウントソルトおよび識別口座データ(例えば、IBAN)を使用することによって検証されます。 @@ -2635,7 +2665,8 @@ payment.japan.recipient=名義 payment.australia.payid=PayID payment.payid=金融機関と繋がっているPayID。例えばEメールアドレスそれとも携帯電話番号。 payment.payid.info=銀行、信用金庫、あるいは住宅金融組合アカウントと安全に繋がれるPayIDとして使われる電話番号、Eメールアドレス、それともオーストラリア企業番号(ABN)。すでにオーストラリアの金融機関とPayIDを作った必要があります。送金と受取の金融機関は両方PayIDをサポートする必要があります。詳しくは以下を訪れて下さい [HYPERLINK:https://payid.com.au/faqs/] -payment.amazonGiftCard.info=アマゾンeGiftカードで支払うには、アマゾンアカウントからeGiftカードを買って、BTC売り手のEメールアドレスあるいは携帯電話番号を受取人に設定します。アマゾンは受取人へメールあるいはSMSを送ります。メッセージ・フィールドにトレードIDを入力して下さい。\n\nアマゾンeGiftカードは同じ通貨を使うアマゾンアカウントのみに受け取られることができます。\n\n詳しくはアマゾンeGiftカードホームページを訪れて下さい。 [HYPERLINK:https://www.amazon.com/Amazon-1_US_Email-eGift-Card/dp/B004LLIKVU] +payment.amazonGiftCard.info=To pay with Amazon eGift Card, you will need to send an Amazon eGift Card to the BTC seller via your Amazon account. \n\nBisq will show the BTC seller''s email address or phone number where the gift card should be sent, and you must include the trade ID in the gift card''s message field. Please see the wiki [HYPERLINK:https://bisq.wiki/Amazon_eGift_card] for further details and best practices. \n\nThree important notes:\n- try to send gift cards with amounts of 100 USD or smaller, as Amazon is known to flag larger gift cards as fraudulent\n- try to use creative, believable text for the gift card''s message (e.g., "Happy birthday Susan!") along with the trade ID (and use trader chat to tell your trading peer the reference text you picked so they can verify your payment)\n- Amazon eGift Cards can only be redeemed on the Amazon website they were purchased on (e.g., a gift card purchased on amazon.it can only be redeemed on amazon.it) + # We use constants from the code so we do not use our normal naming convention # dynamic values are not recognized by IntelliJ diff --git a/core/src/main/resources/i18n/displayStrings_pt-br.properties b/core/src/main/resources/i18n/displayStrings_pt-br.properties index ca804fcffd..e27eabcf27 100644 --- a/core/src/main/resources/i18n/displayStrings_pt-br.properties +++ b/core/src/main/resources/i18n/displayStrings_pt-br.properties @@ -71,6 +71,7 @@ shared.amountWithCur=Quantidade em {0} shared.volumeWithCur=Volume em {0} shared.currency=Moeda shared.market=Mercado +shared.deviation=Deviation shared.paymentMethod=Método de pagamento shared.tradeCurrency=Moeda negociada shared.offerType=Tipo de oferta @@ -104,7 +105,6 @@ shared.selectTradingAccount=Selecionar conta de negociação shared.fundFromSavingsWalletButton=Transferir fundos da carteira Bisq shared.fundFromExternalWalletButton=Abrir sua carteira externa para prover fundos shared.openDefaultWalletFailed=Failed to open a Bitcoin wallet application. Are you sure you have one installed? -shared.distanceInPercent=Distância em % do preço de mercado shared.belowInPercent=% abaixo do preço de mercado shared.aboveInPercent=% acima do preço de mercado shared.enterPercentageValue=Insira a % @@ -191,7 +191,7 @@ shared.tradeWalletBalance=Saldo da carteira de negociação shared.makerTxFee=Ofertante: {0} shared.takerTxFee=Aceitador: {0} shared.iConfirm=Eu confirmo -shared.tradingFeeInBsqInfo=equivalente a {0} utilizado como taxa de negociação +shared.tradingFeeInBsqInfo=≈ {0} shared.openURL=Aberto {0} shared.fiat=Fiat shared.crypto=Cripto @@ -218,6 +218,9 @@ shared.refundAgentForSupportStaff=Árbitro shared.delayedPayoutTxId=Delayed payout transaction ID shared.delayedPayoutTxReceiverAddress=Delayed payout transaction sent to shared.unconfirmedTransactionsLimitReached=No momento, você possui muitas transações não-confirmadas. Tente novamente mais tarde. +shared.numItemsLabel=Number of entries: {0} +shared.filter=Filter +shared.enabled=Enabled #################################################################### @@ -248,14 +251,14 @@ mainView.balance.locked=Travado em negociações mainView.balance.reserved.short=Reservado mainView.balance.locked.short=Travado -mainView.footer.usingTor=(usando Tor) +mainView.footer.usingTor=(via Tor) mainView.footer.localhostBitcoinNode=(localhost) -mainView.footer.btcInfo={0} {1} {2} -mainView.footer.btcFeeRate=/ Current fee rate: {0} sat/vB +mainView.footer.btcInfo={0} {1} +mainView.footer.btcFeeRate=/ Fee rate: {0} sat/vB mainView.footer.btcInfo.initializing=Conectando-se à rede Bitcoin mainView.footer.bsqInfo.synchronizing=/ Sincronizando DAO -mainView.footer.btcInfo.synchronizingWith=Sincronizando com -mainView.footer.btcInfo.synchronizedWith=Synced with +mainView.footer.btcInfo.synchronizingWith=Synchronizing with {0} at block: {1} / {2} +mainView.footer.btcInfo.synchronizedWith=Synced with {0} at block {1} mainView.footer.btcInfo.connectingTo=Conectando-se a mainView.footer.btcInfo.connectionFailed=Falha na conexão à mainView.footer.p2pInfo=Bitcoin network peers: {0} / Bisq network peers: {1} @@ -336,10 +339,10 @@ offerbook.offerersAcceptedBankSeats=Países aceitos como sede bancária (tomador offerbook.availableOffers=Ofertas disponíveis offerbook.filterByCurrency=Filtrar por moeda offerbook.filterByPaymentMethod=Filtrar por método de pagamento -offerbook.timeSinceSigning=Signed since +offerbook.timeSinceSigning=Account info offerbook.timeSinceSigning.info=Esta conta foi verificada e {0} offerbook.timeSinceSigning.info.arbitrator=assinada por um árbitro e pode assinar contas de pares -offerbook.timeSinceSigning.info.peer=assinada por um par, esperando os limites serem levantados +offerbook.timeSinceSigning.info.peer=signed by a peer, waiting %d days for limits to be lifted offerbook.timeSinceSigning.info.peerLimitLifted=assinada por um par e limites foram levantados offerbook.timeSinceSigning.info.signer=assinada por um par e pode assinar contas de pares (limites levantados) offerbook.timeSinceSigning.info.banned=conta foi banida @@ -349,9 +352,12 @@ offerbook.xmrAutoConf=Is auto-confirm enabled offerbook.timeSinceSigning.help=Quando você completa uma negociação bem sucedida com um par que tem uma conta de pagamento assinada, a sua conta de pagamento é assinada.\n{0} dias depois, o limite inicial de {1} é levantado e sua conta pode assinar as contas de pagamento de outros pares. offerbook.timeSinceSigning.notSigned=Ainda não assinada +offerbook.timeSinceSigning.notSigned.ageDays={0} dias offerbook.timeSinceSigning.notSigned.noNeed=N/D -shared.notSigned=Esta conta ainda não foi assinada -shared.notSigned.noNeed=Esse tipo de conta não usa assinatura +shared.notSigned=This account has not been signed yet and was created {0} days ago +shared.notSigned.noNeed=This account type does not require signing +shared.notSigned.noNeedDays=This account type does not require signing and was created {0} days ago +shared.notSigned.noNeedAlts=Altcoin accounts do not feature signing or aging offerbook.nrOffers=N.º de ofertas: {0} offerbook.volume={0} (mín. - máx.) @@ -403,7 +409,7 @@ offerbook.info.sellAboveMarketPrice=Você irá receber {0} a mais do que o atual offerbook.info.buyBelowMarketPrice=Você irá pagar {0} a menos do que o atual preço de mercado (atualizado a cada minuto). offerbook.info.buyAtFixedPrice=Você irá comprar nesse preço fixo. offerbook.info.sellAtFixedPrice=Você irá vender neste preço fixo. -offerbook.info.noArbitrationInUserLanguage=Em caso de disputa, a arbitragem para essa oferta será realizada em {0}. O idioma atualmente está definido como {1}. +offerbook.info.noArbitrationInUserLanguage=Em caso de disputa, a arbitragem para essa oferta será realizada em {0}. O idioma atualmente está definido como {1}. offerbook.info.roundedFiatVolume=O valor foi arredondado para aumentar a privacidade da sua negociação. #################################################################### @@ -435,11 +441,15 @@ createOffer.warning.sellBelowMarketPrice=Você irá sempre receber {0}% a menos createOffer.warning.buyAboveMarketPrice=Você irá sempre pagar {0}% a mais do que o atual preço de mercado e o preço da sua oferta será atualizada constantemente. createOffer.tradeFee.descriptionBTCOnly=Taxa de negociação createOffer.tradeFee.descriptionBSQEnabled=Escolha a moeda da taxa de transação -createOffer.tradeFee.fiatAndPercent=≈ {0} / {1} da quantia da negociação + +createOffer.triggerPrice.prompt=Set optional trigger price +createOffer.triggerPrice.label=Deactivate offer if market price is {0} +createOffer.triggerPrice.tooltip=As protecting against drastic price movements you can set a trigger price which deactivates the offer if the market price reaches that value. +createOffer.triggerPrice.invalid.tooLow=Value must be higher than {0} +createOffer.triggerPrice.invalid.tooHigh=Value must be lower than {0} # new entries createOffer.placeOfferButton=Revisar: Criar oferta para {0} bitcoin -createOffer.alreadyFunded=Você já havia financiado aquela oferta.\nSeus fundos foram movidos para sua carteira local da Bisq e estão disponíveis para retirada na janela \"Fundos/Enviar fundos\". createOffer.createOfferFundWalletInfo.headline=Financiar sua oferta # suppress inspection "TrailingSpacesInProperty" createOffer.createOfferFundWalletInfo.tradeAmount=- Quantia da negociação: {0} \n @@ -496,7 +506,6 @@ takeOffer.error.message=Ocorreu um erro ao aceitar a oferta.\n\n{0} # new entries takeOffer.takeOfferButton=Revisar: Aceitar oferta para {0} bitcoin takeOffer.noPriceFeedAvailable=Você não pode aceitar essa oferta pois ela usa uma porcentagem do preço baseada no preço de mercado, mas o canal de preços está indisponível no momento. -takeOffer.alreadyFunded.movedFunds=Você já havia financiado essa oferta.\nSeus fundos foram movidos para sua carteira Bisq local e estão disponíveis para retirada na tela \"Fundos/Enviar fundos\" takeOffer.takeOfferFundWalletInfo.headline=Financiar sua negociação # suppress inspection "TrailingSpacesInProperty" takeOffer.takeOfferFundWalletInfo.tradeAmount=- Quantia a negociar: {0} \n @@ -524,6 +533,10 @@ takeOffer.tac=Ao aceitar essa oferta, eu concordo com as condições de negocia # Offerbook / Edit offer #################################################################### +openOffer.header.triggerPrice=Preço gatilho +openOffer.triggerPrice=Trigger price {0} +openOffer.triggered=The offer has been deactivated because the market price reached your trigger price.\nPlease edit the offer to define a new trigger price + editOffer.setPrice=Definir preço editOffer.confirmEdit=Editar oferta editOffer.publishOffer=Publicando a sua oferta. @@ -541,6 +554,8 @@ portfolio.tab.history=Histórico portfolio.tab.failed=Falha portfolio.tab.editOpenOffer=Editar oferta +portfolio.closedTrades.deviation.help=Percentage price deviation from market + portfolio.pending.invalidDelayedPayoutTx=There is an issue with a missing or invalid transaction.\n\nPlease do NOT send the fiat or altcoin payment. Contact Bisq developers on Keybase [HYPERLINK:https://keybase.io/team/bisq] or on the forum [HYPERLINK:https://bisq.community] for further assistance.\n\nError message: {0} portfolio.pending.step1.waitForConf=Aguardar confirmação da blockchain @@ -886,13 +901,12 @@ funds.tx.noTxAvailable=Sem transações disponíveis funds.tx.revert=Reverter funds.tx.txSent=Transação enviada com sucesso para um novo endereço em sua carteira Bisq local. funds.tx.direction.self=Enviar para você mesmo -funds.tx.daoTxFee=Taxa do minerador para tx da DAO +funds.tx.daoTxFee=Taxa de mineração para transação de BSQ funds.tx.reimbursementRequestTxFee=Solicitar reembolso funds.tx.compensationRequestTxFee=Pedido de compensação funds.tx.dustAttackTx=Poeira recebida funds.tx.dustAttackTx.popup=Esta transação está enviando uma quantia muito pequena de BTC para a sua carteira e pode ser uma tentativa das empresas de análise da blockchain para espionar a sua carteira.\n\nSe você usar esse output em uma transação eles decobrirão que você provavelmente também é o proprietário de outros endereços (mistura de moedas).\n\nPara proteger sua privacidade a carteira Bisq ignora tais outputs de poeira para fins de consumo e na tela de saldo. Você pode definir a quantia limite a partir da qual um output é considerado poeira nas configurações." - #################################################################### # Support #################################################################### @@ -943,6 +957,7 @@ support.error=O destinatário não pôde processar a mensagem. Erro: {0} support.buyerAddress=Endereço do comprador de BTC support.sellerAddress=Endereço do vendedor de BTC support.role=Função +support.agent=Support agent support.state=Estado support.closed=Fechado support.open=Aberto @@ -1019,7 +1034,7 @@ setting.preferences.dao.isDaoFullNode=Executar Bisq como nó completo DAO setting.preferences.dao.rpcUser=Nome de usuário de RPC setting.preferences.dao.rpcPw=Senha de RPC setting.preferences.dao.blockNotifyPort=Bloquear porta de notificação -setting.preferences.dao.fullNodeInfo=Para executar o Bisq como nó completo da DAO você precisa ter Bitcoin Core em rodando localmente e RPC ativado. Todos os requisitos estão documentados em '' {0} ''. +setting.preferences.dao.fullNodeInfo=Para executar o Bisq como nó completo da DAO você precisa ter Bitcoin Core em rodando localmente e RPC ativado. Todos os requisitos estão documentados em '' {0} ''. setting.preferences.dao.fullNodeInfo.ok=Abrir página de documentos setting.preferences.dao.fullNodeInfo.cancel=Não, eu fico com o modo nó lite settings.preferences.editCustomExplorer.headline=Explorer Settings @@ -1052,6 +1067,7 @@ settings.net.creationDateColumn=Estabelecida settings.net.connectionTypeColumn=Entrada/Saída settings.net.sentDataLabel=Sent data statistics settings.net.receivedDataLabel=Received data statistics +settings.net.chainHeightLabel=Latest BTC block height settings.net.roundTripTimeColumn=Ping settings.net.sentBytesColumn=Enviado settings.net.receivedBytesColumn=Recebido @@ -1066,6 +1082,7 @@ settings.net.needRestart=Você precisa reiniciar o programa para aplicar esta al settings.net.notKnownYet=Ainda desconhecido... settings.net.sentData=Sent data: {0}, {1} messages, {2} messages/sec settings.net.receivedData=Received data: {0}, {1} messages, {2} messages/sec +settings.net.chainHeight=Bisq: {0} | Peers: {1} settings.net.ips=[Endeço IP:porta | nome do host:porta | endereço onion:porta] (seperados por vírgulas). A porta pode ser omitida quando a porta padrão (8333) for usada. settings.net.seedNode=Nó semente settings.net.directPeer=Par (direto) @@ -1074,7 +1091,7 @@ settings.net.inbound=entrada settings.net.outbound=saída settings.net.reSyncSPVChainLabel=Ressincronizar SPV chain settings.net.reSyncSPVChainButton=Remover arquivo SPV e ressincronizar -settings.net.reSyncSPVSuccess=O arquivo da corrente SPV será apagado na próxima inicialização. Você precisa reiniciar seu aplicativo agora. \n\nApós a reinicialização, pode demorar um pouco para ressincronizar com a rede e você apenas verá todas as transações quando a ressincronização for concluída.\n\nDependendo do número de transações e da idade da sua carteira, a ressincronização pode demorar até algumas horas e consumir 100% do processador. Não interrompa este processo pois, caso contrário, você precisará repeti-lo. +settings.net.reSyncSPVSuccess=Are you sure you want to do an SPV resync? If you proceed, the SPV chain file will be deleted on the next startup.\n\nAfter the restart it can take a while to resync with the network and you will only see all transactions once the resync is completed.\n\nDepending on the number of transactions and the age of your wallet the resync can take up to a few hours and consumes 100% of CPU. Do not interrupt the process otherwise you have to repeat it. settings.net.reSyncSPVAfterRestart=O arquivo SPV chain foi removido. Por favor, tenha paciência, pois a ressincronização com a rede pode demorar. settings.net.reSyncSPVAfterRestartCompleted=A ressincronização terminou. Favor reiniciar o programa. settings.net.reSyncSPVFailed=Não foi possível apagar o arquivo da SPV chain.\nErro: {0} @@ -1161,9 +1178,19 @@ account.menu.paymentAccount=Contas de moedas nacionais account.menu.altCoinsAccountView=Contas de altcoins account.menu.password=Senha da carteira account.menu.seedWords=Semente da carteira +account.menu.walletInfo=Wallet info account.menu.backup=Backup account.menu.notifications=Notificações +account.menu.walletInfo.balance.headLine=Wallet balances +account.menu.walletInfo.balance.info=This shows the internal wallet balance including unconfirmed transactions.\nFor BTC, the internal wallet balance shown below should match the sum of the 'Available' and 'Reserved' balances shown in the top right of this window. +account.menu.walletInfo.xpub.headLine=Watch keys (xpub keys) +account.menu.walletInfo.walletSelector={0} {1} wallet +account.menu.walletInfo.path.headLine=HD keychain paths +account.menu.walletInfo.path.info=If you import seed words into another wallet (like Electrum), you'll need to define the path. This should only be done in emergency cases when you lose access to the Bisq wallet and data directory.\nKeep in mind that spending funds from a non-Bisq wallet can bungle the internal Bisq data structures associated with the wallet data, which can lead to failed trades.\n\nNEVER send BSQ from a non-Bisq wallet, as it will probably lead to an invalid BSQ transaction and losing your BSQ. + +account.menu.walletInfo.openDetails=Show raw wallet details and private keys + ## TODO should we rename the following to a gereric name? account.arbitratorRegistration.pubKey=Chave pública @@ -1796,7 +1823,7 @@ dao.wallet.send.setDestinationAddress=Preencha seu endereço de destino dao.wallet.send.send=Enviar fundos BSQ dao.wallet.send.sendBtc=Enviar fundos BTC dao.wallet.send.sendFunds.headline=Confirmar solicitação de retirada. -dao.wallet.send.sendFunds.details=Sending: {0}\nTo receiving address: {1}.\nRequired transaction fee is: {2} ({3} satoshis/vbyte)\nTransaction vsize: {4} vKb\n\nThe recipient will receive: {5}\n\nAre you sure you want to withdraw that amount? +dao.wallet.send.sendFunds.details=Sending: {0}\nTo receiving address: {1}.\nRequired mining fee is: {2} ({3} satoshis/vbyte)\nTransaction vsize: {4} vKb\n\nThe recipient will receive: {5}\n\nAre you sure you want to withdraw that amount? dao.wallet.chainHeightSynced=Último bloco verificado: {0} dao.wallet.chainHeightSyncing=Aguardando blocos... Verificados {0} blocos de {1} dao.wallet.tx.type=Tipo @@ -1928,9 +1955,9 @@ dao.factsAndFigures.menuItem.transactions=Transações BSQ dao.factsAndFigures.dashboard.avgPrice90=Média de 90 dias BSQ/BTC dao.factsAndFigures.dashboard.avgPrice30=Média de 30 dias BSQ/BTC -dao.factsAndFigures.dashboard.avgUSDPrice90=90 days volume weighted average USD/BSQ trade price -dao.factsAndFigures.dashboard.avgUSDPrice30=30 days volume weighted average USD/BSQ trade price -dao.factsAndFigures.dashboard.marketCap=Capitalização do mercado (com base no preço de negociação) +dao.factsAndFigures.dashboard.avgUSDPrice90=90 days volume weighted average USD/BSQ price +dao.factsAndFigures.dashboard.avgUSDPrice30=30 days volume weighted average USD/BSQ price +dao.factsAndFigures.dashboard.marketCap=Market capitalisation (based on 30 days average USD/BSQ price) dao.factsAndFigures.dashboard.availableAmount=Total de BSQ disponível dao.factsAndFigures.supply.issuedVsBurnt=BSQ emitido vs. BSQ queimado @@ -2000,7 +2027,7 @@ disputeSummaryWindow.openDate=Data da abertura do ticket disputeSummaryWindow.role=Função do negociador disputeSummaryWindow.payout=Pagamento da quantia negociada disputeSummaryWindow.payout.getsTradeAmount={0} BTC fica com o pagamento da negociação -disputeSummaryWindow.payout.getsAll={0} BTC fica com tudo +disputeSummaryWindow.payout.getsAll=Max. payout to BTC {0} disputeSummaryWindow.payout.custom=Pagamento personalizado disputeSummaryWindow.payoutAmount.buyer=Quantia do pagamento do comprador disputeSummaryWindow.payoutAmount.seller=Quantia de pagamento do vendedor @@ -2154,6 +2181,7 @@ tradeDetailsWindow.tradingPeersOnion=Endereço onion dos parceiros de negociaç tradeDetailsWindow.tradingPeersPubKeyHash=Trading peers pubkey hash tradeDetailsWindow.tradeState=Estado da negociação tradeDetailsWindow.agentAddresses=Árbitro/Mediador +tradeDetailsWindow.detailData=Detail data walletPasswordWindow.headline=Digite senha para abrir: @@ -2183,6 +2211,8 @@ feeOptionWindow.info=Você pode optar por pagar a taxa de negociação em BSQ ou feeOptionWindow.optionsLabel=Escolha a moeda para pagar a taxa de negociação feeOptionWindow.useBTC=Usar BTC feeOptionWindow.fee={0} (≈ {1}) +feeOptionWindow.btcFeeWithFiatAndPercentage={0} (≈ {1} / {2}) +feeOptionWindow.btcFeeWithPercentage={0} ({1}) #################################################################### @@ -2226,6 +2256,7 @@ popup.warning.noMediatorsAvailable=Não há mediadores disponíveis. popup.warning.notFullyConnected=Você precisa aguardar até estar totalmente conectado à rede.\nIsto pode levar até 2 minutos na inicialização do programa. popup.warning.notSufficientConnectionsToBtcNetwork=Você precisa esperar até ter pelo menos {0} conexões à rede Bitcoin. popup.warning.downloadNotComplete=Você precisa aguardar até que termine o download dos blocos de Bitcoin restantes +popup.warning.chainNotSynced=The Bisq wallet blockchain height is not synced correctly. If you recently started the application, please wait until one Bitcoin block has been published.\n\nYou can check the blockchain height in Settings/Network Info. If more than one block passes and this problem persists it may be stalled, in which case you should do an SPV resync. [HYPERLINK:https://bisq.wiki/Resyncing_SPV_file] popup.warning.removeOffer=Tem certeza que deseja remover essa oferta?\nA taxa de oferta de {0} será perdida se você removê-la. popup.warning.tooLargePercentageValue=Você não pode definir uma porcentagem superior a 100%. popup.warning.examplePercentageValue=Digite um número percentual, como \"5.4\" para 5.4% @@ -2254,7 +2285,7 @@ popup.warning.openOffer.makerFeeTxRejected=A transação de taxa de ofertante pa popup.warning.trade.txRejected.tradeFee=taxa de negociação popup.warning.trade.txRejected.deposit=depósito -popup.warning.trade.txRejected=A transação {0} para a negociação com ID {1} foi rejeitada pela rede Bitcoin.\nID da transação={2}\nA negociação foi movida para negociações com erro.\n Por favor, vá até "Configurações/Informações da rede" e ressincronize o arquivo SPV.\n\nPara mais informações, por favor acesse o canal #support do time da Bisq na Keybase. +popup.warning.trade.txRejected=The {0} transaction for trade with ID {1} was rejected by the Bitcoin network.\nTransaction ID={2}\nThe trade has been moved to failed trades.\nPlease go to \"Settings/Network info\" and do a SPV resync.\nFor further help please contact the Bisq support channel at the Bisq Keybase team. popup.warning.openOfferWithInvalidMakerFeeTx=A transação de taxa de ofertante para a oferta com ID {0} é inválida.\nID da transação: {1}.\nPor favor, vá até "Configurações/Informações da rede" e ressincronize o arquivo SPV.\nPara mais informações, por favor acesse o canal #support do time da Bisq na Keybase. @@ -2264,14 +2295,15 @@ popup.info.cashDepositInfo=Certifique-se de que você possui uma agência bancá popup.info.cashDepositInfo.confirm=Eu confirmo que posso fazer o depósito popup.info.shutDownWithOpenOffers=O Bisq está desligando, mas há ofertas abertas.\n\nEstas ofertas não ficarão disponíveis na rede P2P enquanto o Bisq estiver desligado, mas elas serão republicadas na rede assim que você reiniciar o programa.\n\nPara manter suas ofertas online, mantenha o Bisq aberto e certifique-se de que o seu computador continua online (ex: certifique-se de que o computador não está entrando em modo de hibernação). popup.info.qubesOSSetupInfo=It appears you are running Bisq on Qubes OS. \n\nPlease make sure your Bisq qube is setup according to our Setup Guide at [HYPERLINK:https://bisq.wiki/Running_Bisq_on_Qubes]. +popup.warn.downGradePrevention=Downgrade from version {0} to version {1} is not supported. Please use the latest Bisq version. +popup.warn.daoRequiresRestart=There was a problem with synchronizing the DAO state. You have to restart the application to fix the issue. popup.privateNotification.headline=Notificação privada importante! popup.securityRecommendation.headline=Recomendação de segurança importante popup.securityRecommendation.msg=Lembre-se de proteger a sua carteira com uma senha, caso você já não tenha criado uma.\n\nRecomendamos que você escreva num papel as palavras da semente de sua carteira. Essas palavras funcionam como uma senha mestra para recuperar a sua carteira Bitcoin, caso o seu computador apresente algum problema.\nVocê irá encontrar mais informações na seção \"Semente da carteira\".\n\nTambém aconselhamos que você faça um backup completo da pasta de dados do programa na seção \"Backup\". -popup.bitcoinLocalhostNode.msg=O Bisq detectou um node do Bitcoin Core em execução no ambiente local (localhost).\nPor favor, certifique-se de que este node esteja totalmente sincronizado antes de iniciar o Bisq e que ele não esteja em execução em pruned mode. -popup.bitcoinLocalhostNode.additionalRequirements=\n\nPara que o nó esteja bem configurado, os requisitos são que o nó tenha pruning desativado e bloom filters ativados. +popup.bitcoinLocalhostNode.msg=Bisq detected a Bitcoin Core node running on this machine (at localhost).\n\nPlease ensure:\n- the node is fully synced before starting Bisq\n- pruning is disabled ('prune=0' in bitcoin.conf)\n- bloom filters are enabled ('peerbloomfilters=1' in bitcoin.conf) popup.shutDownInProgress.headline=Desligando popup.shutDownInProgress.msg=O desligamento do programa pode levar alguns segundos.\nPor favor, não interrompa este processo. @@ -2303,15 +2335,12 @@ popup.accountSigning.signedByPeer=Uma de suas contas de pagamento foi verificada popup.accountSigning.peerLimitLifted=O limite inicial para uma de suas contas acaba de ser aumentado. popup.accountSigning.peerSigner=Uma das suas contas é antiga o suficiente para assinar outras contas de pagamento e o limite para uma de suas contas acaba de ser aumentado\n\n{0} -popup.accountSigning.singleAccountSelect.headline=Select account age witness -popup.accountSigning.singleAccountSelect.description=Search for account age witness. -popup.accountSigning.singleAccountSelect.datePicker=Select point of time for signing +popup.accountSigning.singleAccountSelect.headline=Import unsigned account age witness popup.accountSigning.confirmSingleAccount.headline=Confirm selected account age witness popup.accountSigning.confirmSingleAccount.selectedHash=Selected witness hash popup.accountSigning.confirmSingleAccount.button=Sign account age witness popup.accountSigning.successSingleAccount.description=Witness {0} was signed popup.accountSigning.successSingleAccount.success.headline=Success -popup.accountSigning.successSingleAccount.signError=Failed to sign witness, {0} popup.accountSigning.unsignedPubKeys.headline=Unsigned Pubkeys popup.accountSigning.unsignedPubKeys.sign=Sign Pubkeys @@ -2447,8 +2476,8 @@ navigation.dao.wallet.receive=\"DAO/Carteira BSQ/Receber\" formatter.formatVolumeLabel={0} quantia{1} formatter.makerTaker=Ofertante: {1} de {0} / Aceitador: {3} de {2} -formatter.youAreAsMaker=Você está {0} {1} como ofertante / Aceitador está {2} {3} -formatter.youAreAsTaker=Você está {0} {1} como aceitador / Ofertante está {2} {3} +formatter.youAreAsMaker=You are: {1} {0} (maker) / Taker is: {3} {2} +formatter.youAreAsTaker=You are: {1} {0} (taker) / Maker is: {3} {2} formatter.youAre=Você está {0} {1} ({2} {3}) formatter.youAreCreatingAnOffer.fiat=Você está criando uma oferta para {0} {1} formatter.youAreCreatingAnOffer.altcoin=Você está criando uma oferta para {0} {1} ({2} {3}) @@ -2561,6 +2590,7 @@ payment.venmo.venmoUserName=Nome do usuário do Venmo payment.popmoney.accountId=E-mail ou nº de telefone payment.promptPay.promptPayId=ID de cidadão/ID de impostos ou nº de telefone payment.supportedCurrencies=Moedas disponíveis +payment.supportedCurrenciesForReceiver=Currencies for receiving funds payment.limitations=Limitações payment.salt=Sal para verificação da idade da conta payment.error.noHexSalt=The salt needs to be in HEX format.\nIt is only recommended to edit the salt field if you want to transfer the salt from an old account to keep your account age. The account age is verified by using the account salt and the identifying account data (e.g. IBAN). @@ -2635,7 +2665,8 @@ payment.japan.recipient=Nome payment.australia.payid=PayID payment.payid=PayID linked to financial institution. Like email address or mobile phone. payment.payid.info=A PayID like a phone number, email address or an Australian Business Number (ABN), that you can securely link to your bank, credit union or building society account. You need to have already created a PayID with your Australian financial institution. Both sending and receiving financial institutions must support PayID. For more information please check [HYPERLINK:https://payid.com.au/faqs/] -payment.amazonGiftCard.info=To pay with Amazon eGift Card you need to purchase an Amazon eGift Card at your Amazon account and use the BTC seller''s email or mobile nr. as receiver. Amazon sends then an email or text message to the receiver. Use the trade ID for the message field.\n\nAmazon eGift Cards can only be redeemed by Amazon accounts with the same currency.\n\nFor more information visit the Amazon eGift Card webpage. [HYPERLINK:https://www.amazon.com/Amazon-1_US_Email-eGift-Card/dp/B004LLIKVU] +payment.amazonGiftCard.info=To pay with Amazon eGift Card, you will need to send an Amazon eGift Card to the BTC seller via your Amazon account. \n\nBisq will show the BTC seller''s email address or phone number where the gift card should be sent, and you must include the trade ID in the gift card''s message field. Please see the wiki [HYPERLINK:https://bisq.wiki/Amazon_eGift_card] for further details and best practices. \n\nThree important notes:\n- try to send gift cards with amounts of 100 USD or smaller, as Amazon is known to flag larger gift cards as fraudulent\n- try to use creative, believable text for the gift card''s message (e.g., "Happy birthday Susan!") along with the trade ID (and use trader chat to tell your trading peer the reference text you picked so they can verify your payment)\n- Amazon eGift Cards can only be redeemed on the Amazon website they were purchased on (e.g., a gift card purchased on amazon.it can only be redeemed on amazon.it) + # We use constants from the code so we do not use our normal naming convention # dynamic values are not recognized by IntelliJ diff --git a/core/src/main/resources/i18n/displayStrings_pt.properties b/core/src/main/resources/i18n/displayStrings_pt.properties index 19fb55f4bf..1de32d23e4 100644 --- a/core/src/main/resources/i18n/displayStrings_pt.properties +++ b/core/src/main/resources/i18n/displayStrings_pt.properties @@ -71,6 +71,7 @@ shared.amountWithCur=Quantia em {0} shared.volumeWithCur=Volume em {0} shared.currency=Moeda shared.market=Mercado +shared.deviation=Deviation shared.paymentMethod=Método de pagamento shared.tradeCurrency=Moeda de negócio shared.offerType=Tipo de oferta @@ -104,7 +105,6 @@ shared.selectTradingAccount=Selecionar conta de negociação shared.fundFromSavingsWalletButton=Transferir fundos da carteira Bisq shared.fundFromExternalWalletButton=Abrir sua carteira externa para o financiamento shared.openDefaultWalletFailed=Failed to open a Bitcoin wallet application. Are you sure you have one installed? -shared.distanceInPercent=Distância em % do preço de mercado shared.belowInPercent=Abaixo % do preço de mercado shared.aboveInPercent=Acima % do preço de mercado shared.enterPercentageValue=Insira % do valor @@ -191,7 +191,7 @@ shared.tradeWalletBalance=Saldo da carteira de negócio shared.makerTxFee=Ofertante: {0} shared.takerTxFee=Aceitador: {0} shared.iConfirm=Eu confirmo -shared.tradingFeeInBsqInfo=equivalente à {0} utilizado como taxa de negociação +shared.tradingFeeInBsqInfo=≈ {0} shared.openURL=Abrir {0} shared.fiat=Moeda fiduciária shared.crypto=Cripto @@ -218,6 +218,9 @@ shared.refundAgentForSupportStaff=Agente de Reembolso shared.delayedPayoutTxId=Delayed payout transaction ID shared.delayedPayoutTxReceiverAddress=Delayed payout transaction sent to shared.unconfirmedTransactionsLimitReached=You have too many unconfirmed transactions at the moment. Please try again later. +shared.numItemsLabel=Number of entries: {0} +shared.filter=Filter +shared.enabled=Enabled #################################################################### @@ -248,14 +251,14 @@ mainView.balance.locked=Bloqueado em negócios mainView.balance.reserved.short=Reservado mainView.balance.locked.short=Bloqueado -mainView.footer.usingTor=(usando Tor) +mainView.footer.usingTor=(via Tor) mainView.footer.localhostBitcoinNode=(localhost) -mainView.footer.btcInfo={0} {1} {2} -mainView.footer.btcFeeRate=/ Current fee rate: {0} sat/vB +mainView.footer.btcInfo={0} {1} +mainView.footer.btcFeeRate=/ Fee rate: {0} sat/vB mainView.footer.btcInfo.initializing=Conectando à rede Bitcoin mainView.footer.bsqInfo.synchronizing=/ Sincronizando a OAD -mainView.footer.btcInfo.synchronizingWith=Sincronizando com -mainView.footer.btcInfo.synchronizedWith=Synced with +mainView.footer.btcInfo.synchronizingWith=Synchronizing with {0} at block: {1} / {2} +mainView.footer.btcInfo.synchronizedWith=Synced with {0} at block {1} mainView.footer.btcInfo.connectingTo=Conectando à mainView.footer.btcInfo.connectionFailed=Connection failed to mainView.footer.p2pInfo=Bitcoin network peers: {0} / Bisq network peers: {1} @@ -336,10 +339,10 @@ offerbook.offerersAcceptedBankSeats=Sede do banco aceite (aceitador):\n {0} offerbook.availableOffers=Ofertas disponíveis offerbook.filterByCurrency=Filtrar por moeda offerbook.filterByPaymentMethod=Filtrar por método de pagamento -offerbook.timeSinceSigning=Signed since +offerbook.timeSinceSigning=Account info offerbook.timeSinceSigning.info=Esta conta foi verificada e {0} offerbook.timeSinceSigning.info.arbitrator=assinada pelo árbitro e pode assinar contas de pares -offerbook.timeSinceSigning.info.peer=assinada por um par, esperando que os limites sejam aumentados +offerbook.timeSinceSigning.info.peer=signed by a peer, waiting %d days for limits to be lifted offerbook.timeSinceSigning.info.peerLimitLifted=assinada por um par e os limites foram aumentados offerbook.timeSinceSigning.info.signer=assinada por um par e pode assinar contas de pares (limites aumentados) offerbook.timeSinceSigning.info.banned=account was banned @@ -349,9 +352,12 @@ offerbook.xmrAutoConf=Is auto-confirm enabled offerbook.timeSinceSigning.help=Quando você completa com sucesso um negócio com um par que tenha uma conta de pagamento assinada, a sua conta de pagamento é assinada .\n{0} dias depois, o limite inicial de {1} é aumentado e a sua conta pode assinar contas de pagamento de outros pares. offerbook.timeSinceSigning.notSigned=Ainda não assinada +offerbook.timeSinceSigning.notSigned.ageDays={0} dias offerbook.timeSinceSigning.notSigned.noNeed=N/D -shared.notSigned=Esta conta ainda não foi assinada -shared.notSigned.noNeed=Este tipo de conta não usa assinaturas +shared.notSigned=This account has not been signed yet and was created {0} days ago +shared.notSigned.noNeed=This account type does not require signing +shared.notSigned.noNeedDays=This account type does not require signing and was created {0} days ago +shared.notSigned.noNeedAlts=Altcoin accounts do not feature signing or aging offerbook.nrOffers=Nº de ofertas: {0} offerbook.volume={0} (mín - máx) @@ -435,11 +441,15 @@ createOffer.warning.sellBelowMarketPrice=Receberá sempre menos {0}% do que o at createOffer.warning.buyAboveMarketPrice=Pagará sempre mais {0}% do que o atual preço de mercado pois o preço da sua oferta será atualizado continuamente. createOffer.tradeFee.descriptionBTCOnly=taxa de negócio createOffer.tradeFee.descriptionBSQEnabled=Selecione a moeda da taxa de negócio -createOffer.tradeFee.fiatAndPercent=≈ {0} / {1} da quantia de negócio + +createOffer.triggerPrice.prompt=Set optional trigger price +createOffer.triggerPrice.label=Deactivate offer if market price is {0} +createOffer.triggerPrice.tooltip=As protecting against drastic price movements you can set a trigger price which deactivates the offer if the market price reaches that value. +createOffer.triggerPrice.invalid.tooLow=Value must be higher than {0} +createOffer.triggerPrice.invalid.tooHigh=Value must be lower than {0} # new entries createOffer.placeOfferButton=Rever: Colocar oferta para {0} bitcoin -createOffer.alreadyFunded=Você já tinha financiado essa oferta.\nSeus fundos foram transferidos para sua carteira Bisq local e estão disponíveis para levantamento no ecrã \"Fundos/Enviar fundos\". createOffer.createOfferFundWalletInfo.headline=Financiar sua oferta # suppress inspection "TrailingSpacesInProperty" createOffer.createOfferFundWalletInfo.tradeAmount=- Quantia de negócio: {0} \n @@ -496,7 +506,6 @@ takeOffer.error.message=Ocorreu um erro ao aceitar a oferta .\n\n{0} # new entries takeOffer.takeOfferButton=Rever: Colocar oferta para {0} bitcoin takeOffer.noPriceFeedAvailable=Você não pode aceitar aquela oferta pois ela utiliza uma percentagem do preço baseada no preço de mercado, mas o feed de preços está indisponível no momento. -takeOffer.alreadyFunded.movedFunds=Você já tinha financiado essa oferta.\nSeus fundos foram transferidos para a sua carteira Bisq local e estão disponíveis para levantamento na ecrã \"Fundos/Enviar fundos\". takeOffer.takeOfferFundWalletInfo.headline=Financiar seu negócio # suppress inspection "TrailingSpacesInProperty" takeOffer.takeOfferFundWalletInfo.tradeAmount=- Quantia de negócio: {0} \n @@ -524,6 +533,10 @@ takeOffer.tac=Ao aceitar esta oferta, eu concordo com as condições de negócio # Offerbook / Edit offer #################################################################### +openOffer.header.triggerPrice=Preço de desencadeamento +openOffer.triggerPrice=Trigger price {0} +openOffer.triggered=The offer has been deactivated because the market price reached your trigger price.\nPlease edit the offer to define a new trigger price + editOffer.setPrice=Definir preço editOffer.confirmEdit=Confirmar: Editar oferta editOffer.publishOffer=Publicando sua oferta. @@ -541,6 +554,8 @@ portfolio.tab.history=Histórico portfolio.tab.failed=Falhou portfolio.tab.editOpenOffer=Editar oferta +portfolio.closedTrades.deviation.help=Percentage price deviation from market + portfolio.pending.invalidDelayedPayoutTx=There is an issue with a missing or invalid transaction.\n\nPlease do NOT send the fiat or altcoin payment. Contact Bisq developers on Keybase [HYPERLINK:https://keybase.io/team/bisq] or on the forum [HYPERLINK:https://bisq.community] for further assistance.\n\nError message: {0} portfolio.pending.step1.waitForConf=Esperando confirmação da blockchain @@ -886,13 +901,12 @@ funds.tx.noTxAvailable=Sem transações disponíveis funds.tx.revert=Reverter funds.tx.txSent=Transação enviada com sucesso para um novo endereço em sua carteira Bisq local. funds.tx.direction.self=Enviado à você mesmo -funds.tx.daoTxFee=Taxa do mineiro para tx da OAD +funds.tx.daoTxFee=Taxa do mineiro para tx de BSQ funds.tx.reimbursementRequestTxFee=Pedido de reembolso funds.tx.compensationRequestTxFee=Pedido de compensação funds.tx.dustAttackTx=Poeira recebida funds.tx.dustAttackTx.popup=Esta transação está enviando uma quantia muito pequena de BTC para a sua carteira e pode ser uma tentativa das empresas de análise da blockchain para espionar a sua carteira.\n\nSe você usar esse output em uma transação eles decobrirão que você provavelmente também é o proprietário de outros endereços (mistura de moedas).\n\nPara proteger sua privacidade a carteira Bisq ignora tais outputs de poeira para fins de consumo e no ecrã de saldo. Você pode definir a quantia limite a partir da qual um output é considerado poeira nas definições." - #################################################################### # Support #################################################################### @@ -943,6 +957,7 @@ support.error=O recipiente não pode processar a mensagem. Erro: {0} support.buyerAddress=Endereço do comprador de BTC support.sellerAddress=Endereço do vendedor de BTC support.role=Cargo +support.agent=Support agent support.state=Estado support.closed=Fechado support.open=Aberto @@ -1019,7 +1034,7 @@ setting.preferences.dao.isDaoFullNode=Executar Bisq como nó completo OAD setting.preferences.dao.rpcUser=Nome de usuário de RPC setting.preferences.dao.rpcPw=Senha de RPC setting.preferences.dao.blockNotifyPort=Bloquear porta de notificação -setting.preferences.dao.fullNodeInfo=Para executar o Bisq como nó completo da OAD você precisa ter Bitcoin Core em execução local e RPC ativado. Todos os requerimentos estão documentados em '' {0} ''. +setting.preferences.dao.fullNodeInfo=Para executar o Bisq como nó completo da OAD você precisa ter Bitcoin Core em execução local e RPC ativado. Todos os requerimentos estão documentados em '' {0} ''. setting.preferences.dao.fullNodeInfo.ok=Abrir página de documentos setting.preferences.dao.fullNodeInfo.cancel=Não, eu fico com o modo nó lite settings.preferences.editCustomExplorer.headline=Explorer Settings @@ -1052,6 +1067,7 @@ settings.net.creationDateColumn=Estabelecida settings.net.connectionTypeColumn=Entrando/Saindo settings.net.sentDataLabel=Sent data statistics settings.net.receivedDataLabel=Received data statistics +settings.net.chainHeightLabel=Latest BTC block height settings.net.roundTripTimeColumn=Ida-e-volta settings.net.sentBytesColumn=Enviado settings.net.receivedBytesColumn=Recebido @@ -1066,6 +1082,7 @@ settings.net.needRestart=Você precisa reiniciar o programa para aplicar essa al settings.net.notKnownYet=Ainda desconhecido... settings.net.sentData=Sent data: {0}, {1} messages, {2} messages/sec settings.net.receivedData=Received data: {0}, {1} messages, {2} messages/sec +settings.net.chainHeight=Bisq: {0} | Peers: {1} settings.net.ips=[endereço IP:porta | nome de host:porta | endereço onion:porta] (separado por vírgula). A porta pode ser omitida se a padrão for usada (8333). settings.net.seedNode=Nó semente settings.net.directPeer=Par (direto) @@ -1074,7 +1091,7 @@ settings.net.inbound=entrante settings.net.outbound=sainte settings.net.reSyncSPVChainLabel=Re-sincronizar corrente SPV settings.net.reSyncSPVChainButton=Remover ficheiro SPV e re-sincronizar -settings.net.reSyncSPVSuccess=O ficheiro da corrente SPV será apagado na próxima inicialização. Você precisa reiniciar o seu programa agora.\n\nApós a reinicialização, pode demorar um pouco para ressincronizar com a rede e você verá todas as transações apenas quando a ressincronização for concluída.\n\nDependendo do número de transações e da idade da sua carteira, a ressincronização pode levar algumas horas e consumir 100% do CPU. Não interrompa o processo, caso contrário você precisará repeti-lo. +settings.net.reSyncSPVSuccess=Are you sure you want to do an SPV resync? If you proceed, the SPV chain file will be deleted on the next startup.\n\nAfter the restart it can take a while to resync with the network and you will only see all transactions once the resync is completed.\n\nDepending on the number of transactions and the age of your wallet the resync can take up to a few hours and consumes 100% of CPU. Do not interrupt the process otherwise you have to repeat it. settings.net.reSyncSPVAfterRestart=O ficheiro da corrente SPV foi apagado. Por favor, seja paciente. Pode demorar um pouco para re-sincronizar com a rede. settings.net.reSyncSPVAfterRestartCompleted=A resincronização concluiu. Por favor reiniciar o programa. settings.net.reSyncSPVFailed=Não foi possível remover o ficherio da corrente SPV\nErro: {0} @@ -1161,9 +1178,19 @@ account.menu.paymentAccount=Contas de moedas nacionais account.menu.altCoinsAccountView=Contas de altcoins account.menu.password=Senha da carteira account.menu.seedWords=Semente da carteira +account.menu.walletInfo=Wallet info account.menu.backup=Backup account.menu.notifications=Notificações +account.menu.walletInfo.balance.headLine=Wallet balances +account.menu.walletInfo.balance.info=This shows the internal wallet balance including unconfirmed transactions.\nFor BTC, the internal wallet balance shown below should match the sum of the 'Available' and 'Reserved' balances shown in the top right of this window. +account.menu.walletInfo.xpub.headLine=Watch keys (xpub keys) +account.menu.walletInfo.walletSelector={0} {1} wallet +account.menu.walletInfo.path.headLine=HD keychain paths +account.menu.walletInfo.path.info=If you import seed words into another wallet (like Electrum), you'll need to define the path. This should only be done in emergency cases when you lose access to the Bisq wallet and data directory.\nKeep in mind that spending funds from a non-Bisq wallet can bungle the internal Bisq data structures associated with the wallet data, which can lead to failed trades.\n\nNEVER send BSQ from a non-Bisq wallet, as it will probably lead to an invalid BSQ transaction and losing your BSQ. + +account.menu.walletInfo.openDetails=Show raw wallet details and private keys + ## TODO should we rename the following to a gereric name? account.arbitratorRegistration.pubKey=Chave pública @@ -1796,7 +1823,7 @@ dao.wallet.send.setDestinationAddress=Preencha seu endereço de destino dao.wallet.send.send=Enviar fundos BSQ dao.wallet.send.sendBtc=Enviar fundos BTC dao.wallet.send.sendFunds.headline=Confirmar pedido de levantamento. -dao.wallet.send.sendFunds.details=Sending: {0}\nTo receiving address: {1}.\nRequired transaction fee is: {2} ({3} satoshis/vbyte)\nTransaction vsize: {4} vKb\n\nThe recipient will receive: {5}\n\nAre you sure you want to withdraw that amount? +dao.wallet.send.sendFunds.details=Sending: {0}\nTo receiving address: {1}.\nRequired mining fee is: {2} ({3} satoshis/vbyte)\nTransaction vsize: {4} vKb\n\nThe recipient will receive: {5}\n\nAre you sure you want to withdraw that amount? dao.wallet.chainHeightSynced=Último bloco verificado: {0} dao.wallet.chainHeightSyncing=Esperando blocos... {0} dos {1} blocos verificados dao.wallet.tx.type=Tipo @@ -1928,9 +1955,9 @@ dao.factsAndFigures.menuItem.transactions=Transações BSQ dao.factsAndFigures.dashboard.avgPrice90=Média de 90 dias do preço de negócio de BSQ/BTC dao.factsAndFigures.dashboard.avgPrice30=Média de 30 dias do preço de negócio de BSQ/BTC -dao.factsAndFigures.dashboard.avgUSDPrice90=90 days volume weighted average USD/BSQ trade price -dao.factsAndFigures.dashboard.avgUSDPrice30=30 days volume weighted average USD/BSQ trade price -dao.factsAndFigures.dashboard.marketCap=Capitalização do mercado (com base no preço de negócio) +dao.factsAndFigures.dashboard.avgUSDPrice90=90 days volume weighted average USD/BSQ price +dao.factsAndFigures.dashboard.avgUSDPrice30=30 days volume weighted average USD/BSQ price +dao.factsAndFigures.dashboard.marketCap=Market capitalisation (based on 30 days average USD/BSQ price) dao.factsAndFigures.dashboard.availableAmount=Total BSQ disponível dao.factsAndFigures.supply.issuedVsBurnt=BSQ emitido v. BSQ queimado @@ -2000,7 +2027,7 @@ disputeSummaryWindow.openDate=Data de abertura do bilhete disputeSummaryWindow.role=Função do negociador disputeSummaryWindow.payout=Pagamento da quantia de negócio disputeSummaryWindow.payout.getsTradeAmount={0} de BTC fica com o pagamento da quantia de negócio -disputeSummaryWindow.payout.getsAll={0} BTC fica com tudo +disputeSummaryWindow.payout.getsAll=Max. payout to BTC {0} disputeSummaryWindow.payout.custom=Pagamento personalizado disputeSummaryWindow.payoutAmount.buyer=Quantia de pagamento do comprador disputeSummaryWindow.payoutAmount.seller=Quantia de pagamento do vendedor @@ -2154,6 +2181,7 @@ tradeDetailsWindow.tradingPeersOnion=Endereço onion dos parceiros de negociaç tradeDetailsWindow.tradingPeersPubKeyHash=Trading peers pubkey hash tradeDetailsWindow.tradeState=Estado de negócio tradeDetailsWindow.agentAddresses=Árbitro/Mediador +tradeDetailsWindow.detailData=Detail data walletPasswordWindow.headline=Digite senha para abrir: @@ -2183,6 +2211,8 @@ feeOptionWindow.info=Pode escolher pagar a taxa de negócio em BSQ ou em BTC. Se feeOptionWindow.optionsLabel=Escolha a moeda para o pagamento da taxa de negócio feeOptionWindow.useBTC=Usar BTC feeOptionWindow.fee={0} (≈ {1}) +feeOptionWindow.btcFeeWithFiatAndPercentage={0} (≈ {1} / {2}) +feeOptionWindow.btcFeeWithPercentage={0} ({1}) #################################################################### @@ -2226,6 +2256,7 @@ popup.warning.noMediatorsAvailable=Não há mediadores disponíveis. popup.warning.notFullyConnected=Você precisa esperar até estar totalmente conectado à rede.\nIsso pode levar cerca de 2 minutos na inicialização. popup.warning.notSufficientConnectionsToBtcNetwork=Você precisa esperar até que você tenha pelo menos {0} conexões com a rede Bitcoin. popup.warning.downloadNotComplete=Você precisa esperar até que o download dos blocos de Bitcoin ausentes esteja completo. +popup.warning.chainNotSynced=The Bisq wallet blockchain height is not synced correctly. If you recently started the application, please wait until one Bitcoin block has been published.\n\nYou can check the blockchain height in Settings/Network Info. If more than one block passes and this problem persists it may be stalled, in which case you should do an SPV resync. [HYPERLINK:https://bisq.wiki/Resyncing_SPV_file] popup.warning.removeOffer=Tem certeza de que deseja remover essa oferta?\nA taxa de ofertante de {0} será perdida se você remover essa oferta. popup.warning.tooLargePercentageValue=Você não pode definir uma percentagem superior à 100%. popup.warning.examplePercentageValue=Por favor digitar um número percentual como \"5.4\" para 5.4% @@ -2254,7 +2285,7 @@ popup.warning.openOffer.makerFeeTxRejected=A transação da taxa de ofertante pa popup.warning.trade.txRejected.tradeFee=taxa de negócio popup.warning.trade.txRejected.deposit=depósito -popup.warning.trade.txRejected=A transação de {0} para o negócio com o ID {1} foi rejeitada pela rede do Bitcoin.\nID da transação={2}}\nO negócio foi movido para negócios falahados.\nPor favor vá à \"Definições/Informação da Rede\" e re-sincronize o ficheiro SPV.\nPara mais ajuda por favor contacte o canal de apoio do Bisq na equipa Keybase do Bisq. +popup.warning.trade.txRejected=The {0} transaction for trade with ID {1} was rejected by the Bitcoin network.\nTransaction ID={2}\nThe trade has been moved to failed trades.\nPlease go to \"Settings/Network info\" and do a SPV resync.\nFor further help please contact the Bisq support channel at the Bisq Keybase team. popup.warning.openOfferWithInvalidMakerFeeTx=A transação de taxa de ofertante para a oferta com o ID {0} é inválida\nID da transação={1}.\nPor favor vá à \"Definições/Informação da Rede\" e re-sincronize o ficheiro SPV.\nPara mais ajuda por favor contacte o canal de apoio do Bisq na equipa Keybase do Bisq. @@ -2264,14 +2295,15 @@ popup.info.cashDepositInfo=Por favor, certifique-se de que você tem uma agênci popup.info.cashDepositInfo.confirm=Eu confirmo que eu posso fazer o depósito popup.info.shutDownWithOpenOffers=Bisq está sendo fechado, mas há ofertas abertas. \n\nEstas ofertas não estarão disponíveis na rede P2P enquanto o Bisq estiver desligado, mas elas serão publicadas novamente na rede P2P na próxima vez que você iniciar o Bisq.\n\nPara manter suas ofertas on-line, mantenha o Bisq em execução e certifique-se de que este computador também permaneça online (ou seja, certifique-se de que ele não entra no modo de espera... o modo de espera do monitor não causa problema). popup.info.qubesOSSetupInfo=It appears you are running Bisq on Qubes OS. \n\nPlease make sure your Bisq qube is setup according to our Setup Guide at [HYPERLINK:https://bisq.wiki/Running_Bisq_on_Qubes]. +popup.warn.downGradePrevention=Downgrade from version {0} to version {1} is not supported. Please use the latest Bisq version. +popup.warn.daoRequiresRestart=There was a problem with synchronizing the DAO state. You have to restart the application to fix the issue. popup.privateNotification.headline=Notificação privada importante! popup.securityRecommendation.headline=Recomendação de segurança importante popup.securityRecommendation.msg=Gostaríamos de lembrá-lo de considerar a possibilidade de usar a proteção por senha para sua carteira, caso você ainda não tenha ativado isso.\n\nTambém é altamente recomendável anotar as palavras-semente da carteira. Essas palavras-semente são como uma senha mestre para recuperar sua carteira Bitcoin.\nNa secção \"Semente da Carteira\", você encontrará mais informações.\n\nAlém disso, você deve fazer o backup da pasta completa de dados do programa na secção \"Backup\". -popup.bitcoinLocalhostNode.msg=O Bisq detectou um nó do Bitcoin Core em execução localmente (no localhost).\nPor favor, certifique-se de que este nó esteja totalmente sincronizado antes de iniciar o Bisq e que ele não esteja em execução no pruned mode. -popup.bitcoinLocalhostNode.additionalRequirements=\n\nFor a well configured node, the requirements are for the node to have pruning disabled and bloom filters enabled. +popup.bitcoinLocalhostNode.msg=Bisq detected a Bitcoin Core node running on this machine (at localhost).\n\nPlease ensure:\n- the node is fully synced before starting Bisq\n- pruning is disabled ('prune=0' in bitcoin.conf)\n- bloom filters are enabled ('peerbloomfilters=1' in bitcoin.conf) popup.shutDownInProgress.headline=Desligando popup.shutDownInProgress.msg=Desligar o programa pode demorar alguns segundos.\nPor favor não interrompa este processo. @@ -2303,15 +2335,12 @@ popup.accountSigning.signedByPeer=Uma das suas contas de pagamento foi verificad popup.accountSigning.peerLimitLifted=O limite inicial de uma das suas contas foi aumentado.\n\n{0} popup.accountSigning.peerSigner=Uma das suas contas tem maturidade suficiente para assinar outras contas de pagamento e o limite inicial de uma delas foi aumentado.\n\n{0} -popup.accountSigning.singleAccountSelect.headline=Select account age witness -popup.accountSigning.singleAccountSelect.description=Search for account age witness. -popup.accountSigning.singleAccountSelect.datePicker=Select point of time for signing +popup.accountSigning.singleAccountSelect.headline=Import unsigned account age witness popup.accountSigning.confirmSingleAccount.headline=Confirm selected account age witness popup.accountSigning.confirmSingleAccount.selectedHash=Selected witness hash popup.accountSigning.confirmSingleAccount.button=Sign account age witness popup.accountSigning.successSingleAccount.description=Witness {0} was signed popup.accountSigning.successSingleAccount.success.headline=Success -popup.accountSigning.successSingleAccount.signError=Failed to sign witness, {0} popup.accountSigning.unsignedPubKeys.headline=Unsigned Pubkeys popup.accountSigning.unsignedPubKeys.sign=Sign Pubkeys @@ -2447,8 +2476,8 @@ navigation.dao.wallet.receive=\"OAD/Carteira BSQ/Receber\" formatter.formatVolumeLabel={0} quantia{1} formatter.makerTaker=Ofertante como {0} {1} / Aceitador como {2} {3} -formatter.youAreAsMaker=Você está {0} {1} como ofertante / Aceitador está {2} {3} -formatter.youAreAsTaker=Você está {0} {1} como aceitador / Ofertante está {2} {3} +formatter.youAreAsMaker=You are: {1} {0} (maker) / Taker is: {3} {2} +formatter.youAreAsTaker=You are: {1} {0} (taker) / Maker is: {3} {2} formatter.youAre=Você é {0} {1} ({2} {3}) formatter.youAreCreatingAnOffer.fiat=Você está criando uma oferta para {0} {1} formatter.youAreCreatingAnOffer.altcoin=Você está criando uma oferta para {0} {1} ({2} {3}) @@ -2561,6 +2590,7 @@ payment.venmo.venmoUserName=Nome de utilizador do Venmo payment.popmoney.accountId=Email ou nº de telemóvel payment.promptPay.promptPayId=ID de cidadão/ID de impostos ou nº de telemóvel payment.supportedCurrencies=Moedas suportadas +payment.supportedCurrenciesForReceiver=Currencies for receiving funds payment.limitations=Limitações payment.salt=Sal para verificação da idade da conta payment.error.noHexSalt=The salt needs to be in HEX format.\nIt is only recommended to edit the salt field if you want to transfer the salt from an old account to keep your account age. The account age is verified by using the account salt and the identifying account data (e.g. IBAN). @@ -2635,7 +2665,8 @@ payment.japan.recipient=Nome payment.australia.payid=PayID payment.payid=PayID linked to financial institution. Like email address or mobile phone. payment.payid.info=A PayID like a phone number, email address or an Australian Business Number (ABN), that you can securely link to your bank, credit union or building society account. You need to have already created a PayID with your Australian financial institution. Both sending and receiving financial institutions must support PayID. For more information please check [HYPERLINK:https://payid.com.au/faqs/] -payment.amazonGiftCard.info=To pay with Amazon eGift Card you need to purchase an Amazon eGift Card at your Amazon account and use the BTC seller''s email or mobile nr. as receiver. Amazon sends then an email or text message to the receiver. Use the trade ID for the message field.\n\nAmazon eGift Cards can only be redeemed by Amazon accounts with the same currency.\n\nFor more information visit the Amazon eGift Card webpage. [HYPERLINK:https://www.amazon.com/Amazon-1_US_Email-eGift-Card/dp/B004LLIKVU] +payment.amazonGiftCard.info=To pay with Amazon eGift Card, you will need to send an Amazon eGift Card to the BTC seller via your Amazon account. \n\nBisq will show the BTC seller''s email address or phone number where the gift card should be sent, and you must include the trade ID in the gift card''s message field. Please see the wiki [HYPERLINK:https://bisq.wiki/Amazon_eGift_card] for further details and best practices. \n\nThree important notes:\n- try to send gift cards with amounts of 100 USD or smaller, as Amazon is known to flag larger gift cards as fraudulent\n- try to use creative, believable text for the gift card''s message (e.g., "Happy birthday Susan!") along with the trade ID (and use trader chat to tell your trading peer the reference text you picked so they can verify your payment)\n- Amazon eGift Cards can only be redeemed on the Amazon website they were purchased on (e.g., a gift card purchased on amazon.it can only be redeemed on amazon.it) + # We use constants from the code so we do not use our normal naming convention # dynamic values are not recognized by IntelliJ @@ -2855,4 +2886,4 @@ validation.phone.invalidCharacters=O número de telfone {0} contém carácteres validation.phone.insufficientDigits=There are not enough digits in {0} to be a valid phone number validation.phone.tooManyDigits=There are too many digits in {0} to be a valid phone number validation.phone.invalidDialingCode=Country dialing code for number {0} is invalid for country {1}. The correct dialing code is {2}. -validation.invalidAddressList=Deve ser um lista de endereços válidos separados por vírgulas +validation.invalidAddressList=Deve ser um lista de endereços válidos separados por vírgulas diff --git a/core/src/main/resources/i18n/displayStrings_ru.properties b/core/src/main/resources/i18n/displayStrings_ru.properties index c378302ce5..39a203abac 100644 --- a/core/src/main/resources/i18n/displayStrings_ru.properties +++ b/core/src/main/resources/i18n/displayStrings_ru.properties @@ -71,6 +71,7 @@ shared.amountWithCur=Количество в {0} shared.volumeWithCur=Объём в {0} shared.currency=Валюта shared.market=Рынок +shared.deviation=Deviation shared.paymentMethod=Способ оплаты shared.tradeCurrency=Торговая валюта shared.offerType=Тип предложения @@ -104,7 +105,6 @@ shared.selectTradingAccount=Выбрать торговый счёт shared.fundFromSavingsWalletButton=Перевести средства с кошелька Bisq shared.fundFromExternalWalletButton=Открыть внешний кошелёк для пополнения shared.openDefaultWalletFailed=Failed to open a Bitcoin wallet application. Are you sure you have one installed? -shared.distanceInPercent=Отклонение от рыночного курса в % shared.belowInPercent=% ниже рыночного курса shared.aboveInPercent=% выше рыночного курса shared.enterPercentageValue=Ввести величину в % @@ -191,7 +191,7 @@ shared.tradeWalletBalance=Баланс кошелька сделки shared.makerTxFee=Мейкер: {0} shared.takerTxFee=Тейкер: {0} shared.iConfirm=Подтверждаю -shared.tradingFeeInBsqInfo=equivalent to {0} used as trading fee +shared.tradingFeeInBsqInfo=≈ {0} shared.openURL=Открыть {0} shared.fiat=Нац. валюта shared.crypto=Криптовалюта @@ -218,6 +218,9 @@ shared.refundAgentForSupportStaff=Refund agent shared.delayedPayoutTxId=Delayed payout transaction ID shared.delayedPayoutTxReceiverAddress=Delayed payout transaction sent to shared.unconfirmedTransactionsLimitReached=You have too many unconfirmed transactions at the moment. Please try again later. +shared.numItemsLabel=Number of entries: {0} +shared.filter=Filter +shared.enabled=Enabled #################################################################### @@ -248,14 +251,14 @@ mainView.balance.locked=Используется в сделках mainView.balance.reserved.short=Выделено mainView.balance.locked.short=В сделках -mainView.footer.usingTor=(используется Tor) +mainView.footer.usingTor=(via Tor) mainView.footer.localhostBitcoinNode=(локальный узел) -mainView.footer.btcInfo={0} {1} {2} -mainView.footer.btcFeeRate=/ Current fee rate: {0} sat/vB +mainView.footer.btcInfo={0} {1} +mainView.footer.btcFeeRate=/ Fee rate: {0} sat/vB mainView.footer.btcInfo.initializing=Подключение к сети Биткойн mainView.footer.bsqInfo.synchronizing=/ Синхронизация ДАО -mainView.footer.btcInfo.synchronizingWith=Синхронизация с -mainView.footer.btcInfo.synchronizedWith=Synced with +mainView.footer.btcInfo.synchronizingWith=Synchronizing with {0} at block: {1} / {2} +mainView.footer.btcInfo.synchronizedWith=Synced with {0} at block {1} mainView.footer.btcInfo.connectingTo=Подключение к mainView.footer.btcInfo.connectionFailed=Connection failed to mainView.footer.p2pInfo=Bitcoin network peers: {0} / Bisq network peers: {1} @@ -336,10 +339,10 @@ offerbook.offerersAcceptedBankSeats=Допустимые страны банка offerbook.availableOffers=Доступные предложения offerbook.filterByCurrency=Фильтровать по валюте offerbook.filterByPaymentMethod=Фильтровать по способу оплаты -offerbook.timeSinceSigning=Signed since +offerbook.timeSinceSigning=Account info offerbook.timeSinceSigning.info=This account was verified and {0} offerbook.timeSinceSigning.info.arbitrator=signed by an arbitrator and can sign peer accounts -offerbook.timeSinceSigning.info.peer=signed by a peer, waiting for limits to be lifted +offerbook.timeSinceSigning.info.peer=signed by a peer, waiting %d days for limits to be lifted offerbook.timeSinceSigning.info.peerLimitLifted=signed by a peer and limits were lifted offerbook.timeSinceSigning.info.signer=signed by peer and can sign peer accounts (limits lifted) offerbook.timeSinceSigning.info.banned=account was banned @@ -349,9 +352,12 @@ offerbook.xmrAutoConf=Is auto-confirm enabled offerbook.timeSinceSigning.help=When you successfully complete a trade with a peer who has a signed payment account, your payment account is signed.\n{0} days later, the initial limit of {1} is lifted and your account can sign other peers'' payment accounts. offerbook.timeSinceSigning.notSigned=Not signed yet +offerbook.timeSinceSigning.notSigned.ageDays={0} дн. offerbook.timeSinceSigning.notSigned.noNeed=Н/Д -shared.notSigned=This account hasn't been signed yet -shared.notSigned.noNeed=This account type doesn't use signing +shared.notSigned=This account has not been signed yet and was created {0} days ago +shared.notSigned.noNeed=This account type does not require signing +shared.notSigned.noNeedDays=This account type does not require signing and was created {0} days ago +shared.notSigned.noNeedAlts=Altcoin accounts do not feature signing or aging offerbook.nrOffers=Кол-во предложений: {0} offerbook.volume={0} (мин. ⁠— макс.) @@ -435,11 +441,15 @@ createOffer.warning.sellBelowMarketPrice=Вы всегда получите на createOffer.warning.buyAboveMarketPrice=Вы всегда заплатите на {0}% больше текущего рыночного курса, так как курс вашего предложения будет постоянно обновляться. createOffer.tradeFee.descriptionBTCOnly=Комиссия за сделку createOffer.tradeFee.descriptionBSQEnabled=Выбрать валюту комиссии за сделку -createOffer.tradeFee.fiatAndPercent=≈ {0} / {1} от суммы сделки + +createOffer.triggerPrice.prompt=Set optional trigger price +createOffer.triggerPrice.label=Deactivate offer if market price is {0} +createOffer.triggerPrice.tooltip=As protecting against drastic price movements you can set a trigger price which deactivates the offer if the market price reaches that value. +createOffer.triggerPrice.invalid.tooLow=Value must be higher than {0} +createOffer.triggerPrice.invalid.tooHigh=Value must be lower than {0} # new entries createOffer.placeOfferButton=Проверка: разместить предложение {0} биткойн -createOffer.alreadyFunded=Вы уже обеспечили это предложение.\nВаши средства были перемещены в локальный кошелёк Bisq. Они доступны для вывода в разделе \«Средства/Отправить средства\». createOffer.createOfferFundWalletInfo.headline=Обеспечить своё предложение # suppress inspection "TrailingSpacesInProperty" createOffer.createOfferFundWalletInfo.tradeAmount=- Сумма сделки: {0} \n @@ -496,7 +506,6 @@ takeOffer.error.message=Ошибка при принятии предложен # new entries takeOffer.takeOfferButton=Проверка: принять предложение {0} биткойн takeOffer.noPriceFeedAvailable=Нельзя принять это предложение, поскольку в нем используется процентный курс на основе рыночного курса, источник которого недоступен. -takeOffer.alreadyFunded.movedFunds=Вы уже обеспечили это предложение.\nВаши средства были перемещены в локальный кошелёк Bisq. Они доступны для вывода в разделе \«Средства/Отправить средства\». takeOffer.takeOfferFundWalletInfo.headline=Обеспечьте свою сделку # suppress inspection "TrailingSpacesInProperty" takeOffer.takeOfferFundWalletInfo.tradeAmount=- Сумма сделки: {0} \n @@ -524,6 +533,10 @@ takeOffer.tac=Принимая это предложение, я соглаша # Offerbook / Edit offer #################################################################### +openOffer.header.triggerPrice=Начальная цена +openOffer.triggerPrice=Trigger price {0} +openOffer.triggered=The offer has been deactivated because the market price reached your trigger price.\nPlease edit the offer to define a new trigger price + editOffer.setPrice=Укажите курс editOffer.confirmEdit=Подтвердите: изменить предложение editOffer.publishOffer=Публикация вашего предложения. @@ -541,6 +554,8 @@ portfolio.tab.history=История portfolio.tab.failed=Не удалось portfolio.tab.editOpenOffer=Изменить предложение +portfolio.closedTrades.deviation.help=Percentage price deviation from market + portfolio.pending.invalidDelayedPayoutTx=There is an issue with a missing or invalid transaction.\n\nPlease do NOT send the fiat or altcoin payment. Contact Bisq developers on Keybase [HYPERLINK:https://keybase.io/team/bisq] or on the forum [HYPERLINK:https://bisq.community] for further assistance.\n\nError message: {0} portfolio.pending.step1.waitForConf=Ожидание подтверждения в блокчейне @@ -886,13 +901,12 @@ funds.tx.noTxAvailable=Транзакции отсутствуют funds.tx.revert=Отменить funds.tx.txSent=Транзакция успешно отправлена на новый адрес локального кошелька Bisq. funds.tx.direction.self=Транзакция внутри кошелька -funds.tx.daoTxFee=Комиссия майнера за транзакцию ДАО +funds.tx.daoTxFee=Комиссия майнера за транзакцию в BSQ funds.tx.reimbursementRequestTxFee=Запрос возмещения funds.tx.compensationRequestTxFee=Запрос компенсации funds.tx.dustAttackTx=Полученная «пыль» funds.tx.dustAttackTx.popup=Вы получили очень маленькую сумму BTC, что может являться попыткой компаний, занимающихся анализом блокчейна, проследить за вашим кошельком.\n\nЕсли вы воспользуетесь этими средствами для совершения исходящей транзакции, они смогут узнать, что вы также являетесь вероятным владельцем другого адреса (т. н. «объединение монет»).\n\nДля защиты вашей конфиденциальности кошелёк Bisq игнорирует такую «пыль» при совершении исходящих транзакций и отображении баланса. Вы можете самостоятельно установить сумму, которая будет рассматриваться в качестве «пыли» в настройках. - #################################################################### # Support #################################################################### @@ -943,6 +957,7 @@ support.error=Получателю не удалось обработать со support.buyerAddress=Адрес покупателя ВТС support.sellerAddress=Адрес продавца ВТС support.role=Роль +support.agent=Support agent support.state=Состояние support.closed=Закрыто support.open=Открыто @@ -1052,6 +1067,7 @@ settings.net.creationDateColumn=Создано settings.net.connectionTypeColumn=Вх./Вых. settings.net.sentDataLabel=Sent data statistics settings.net.receivedDataLabel=Received data statistics +settings.net.chainHeightLabel=Latest BTC block height settings.net.roundTripTimeColumn=Задержка settings.net.sentBytesColumn=Отправлено settings.net.receivedBytesColumn=Получено @@ -1066,6 +1082,7 @@ settings.net.needRestart=Необходимо перезагрузить при settings.net.notKnownYet=Пока неизвестно... settings.net.sentData=Sent data: {0}, {1} messages, {2} messages/sec settings.net.receivedData=Received data: {0}, {1} messages, {2} messages/sec +settings.net.chainHeight=Bisq: {0} | Peers: {1} settings.net.ips=[IP-адрес:порт | хост:порт | onion-адрес:порт] (через запятые). Порт можно не указывать, если используется порт по умолчанию (8333). settings.net.seedNode=Исходный узел settings.net.directPeer=Пир (прямой) @@ -1074,7 +1091,7 @@ settings.net.inbound=входящий settings.net.outbound=выходящий settings.net.reSyncSPVChainLabel=Синхронизировать цепь SPV заново settings.net.reSyncSPVChainButton=Удалить файл SPV и синхронизировать повторно -settings.net.reSyncSPVSuccess=The SPV chain file will be deleted on the next startup. You need to restart your application now.\n\nAfter the restart it can take a while to resync with the network and you will only see all transactions once the resync is completed.\n\nDepending on the number of transactions and the age of your wallet the resync can take up to a few hours and consumes 100% of CPU. Do not interrupt the process otherwise you have to repeat it. +settings.net.reSyncSPVSuccess=Are you sure you want to do an SPV resync? If you proceed, the SPV chain file will be deleted on the next startup.\n\nAfter the restart it can take a while to resync with the network and you will only see all transactions once the resync is completed.\n\nDepending on the number of transactions and the age of your wallet the resync can take up to a few hours and consumes 100% of CPU. Do not interrupt the process otherwise you have to repeat it. settings.net.reSyncSPVAfterRestart=Файл цепи SPV удален. Подождите. Повторная синхронизации с сетью может занять некоторое время. settings.net.reSyncSPVAfterRestartCompleted=Повторная синхронизация завершена. Перезагрузите приложение. settings.net.reSyncSPVFailed=Не удалось удалить файл цепи SPV.\nОшибка: {0} @@ -1161,9 +1178,19 @@ account.menu.paymentAccount=Счета в нац. валюте account.menu.altCoinsAccountView=Альткойн-счета account.menu.password=Пароль кошелька account.menu.seedWords=Мнемоническая фраза +account.menu.walletInfo=Wallet info account.menu.backup=Резервное копирование account.menu.notifications=Уведомления +account.menu.walletInfo.balance.headLine=Wallet balances +account.menu.walletInfo.balance.info=This shows the internal wallet balance including unconfirmed transactions.\nFor BTC, the internal wallet balance shown below should match the sum of the 'Available' and 'Reserved' balances shown in the top right of this window. +account.menu.walletInfo.xpub.headLine=Watch keys (xpub keys) +account.menu.walletInfo.walletSelector={0} {1} wallet +account.menu.walletInfo.path.headLine=HD keychain paths +account.menu.walletInfo.path.info=If you import seed words into another wallet (like Electrum), you'll need to define the path. This should only be done in emergency cases when you lose access to the Bisq wallet and data directory.\nKeep in mind that spending funds from a non-Bisq wallet can bungle the internal Bisq data structures associated with the wallet data, which can lead to failed trades.\n\nNEVER send BSQ from a non-Bisq wallet, as it will probably lead to an invalid BSQ transaction and losing your BSQ. + +account.menu.walletInfo.openDetails=Show raw wallet details and private keys + ## TODO should we rename the following to a gereric name? account.arbitratorRegistration.pubKey=Публичный ключ @@ -1796,7 +1823,7 @@ dao.wallet.send.setDestinationAddress=Укажите адрес получате dao.wallet.send.send=Отправить BSQ dao.wallet.send.sendBtc=Отправить BTC dao.wallet.send.sendFunds.headline=Подтвердите запрос на вывод средств -dao.wallet.send.sendFunds.details=Sending: {0}\nTo receiving address: {1}.\nRequired transaction fee is: {2} ({3} satoshis/vbyte)\nTransaction vsize: {4} vKb\n\nThe recipient will receive: {5}\n\nAre you sure you want to withdraw that amount? +dao.wallet.send.sendFunds.details=Sending: {0}\nTo receiving address: {1}.\nRequired mining fee is: {2} ({3} satoshis/vbyte)\nTransaction vsize: {4} vKb\n\nThe recipient will receive: {5}\n\nAre you sure you want to withdraw that amount? dao.wallet.chainHeightSynced=Последний проверенный блок: {0} dao.wallet.chainHeightSyncing=Ожидание блоков... Проверено: {0} бл. из {1} dao.wallet.tx.type=Тип @@ -1928,9 +1955,9 @@ dao.factsAndFigures.menuItem.transactions=Транзакции в BSQ dao.factsAndFigures.dashboard.avgPrice90=90 days average BSQ/BTC trade price dao.factsAndFigures.dashboard.avgPrice30=30 days average BSQ/BTC trade price -dao.factsAndFigures.dashboard.avgUSDPrice90=90 days volume weighted average USD/BSQ trade price -dao.factsAndFigures.dashboard.avgUSDPrice30=30 days volume weighted average USD/BSQ trade price -dao.factsAndFigures.dashboard.marketCap=Рыночная капитализация (на основе цены последней сделки) +dao.factsAndFigures.dashboard.avgUSDPrice90=90 days volume weighted average USD/BSQ price +dao.factsAndFigures.dashboard.avgUSDPrice30=30 days volume weighted average USD/BSQ price +dao.factsAndFigures.dashboard.marketCap=Market capitalisation (based on 30 days average USD/BSQ price) dao.factsAndFigures.dashboard.availableAmount=Доступное количество BSQ dao.factsAndFigures.supply.issuedVsBurnt=BSQ issued v. BSQ burnt @@ -2000,7 +2027,7 @@ disputeSummaryWindow.openDate=Дата обращения за поддержк disputeSummaryWindow.role=Роль трейдера disputeSummaryWindow.payout=Выплата суммы сделки disputeSummaryWindow.payout.getsTradeAmount={0} BTC получит выплату суммы сделки -disputeSummaryWindow.payout.getsAll={0} BTC получит всё +disputeSummaryWindow.payout.getsAll=Max. payout to BTC {0} disputeSummaryWindow.payout.custom=Пользовательская выплата disputeSummaryWindow.payoutAmount.buyer=Сумма выплаты покупателя disputeSummaryWindow.payoutAmount.seller=Сумма выплаты продавца @@ -2154,6 +2181,7 @@ tradeDetailsWindow.tradingPeersOnion=Оnion-адрес контрагента tradeDetailsWindow.tradingPeersPubKeyHash=Trading peers pubkey hash tradeDetailsWindow.tradeState=Статус сделки tradeDetailsWindow.agentAddresses=Arbitrator/Mediator +tradeDetailsWindow.detailData=Detail data walletPasswordWindow.headline=Введите пароль для разблокировки @@ -2183,6 +2211,8 @@ feeOptionWindow.info=Вы можете оплатить комиссию за с feeOptionWindow.optionsLabel=Выберите валюту для оплаты комиссии за сделку feeOptionWindow.useBTC=Использовать ВТС feeOptionWindow.fee={0} (≈ {1}) +feeOptionWindow.btcFeeWithFiatAndPercentage={0} (≈ {1} / {2}) +feeOptionWindow.btcFeeWithPercentage={0} ({1}) #################################################################### @@ -2226,6 +2256,7 @@ popup.warning.noMediatorsAvailable=There are no mediators available. popup.warning.notFullyConnected=Необходимо дождаться полного подключения к сети.\nОно может занять до 2 минут. popup.warning.notSufficientConnectionsToBtcNetwork=Необходимо дождаться не менее {0} соединений с сетью Биткойн. popup.warning.downloadNotComplete=Необходимо дождаться завершения загрузки недостающих блоков сети Биткойн. +popup.warning.chainNotSynced=The Bisq wallet blockchain height is not synced correctly. If you recently started the application, please wait until one Bitcoin block has been published.\n\nYou can check the blockchain height in Settings/Network Info. If more than one block passes and this problem persists it may be stalled, in which case you should do an SPV resync. [HYPERLINK:https://bisq.wiki/Resyncing_SPV_file] popup.warning.removeOffer=Действительно хотите удалить это предложение?\nКомиссия мейкера в размере {0} компенсации не подлежит. popup.warning.tooLargePercentageValue=Нельзя установить процент в размере 100% или выше. popup.warning.examplePercentageValue=Введите процент, например \«5,4\» для 5,4% @@ -2254,7 +2285,7 @@ popup.warning.openOffer.makerFeeTxRejected=The maker fee transaction for offer w popup.warning.trade.txRejected.tradeFee=trade fee popup.warning.trade.txRejected.deposit=deposit -popup.warning.trade.txRejected=The {0} transaction for trade with ID {1} was rejected by the Bitcoin network.\nTransaction ID={2}}\nThe trade has been moved to failed trades.\nPlease go to \"Settings/Network info\" and do a SPV resync.\nFor further help please contact the Bisq support channel at the Bisq Keybase team. +popup.warning.trade.txRejected=The {0} transaction for trade with ID {1} was rejected by the Bitcoin network.\nTransaction ID={2}\nThe trade has been moved to failed trades.\nPlease go to \"Settings/Network info\" and do a SPV resync.\nFor further help please contact the Bisq support channel at the Bisq Keybase team. popup.warning.openOfferWithInvalidMakerFeeTx=The maker fee transaction for offer with ID {0} is invalid.\nTransaction ID={1}.\nPlease go to \"Settings/Network info\" and do a SPV resync.\nFor further help please contact the Bisq support channel at the Bisq Keybase team. @@ -2264,14 +2295,15 @@ popup.info.cashDepositInfo=Убедитесь, что в вашем районе popup.info.cashDepositInfo.confirm=Я подтверждаю, что могу внести оплату popup.info.shutDownWithOpenOffers=Bisq закрывается, но у вас есть открытые предложения.\n\nЭти предложения будут недоступны в сети P2P, пока приложение Bisq закрыто, но будут повторно опубликованы в сети P2P при следующем запуске Bisq.\n\nЧтобы ваши предложения были доступны в сети, компьютер и приложение должны быть включены и подключены к сети (убедитесь, что компьютер не перешёл в режим ожидания; переход монитора в спящий режим не влияет на работу приложения). popup.info.qubesOSSetupInfo=It appears you are running Bisq on Qubes OS. \n\nPlease make sure your Bisq qube is setup according to our Setup Guide at [HYPERLINK:https://bisq.wiki/Running_Bisq_on_Qubes]. +popup.warn.downGradePrevention=Downgrade from version {0} to version {1} is not supported. Please use the latest Bisq version. +popup.warn.daoRequiresRestart=There was a problem with synchronizing the DAO state. You have to restart the application to fix the issue. popup.privateNotification.headline=Важное личное уведомление! popup.securityRecommendation.headline=Важная рекомендация по безопасности popup.securityRecommendation.msg=Рекомендуем вам защитить свой кошелёк паролем, если вы ещё этого не сделали.\n\nТакже убедительно рекомендуем записать вашу мнемоническую фразу. Она поможет восстановить ваш кошелёк Биткойн.\nДополнительная информация указана в разделе \«Мнемоническая фраза\».\n\nВам также следует сохранить копию папки со всеми данными программы в разделе \«Резервное копирование\». -popup.bitcoinLocalhostNode.msg=Bisq обнаружил локальный узел Bitcoin Core.\nПеред запуском Bisq убедитесь, что этот узел полностью синхронизирован с сетью Биткойн и не работает в режиме обрезки данных (pruned mode). -popup.bitcoinLocalhostNode.additionalRequirements=\n\nFor a well configured node, the requirements are for the node to have pruning disabled and bloom filters enabled. +popup.bitcoinLocalhostNode.msg=Bisq detected a Bitcoin Core node running on this machine (at localhost).\n\nPlease ensure:\n- the node is fully synced before starting Bisq\n- pruning is disabled ('prune=0' in bitcoin.conf)\n- bloom filters are enabled ('peerbloomfilters=1' in bitcoin.conf) popup.shutDownInProgress.headline=Завершение работы popup.shutDownInProgress.msg=Завершение работы приложения может занять несколько секунд.\nПросьба не прерывать этот процесс. @@ -2303,15 +2335,12 @@ popup.accountSigning.signedByPeer=One of your payment accounts has been verified popup.accountSigning.peerLimitLifted=The initial limit for one of your accounts has been lifted.\n\n{0} popup.accountSigning.peerSigner=One of your accounts is mature enough to sign other payment accounts and the initial limit for one of your accounts has been lifted.\n\n{0} -popup.accountSigning.singleAccountSelect.headline=Select account age witness -popup.accountSigning.singleAccountSelect.description=Search for account age witness. -popup.accountSigning.singleAccountSelect.datePicker=Select point of time for signing +popup.accountSigning.singleAccountSelect.headline=Import unsigned account age witness popup.accountSigning.confirmSingleAccount.headline=Confirm selected account age witness popup.accountSigning.confirmSingleAccount.selectedHash=Selected witness hash popup.accountSigning.confirmSingleAccount.button=Sign account age witness popup.accountSigning.successSingleAccount.description=Witness {0} was signed popup.accountSigning.successSingleAccount.success.headline=Success -popup.accountSigning.successSingleAccount.signError=Failed to sign witness, {0} popup.accountSigning.unsignedPubKeys.headline=Unsigned Pubkeys popup.accountSigning.unsignedPubKeys.sign=Sign Pubkeys @@ -2447,8 +2476,8 @@ navigation.dao.wallet.receive=\«ДАО/BSQ-кошелёк/Получить\» formatter.formatVolumeLabel={0} сумма {1} formatter.makerTaker=Мейкер как {0} {1} / Тейкер как {2} {3} -formatter.youAreAsMaker=Вы как {0} {1} (мейкер) / тейкер как {2} {3} -formatter.youAreAsTaker=Вы как {0} {1} (тейкер) / мейкер как {2} {3} +formatter.youAreAsMaker=You are: {1} {0} (maker) / Taker is: {3} {2} +formatter.youAreAsTaker=You are: {1} {0} (taker) / Maker is: {3} {2} formatter.youAre=Вы {0} {1} ({2} {3}) formatter.youAreCreatingAnOffer.fiat=Вы создаете предложение {0} {1} formatter.youAreCreatingAnOffer.altcoin=Вы создаете предложение {0} {1} ({2} {3}) @@ -2561,6 +2590,7 @@ payment.venmo.venmoUserName=Имя пользователя Venmo payment.popmoney.accountId=Эл. адрес или тел. номер payment.promptPay.promptPayId=Удостовер. личности / налог. номер или номер телефона payment.supportedCurrencies=Поддерживаемые валюты +payment.supportedCurrenciesForReceiver=Currencies for receiving funds payment.limitations=Ограничения payment.salt=Модификатор («соль») для подтверждения возраста счёта payment.error.noHexSalt=The salt needs to be in HEX format.\nIt is only recommended to edit the salt field if you want to transfer the salt from an old account to keep your account age. The account age is verified by using the account salt and the identifying account data (e.g. IBAN). @@ -2635,7 +2665,8 @@ payment.japan.recipient=Имя payment.australia.payid=PayID payment.payid=PayID linked to financial institution. Like email address or mobile phone. payment.payid.info=A PayID like a phone number, email address or an Australian Business Number (ABN), that you can securely link to your bank, credit union or building society account. You need to have already created a PayID with your Australian financial institution. Both sending and receiving financial institutions must support PayID. For more information please check [HYPERLINK:https://payid.com.au/faqs/] -payment.amazonGiftCard.info=To pay with Amazon eGift Card you need to purchase an Amazon eGift Card at your Amazon account and use the BTC seller''s email or mobile nr. as receiver. Amazon sends then an email or text message to the receiver. Use the trade ID for the message field.\n\nAmazon eGift Cards can only be redeemed by Amazon accounts with the same currency.\n\nFor more information visit the Amazon eGift Card webpage. [HYPERLINK:https://www.amazon.com/Amazon-1_US_Email-eGift-Card/dp/B004LLIKVU] +payment.amazonGiftCard.info=To pay with Amazon eGift Card, you will need to send an Amazon eGift Card to the BTC seller via your Amazon account. \n\nBisq will show the BTC seller''s email address or phone number where the gift card should be sent, and you must include the trade ID in the gift card''s message field. Please see the wiki [HYPERLINK:https://bisq.wiki/Amazon_eGift_card] for further details and best practices. \n\nThree important notes:\n- try to send gift cards with amounts of 100 USD or smaller, as Amazon is known to flag larger gift cards as fraudulent\n- try to use creative, believable text for the gift card''s message (e.g., "Happy birthday Susan!") along with the trade ID (and use trader chat to tell your trading peer the reference text you picked so they can verify your payment)\n- Amazon eGift Cards can only be redeemed on the Amazon website they were purchased on (e.g., a gift card purchased on amazon.it can only be redeemed on amazon.it) + # We use constants from the code so we do not use our normal naming convention # dynamic values are not recognized by IntelliJ diff --git a/core/src/main/resources/i18n/displayStrings_th.properties b/core/src/main/resources/i18n/displayStrings_th.properties index 7527a45ad2..69a91d7d16 100644 --- a/core/src/main/resources/i18n/displayStrings_th.properties +++ b/core/src/main/resources/i18n/displayStrings_th.properties @@ -71,6 +71,7 @@ shared.amountWithCur=จำนวนใน {0} shared.volumeWithCur=ปริมาณการซื้อขายใน {0} shared.currency=เงินตรา shared.market=ตลาด +shared.deviation=Deviation shared.paymentMethod=วิธีการชำระเงิน shared.tradeCurrency=สกุลเงินตราการค้า shared.offerType=ประเภทข้อเสนอ @@ -104,7 +105,6 @@ shared.selectTradingAccount=เลือกบัญชีการซื้อ shared.fundFromSavingsWalletButton=โอนเงินจาก Bisq wallet shared.fundFromExternalWalletButton=เริ่มทำการระดมเงินทุนหาแหล่งเงินจากกระเป๋าสตางค์ภายนอกของคุณ shared.openDefaultWalletFailed=Failed to open a Bitcoin wallet application. Are you sure you have one installed? -shared.distanceInPercent=ระดับราคาในรูปแบบ % จากราคาตลาด shared.belowInPercent=ต่ำกว่า % จากราคาตลาด shared.aboveInPercent=สูงกว่า % จากราคาตาด shared.enterPercentageValue=เข้าสู่ % ตามมูลค่า @@ -191,7 +191,7 @@ shared.tradeWalletBalance=ยอดคงเหลือของ Trade wallet shared.makerTxFee=ผู้ทำ: {0} shared.takerTxFee=ผู้รับ: {0} shared.iConfirm=ฉันยืนยัน -shared.tradingFeeInBsqInfo=equivalent to {0} used as trading fee +shared.tradingFeeInBsqInfo=≈ {0} shared.openURL=เปิด {0} shared.fiat=คำสั่ง shared.crypto=คริปโต @@ -218,6 +218,9 @@ shared.refundAgentForSupportStaff=Refund agent shared.delayedPayoutTxId=Delayed payout transaction ID shared.delayedPayoutTxReceiverAddress=Delayed payout transaction sent to shared.unconfirmedTransactionsLimitReached=You have too many unconfirmed transactions at the moment. Please try again later. +shared.numItemsLabel=Number of entries: {0} +shared.filter=Filter +shared.enabled=Enabled #################################################################### @@ -248,14 +251,14 @@ mainView.balance.locked=ล็อคในการซื้อขาย mainView.balance.reserved.short=จองแล้ว mainView.balance.locked.short=ถูกล็อคไว้ -mainView.footer.usingTor=(ใช้งาน Tor) +mainView.footer.usingTor=(via Tor) mainView.footer.localhostBitcoinNode=(แม่ข่ายเฉพาะที่) -mainView.footer.btcInfo={0} {1} {2} -mainView.footer.btcFeeRate=/ Current fee rate: {0} sat/vB +mainView.footer.btcInfo={0} {1} +mainView.footer.btcFeeRate=/ Fee rate: {0} sat/vB mainView.footer.btcInfo.initializing=Connecting to Bitcoin network mainView.footer.bsqInfo.synchronizing=/ Synchronizing DAO -mainView.footer.btcInfo.synchronizingWith=Synchronizing with -mainView.footer.btcInfo.synchronizedWith=Synced with +mainView.footer.btcInfo.synchronizingWith=Synchronizing with {0} at block: {1} / {2} +mainView.footer.btcInfo.synchronizedWith=Synced with {0} at block {1} mainView.footer.btcInfo.connectingTo=Connecting to mainView.footer.btcInfo.connectionFailed=Connection failed to mainView.footer.p2pInfo=Bitcoin network peers: {0} / Bisq network peers: {1} @@ -336,10 +339,10 @@ offerbook.offerersAcceptedBankSeats=ยอมรับตำแหน่งป offerbook.availableOffers=ข้อเสนอที่พร้อมใช้งาน offerbook.filterByCurrency=กรองตามสกุลเงิน offerbook.filterByPaymentMethod=ตัวกรองตามวิธีการชำระเงิน -offerbook.timeSinceSigning=Signed since +offerbook.timeSinceSigning=Account info offerbook.timeSinceSigning.info=This account was verified and {0} offerbook.timeSinceSigning.info.arbitrator=signed by an arbitrator and can sign peer accounts -offerbook.timeSinceSigning.info.peer=signed by a peer, waiting for limits to be lifted +offerbook.timeSinceSigning.info.peer=signed by a peer, waiting %d days for limits to be lifted offerbook.timeSinceSigning.info.peerLimitLifted=signed by a peer and limits were lifted offerbook.timeSinceSigning.info.signer=signed by peer and can sign peer accounts (limits lifted) offerbook.timeSinceSigning.info.banned=account was banned @@ -349,9 +352,12 @@ offerbook.xmrAutoConf=Is auto-confirm enabled offerbook.timeSinceSigning.help=When you successfully complete a trade with a peer who has a signed payment account, your payment account is signed.\n{0} days later, the initial limit of {1} is lifted and your account can sign other peers'' payment accounts. offerbook.timeSinceSigning.notSigned=Not signed yet +offerbook.timeSinceSigning.notSigned.ageDays={0} วัน offerbook.timeSinceSigning.notSigned.noNeed=ไม่พร้อมใช้งาน -shared.notSigned=This account hasn't been signed yet -shared.notSigned.noNeed=This account type doesn't use signing +shared.notSigned=This account has not been signed yet and was created {0} days ago +shared.notSigned.noNeed=This account type does not require signing +shared.notSigned.noNeedDays=This account type does not require signing and was created {0} days ago +shared.notSigned.noNeedAlts=Altcoin accounts do not feature signing or aging offerbook.nrOffers=No. ของข้อเสนอ: {0} offerbook.volume={0} (ต่ำสุด - สูงสุด) @@ -435,11 +441,15 @@ createOffer.warning.sellBelowMarketPrice=คุณจะได้รับ {0}% createOffer.warning.buyAboveMarketPrice=คุณจะต้องจ่ายเงิน {0}% มากกว่าราคาตลาดในปัจจุบันเนื่องจากราคาข้อเสนอของคุณจะได้รับการอัพเดตอย่างต่อเนื่อง createOffer.tradeFee.descriptionBTCOnly=ค่าธรรมเนียมการซื้อขาย createOffer.tradeFee.descriptionBSQEnabled=เลือกสกุลเงินค่าธรรมเนียมในการเทรด -createOffer.tradeFee.fiatAndPercent=≈ {0} / {1} จำนวนการเทรด + +createOffer.triggerPrice.prompt=Set optional trigger price +createOffer.triggerPrice.label=Deactivate offer if market price is {0} +createOffer.triggerPrice.tooltip=As protecting against drastic price movements you can set a trigger price which deactivates the offer if the market price reaches that value. +createOffer.triggerPrice.invalid.tooLow=Value must be higher than {0} +createOffer.triggerPrice.invalid.tooHigh=Value must be lower than {0} # new entries createOffer.placeOfferButton=รีวิว: ใส่ข้อเสนอไปยัง {0} บิตคอย -createOffer.alreadyFunded=คุณได้รับเงินจากข้อเสนอนั้นแล้ว\nเงินของคุณถูกย้ายไปที่กระเป๋าสตางค์ Bisq ของคุณและคุณสามารถถอนเงินออกได้โดยไปที่หน้า \"เงิน / ส่งเงิน \" createOffer.createOfferFundWalletInfo.headline=เงินทุนสำหรับข้อเสนอของคุณ # suppress inspection "TrailingSpacesInProperty" createOffer.createOfferFundWalletInfo.tradeAmount=- ปริมาณการซื้อขาย: {0} @@ -496,7 +506,6 @@ takeOffer.error.message=เกิดข้อผิดพลาดขณะร # new entries takeOffer.takeOfferButton=รีวิว: รับข้อเสนอจาก {0} bitcoin takeOffer.noPriceFeedAvailable=คุณไม่สามารถรับข้อเสนอดังกล่าวเนื่องจากใช้ราคาร้อยละตามราคาตลาด แต่ไม่มีฟีดราคาที่พร้อมใช้งาน -takeOffer.alreadyFunded.movedFunds=คุณได้รับเงินสนับสนุนแล้ว\nเงินของคุณถูกย้ายไปที่กระเป๋าสตางค์ Bisq ของคุณและพร้อมสำหรับการถอนเงินโดยไปที่หน้า \"เงิน / ส่งเงิน \" takeOffer.takeOfferFundWalletInfo.headline=ทุนการซื้อขายของคุณ # suppress inspection "TrailingSpacesInProperty" takeOffer.takeOfferFundWalletInfo.tradeAmount=- ปริมาณการซื้อขาย: {0} @@ -524,6 +533,10 @@ takeOffer.tac=ด้วยข้อเสนอนี้ฉันยอมรั # Offerbook / Edit offer #################################################################### +openOffer.header.triggerPrice=ราคาเงื่อนไขที่ตั้งไว้ +openOffer.triggerPrice=Trigger price {0} +openOffer.triggered=The offer has been deactivated because the market price reached your trigger price.\nPlease edit the offer to define a new trigger price + editOffer.setPrice=ตั้งราคา editOffer.confirmEdit=ยืนยัน: แก้ไขข้อเสนอ editOffer.publishOffer=กำลังเผยแพร่ข้อเสนอของคุณ @@ -541,6 +554,8 @@ portfolio.tab.history=ประวัติ portfolio.tab.failed=ผิดพลาด portfolio.tab.editOpenOffer=แก้ไขข้อเสนอ +portfolio.closedTrades.deviation.help=Percentage price deviation from market + portfolio.pending.invalidDelayedPayoutTx=There is an issue with a missing or invalid transaction.\n\nPlease do NOT send the fiat or altcoin payment. Contact Bisq developers on Keybase [HYPERLINK:https://keybase.io/team/bisq] or on the forum [HYPERLINK:https://bisq.community] for further assistance.\n\nError message: {0} portfolio.pending.step1.waitForConf=รอการยืนยันของบล็อกเชน @@ -886,13 +901,12 @@ funds.tx.noTxAvailable=ไม่มีธุรกรรมใด ๆ funds.tx.revert=กลับสู่สภาพเดิม funds.tx.txSent=ธุรกรรมถูกส่งสำเร็จไปยังที่อยู่ใหม่ใน Bisq wallet ท้องถิ่นแล้ว funds.tx.direction.self=ส่งถึงตัวคุณเอง -funds.tx.daoTxFee=ค่าธรรมเนียมนักขุดสำหรับธุรกรรม DAO +funds.tx.daoTxFee=ค่าธรรมเนียมของนักขุดบิทคอยน์สำหรับการทำธุรกรรม BSQ funds.tx.reimbursementRequestTxFee=ยื่นคำขอการชำระเงินคืน funds.tx.compensationRequestTxFee=คำขอค่าสินไหมทดแทน funds.tx.dustAttackTx=Received dust funds.tx.dustAttackTx.popup=This transaction is sending a very small BTC amount to your wallet and might be an attempt from chain analysis companies to spy on your wallet.\n\nIf you use that transaction output in a spending transaction they will learn that you are likely the owner of the other address as well (coin merge).\n\nTo protect your privacy the Bisq wallet ignores such dust outputs for spending purposes and in the balance display. You can set the threshold amount when an output is considered dust in the settings. - #################################################################### # Support #################################################################### @@ -943,6 +957,7 @@ support.error=ผู้รับไม่สามารถประมวลผ support.buyerAddress=ที่อยู่ของผู้ซื้อ BTC support.sellerAddress=ที่อยู่ของผู้ขาย BTC support.role=บทบาท +support.agent=Support agent support.state=สถานะ support.closed=ปิดแล้ว support.open=เปิด @@ -1052,6 +1067,7 @@ settings.net.creationDateColumn=ที่จัดตั้งขึ้น settings.net.connectionTypeColumn=เข้า/ออก settings.net.sentDataLabel=Sent data statistics settings.net.receivedDataLabel=Received data statistics +settings.net.chainHeightLabel=Latest BTC block height settings.net.roundTripTimeColumn=ไป - กลับ settings.net.sentBytesColumn=ส่งแล้ว settings.net.receivedBytesColumn=ได้รับแล้ว @@ -1066,6 +1082,7 @@ settings.net.needRestart=คุณต้องรีสตาร์ทแอ็ settings.net.notKnownYet=ยังไม่ทราบ ... settings.net.sentData=Sent data: {0}, {1} messages, {2} messages/sec settings.net.receivedData=Received data: {0}, {1} messages, {2} messages/sec +settings.net.chainHeight=Bisq: {0} | Peers: {1} settings.net.ips=[ที่อยู่ IP: พอร์ต | ชื่อโฮสต์: พอร์ต | ที่อยู่ onion: พอร์ต] (คั่นด้วยเครื่องหมายจุลภาค) Port สามารถละเว้นได้ถ้าใช้ค่าเริ่มต้น (8333) settings.net.seedNode=แหล่งโหนดข้อมูล settings.net.directPeer=Peer (โดยตรง) @@ -1074,7 +1091,7 @@ settings.net.inbound=ขาเข้า settings.net.outbound=ขาออก settings.net.reSyncSPVChainLabel=ซิงค์อีกครั้ง SPV chain settings.net.reSyncSPVChainButton=ลบไฟล์ SPV และ ซิงค์อีกครั้ง -settings.net.reSyncSPVSuccess=The SPV chain file will be deleted on the next startup. You need to restart your application now.\n\nAfter the restart it can take a while to resync with the network and you will only see all transactions once the resync is completed.\n\nDepending on the number of transactions and the age of your wallet the resync can take up to a few hours and consumes 100% of CPU. Do not interrupt the process otherwise you have to repeat it. +settings.net.reSyncSPVSuccess=Are you sure you want to do an SPV resync? If you proceed, the SPV chain file will be deleted on the next startup.\n\nAfter the restart it can take a while to resync with the network and you will only see all transactions once the resync is completed.\n\nDepending on the number of transactions and the age of your wallet the resync can take up to a few hours and consumes 100% of CPU. Do not interrupt the process otherwise you have to repeat it. settings.net.reSyncSPVAfterRestart=ไฟล์ SPV chain ถูกลบแล้ว โปรดอดใจรอ อาจใช้เวลาสักครู่เพื่อทำการซิงค์ครั้งใหม่กับเครือข่าย settings.net.reSyncSPVAfterRestartCompleted=การซิงค์เสร็จสมบูรณ์แล้ว โปรดรีสตาร์ทแอ็พพลิเคชั่น settings.net.reSyncSPVFailed=ไม่สามารถลบไฟล์ SPV chain ได้\nข้อผิดพลาด: {0} @@ -1161,9 +1178,19 @@ account.menu.paymentAccount=บัญชีสกุลเงินของป account.menu.altCoinsAccountView=บัญชี Altcoin (เหรียญทางเลือก) account.menu.password=รหัส Wallet account.menu.seedWords=รหัสลับ Wallet +account.menu.walletInfo=Wallet info account.menu.backup=การสำรองข้อมูล account.menu.notifications=การแจ้งเตือน +account.menu.walletInfo.balance.headLine=Wallet balances +account.menu.walletInfo.balance.info=This shows the internal wallet balance including unconfirmed transactions.\nFor BTC, the internal wallet balance shown below should match the sum of the 'Available' and 'Reserved' balances shown in the top right of this window. +account.menu.walletInfo.xpub.headLine=Watch keys (xpub keys) +account.menu.walletInfo.walletSelector={0} {1} wallet +account.menu.walletInfo.path.headLine=HD keychain paths +account.menu.walletInfo.path.info=If you import seed words into another wallet (like Electrum), you'll need to define the path. This should only be done in emergency cases when you lose access to the Bisq wallet and data directory.\nKeep in mind that spending funds from a non-Bisq wallet can bungle the internal Bisq data structures associated with the wallet data, which can lead to failed trades.\n\nNEVER send BSQ from a non-Bisq wallet, as it will probably lead to an invalid BSQ transaction and losing your BSQ. + +account.menu.walletInfo.openDetails=Show raw wallet details and private keys + ## TODO should we rename the following to a gereric name? account.arbitratorRegistration.pubKey=กุญแจสาธารณะ @@ -1796,7 +1823,7 @@ dao.wallet.send.setDestinationAddress=กรอกที่อยู่ปลา dao.wallet.send.send=ส่งเงิน BSQ dao.wallet.send.sendBtc=ส่งเงินทุน BTC dao.wallet.send.sendFunds.headline=ยืนยันคำขอถอนเงิน -dao.wallet.send.sendFunds.details=Sending: {0}\nTo receiving address: {1}.\nRequired transaction fee is: {2} ({3} satoshis/vbyte)\nTransaction vsize: {4} vKb\n\nThe recipient will receive: {5}\n\nAre you sure you want to withdraw that amount? +dao.wallet.send.sendFunds.details=Sending: {0}\nTo receiving address: {1}.\nRequired mining fee is: {2} ({3} satoshis/vbyte)\nTransaction vsize: {4} vKb\n\nThe recipient will receive: {5}\n\nAre you sure you want to withdraw that amount? dao.wallet.chainHeightSynced=บล็อกที่ได้รับการพิสูจน์แล้วล่าสุด: {0} dao.wallet.chainHeightSyncing=บล็อกที่กำลังรอดำเนินการ... ตรวจสอบแล้ว {0} จากบล็อกทั้งหมด {1} dao.wallet.tx.type=หมวด @@ -1928,9 +1955,9 @@ dao.factsAndFigures.menuItem.transactions=BSQ Transactions dao.factsAndFigures.dashboard.avgPrice90=90 days average BSQ/BTC trade price dao.factsAndFigures.dashboard.avgPrice30=30 days average BSQ/BTC trade price -dao.factsAndFigures.dashboard.avgUSDPrice90=90 days volume weighted average USD/BSQ trade price -dao.factsAndFigures.dashboard.avgUSDPrice30=30 days volume weighted average USD/BSQ trade price -dao.factsAndFigures.dashboard.marketCap=โครงสร้างเงินทุนในตลาด (ขึ้นอยู่กับราคาเทรด) +dao.factsAndFigures.dashboard.avgUSDPrice90=90 days volume weighted average USD/BSQ price +dao.factsAndFigures.dashboard.avgUSDPrice30=30 days volume weighted average USD/BSQ price +dao.factsAndFigures.dashboard.marketCap=Market capitalisation (based on 30 days average USD/BSQ price) dao.factsAndFigures.dashboard.availableAmount=BSQ ที่ใช้งานได้ทั้งหมด dao.factsAndFigures.supply.issuedVsBurnt=BSQ issued v. BSQ burnt @@ -2000,7 +2027,7 @@ disputeSummaryWindow.openDate=วันที่ยื่นการเปิ disputeSummaryWindow.role=บทบาทของผู้ค้า disputeSummaryWindow.payout=การจ่ายเงินของจำนวนการซื้อขาย disputeSummaryWindow.payout.getsTradeAmount=BTC {0} รับการจ่ายเงินของปริมาณการซื้อขาย: -disputeSummaryWindow.payout.getsAll=BTC {0} รับทั้งหมด +disputeSummaryWindow.payout.getsAll=Max. payout to BTC {0} disputeSummaryWindow.payout.custom=การชำระเงินที่กำหนดเอง disputeSummaryWindow.payoutAmount.buyer=จำนวนเงินที่จ่ายของผู้ซื้อ disputeSummaryWindow.payoutAmount.seller=จำนวนเงินที่จ่ายของผู้ขาย @@ -2154,6 +2181,7 @@ tradeDetailsWindow.tradingPeersOnion=ที่อยู่ของ onion คู tradeDetailsWindow.tradingPeersPubKeyHash=Trading peers pubkey hash tradeDetailsWindow.tradeState=สถานะการค้า tradeDetailsWindow.agentAddresses=Arbitrator/Mediator +tradeDetailsWindow.detailData=Detail data walletPasswordWindow.headline=ป้อนรหัสผ่านเพื่อปลดล็อก @@ -2183,6 +2211,8 @@ feeOptionWindow.info=คุณสามารถเลือกที่จะ feeOptionWindow.optionsLabel=เลือกสกุลเงินสำหรับการชำระค่าธรรมเนียมการซื้อขาย feeOptionWindow.useBTC=ใช้ BTC feeOptionWindow.fee={0} (≈ {1}) +feeOptionWindow.btcFeeWithFiatAndPercentage={0} (≈ {1} / {2}) +feeOptionWindow.btcFeeWithPercentage={0} ({1}) #################################################################### @@ -2226,6 +2256,7 @@ popup.warning.noMediatorsAvailable=There are no mediators available. popup.warning.notFullyConnected=คุณต้องรอจนกว่าคุณจะเชื่อมต่อกับเครือข่ายอย่างสมบูรณ์\nอาจใช้เวลาประมาณ 2 นาทีเมื่อเริ่มต้น popup.warning.notSufficientConnectionsToBtcNetwork=คุณต้องรอจนกว่าจะมีการเชื่อมต่อกับเครือข่าย Bitcoin อย่างน้อย {0} รายการ popup.warning.downloadNotComplete=คุณต้องรอจนกว่าการดาวน์โหลดบล็อค Bitcoin ที่ขาดหายไปจะเสร็จสมบูรณ์ +popup.warning.chainNotSynced=The Bisq wallet blockchain height is not synced correctly. If you recently started the application, please wait until one Bitcoin block has been published.\n\nYou can check the blockchain height in Settings/Network Info. If more than one block passes and this problem persists it may be stalled, in which case you should do an SPV resync. [HYPERLINK:https://bisq.wiki/Resyncing_SPV_file] popup.warning.removeOffer=คุณแน่ใจหรือไม่ว่าต้องการนำข้อเสนอนั้นออก\nค่าธรรมเนียมของผู้สร้าง {0} จะสูญหายไปหากคุณนำข้อเสนอนั้นออก popup.warning.tooLargePercentageValue=คุณไม่สามารถกำหนดเปอร์เซ็นต์เป็น 100% หรือมากกว่าได้ popup.warning.examplePercentageValue=โปรดป้อนตัวเลขเปอร์เซ็นต์เช่น \"5.4 \" เป็น 5.4% @@ -2254,7 +2285,7 @@ popup.warning.openOffer.makerFeeTxRejected=The maker fee transaction for offer w popup.warning.trade.txRejected.tradeFee=trade fee popup.warning.trade.txRejected.deposit=deposit -popup.warning.trade.txRejected=The {0} transaction for trade with ID {1} was rejected by the Bitcoin network.\nTransaction ID={2}}\nThe trade has been moved to failed trades.\nPlease go to \"Settings/Network info\" and do a SPV resync.\nFor further help please contact the Bisq support channel at the Bisq Keybase team. +popup.warning.trade.txRejected=The {0} transaction for trade with ID {1} was rejected by the Bitcoin network.\nTransaction ID={2}\nThe trade has been moved to failed trades.\nPlease go to \"Settings/Network info\" and do a SPV resync.\nFor further help please contact the Bisq support channel at the Bisq Keybase team. popup.warning.openOfferWithInvalidMakerFeeTx=The maker fee transaction for offer with ID {0} is invalid.\nTransaction ID={1}.\nPlease go to \"Settings/Network info\" and do a SPV resync.\nFor further help please contact the Bisq support channel at the Bisq Keybase team. @@ -2264,14 +2295,15 @@ popup.info.cashDepositInfo=โปรดตรวจสอบว่าคุณ popup.info.cashDepositInfo.confirm=ฉันยืนยันว่าฉันสามารถฝากเงินได้ popup.info.shutDownWithOpenOffers=Bisq คือกำลังจะปิดลง แต่ยังคงมีการเปิดขายข้อเสนอปกติ\nข้อเสนอเหล่านี้จะไม่ใข้งานได้บนเครือข่าย P2P network ในขณะที่ Bisq ปิดตัวลง แต่จะมีการเผยแพร่บนเครือข่าย P2P ครั้งถัดไปเมื่อคุณมีการเริ่มใช้งาน Bisq.\n\nในการคงสถานะข้อเสนอแบบออนไลน์ คือเปิดใข้งาน Bisq และทำให้มั่นใจว่าคอมพิวเตอร์เครื่องนี้กำลังออนไลน์อยู่ด้วยเช่นกัน (เช่น ตรวจสอบว่าคอมพิวเตอร์ไม่ได้อยู่ในโหมดแสตนบายด์...หน้าจอแสตนบายด์ไม่มีปัญหา) popup.info.qubesOSSetupInfo=It appears you are running Bisq on Qubes OS. \n\nPlease make sure your Bisq qube is setup according to our Setup Guide at [HYPERLINK:https://bisq.wiki/Running_Bisq_on_Qubes]. +popup.warn.downGradePrevention=Downgrade from version {0} to version {1} is not supported. Please use the latest Bisq version. +popup.warn.daoRequiresRestart=There was a problem with synchronizing the DAO state. You have to restart the application to fix the issue. popup.privateNotification.headline=การแจ้งเตือนส่วนตัวที่สำคัญ! popup.securityRecommendation.headline=ข้อเสนอแนะด้านความปลอดภัยที่สำคัญ popup.securityRecommendation.msg=เราขอแจ้งเตือนให้คุณพิจารณาใช้การป้องกันด้วยรหัสผ่านสำหรับ wallet ของคุณ หากยังไม่ได้เปิดใช้งาน\n\nขอแนะนำให้เขียนรหัสลับป้องกัน wallet รหัสลับเหล่านี้เหมือนกับรหัสผ่านหลักสำหรับการกู้คืน Bitcoin wallet ของคุณ\nไปที่ \"กระเป๋าสตางค์ \" คุณจะพบข้อมูลเพิ่มเติม\n\nนอกจากนี้คุณควรสำรองโฟลเดอร์ข้อมูลแอ็พพลิเคชั่นทั้งหมดไว้ที่ส่วน \"สำรองข้อมูล \" -popup.bitcoinLocalhostNode.msg=Bisq ตรวจพบเฉพาะบิตโหนดหลักของ Bitcoin ที่ใช้งานอยู่ (ที่ localhost)\nโปรดตรวจสอบว่าโหนดนี้ได้รับการซิงค์อย่างสมบูรณ์ก่อนที่คุณจะเริ่ม Bisq และไม่ได้ทำงานในโหมด pruned -popup.bitcoinLocalhostNode.additionalRequirements=\n\nFor a well configured node, the requirements are for the node to have pruning disabled and bloom filters enabled. +popup.bitcoinLocalhostNode.msg=Bisq detected a Bitcoin Core node running on this machine (at localhost).\n\nPlease ensure:\n- the node is fully synced before starting Bisq\n- pruning is disabled ('prune=0' in bitcoin.conf)\n- bloom filters are enabled ('peerbloomfilters=1' in bitcoin.conf) popup.shutDownInProgress.headline=การปิดระบบอยู่ระหว่างดำเนินการ popup.shutDownInProgress.msg=การปิดแอพพลิเคชั่นอาจใช้เวลาสักครู่\nโปรดอย่าขัดจังหวะกระบวนการนี้ @@ -2303,15 +2335,12 @@ popup.accountSigning.signedByPeer=One of your payment accounts has been verified popup.accountSigning.peerLimitLifted=The initial limit for one of your accounts has been lifted.\n\n{0} popup.accountSigning.peerSigner=One of your accounts is mature enough to sign other payment accounts and the initial limit for one of your accounts has been lifted.\n\n{0} -popup.accountSigning.singleAccountSelect.headline=Select account age witness -popup.accountSigning.singleAccountSelect.description=Search for account age witness. -popup.accountSigning.singleAccountSelect.datePicker=Select point of time for signing +popup.accountSigning.singleAccountSelect.headline=Import unsigned account age witness popup.accountSigning.confirmSingleAccount.headline=Confirm selected account age witness popup.accountSigning.confirmSingleAccount.selectedHash=Selected witness hash popup.accountSigning.confirmSingleAccount.button=Sign account age witness popup.accountSigning.successSingleAccount.description=Witness {0} was signed popup.accountSigning.successSingleAccount.success.headline=Success -popup.accountSigning.successSingleAccount.signError=Failed to sign witness, {0} popup.accountSigning.unsignedPubKeys.headline=Unsigned Pubkeys popup.accountSigning.unsignedPubKeys.sign=Sign Pubkeys @@ -2447,8 +2476,8 @@ navigation.dao.wallet.receive=\ "Wallet DAO / BSQ / การรับ \" formatter.formatVolumeLabel={0} จำนวนยอด{1} formatter.makerTaker=ผู้สร้าง เป็น {0} {1} / ผู้รับเป็น {2} {3} -formatter.youAreAsMaker=คุณคือ {0} {1} ในฐานะผู้สร้าง / ผู้รับคือ {2} {3} -formatter.youAreAsTaker=คุณคือ {0} {1} เป็นผู้รับ / ผู้สร้างคือ {2} {3} +formatter.youAreAsMaker=You are: {1} {0} (maker) / Taker is: {3} {2} +formatter.youAreAsTaker=You are: {1} {0} (taker) / Maker is: {3} {2} formatter.youAre=คุณคือ {0} {1} ({2} {3}) formatter.youAreCreatingAnOffer.fiat=คุณกำลังสร้างข้อเสนอให้ {0} {1} formatter.youAreCreatingAnOffer.altcoin=คุณกำลังสร้างข้อเสนอให้กับ {0} {1} ({2} {3}) @@ -2561,6 +2590,7 @@ payment.venmo.venmoUserName=ชื่อผู้ใช้ Venmo payment.popmoney.accountId=อีเมลหรือหมายเลขโทรศัพท์ payment.promptPay.promptPayId=รหัสบัตรประชาชน/รหัสประจำตัวผู้เสียภาษี หรือเบอร์โทรศัพท์ payment.supportedCurrencies=สกุลเงินที่ได้รับการสนับสนุน +payment.supportedCurrenciesForReceiver=Currencies for receiving funds payment.limitations=ข้อจำกัด payment.salt=ข้อมูลแบบสุ่มสำหรับการตรวจสอบอายุบัญชี payment.error.noHexSalt=The salt needs to be in HEX format.\nIt is only recommended to edit the salt field if you want to transfer the salt from an old account to keep your account age. The account age is verified by using the account salt and the identifying account data (e.g. IBAN). @@ -2635,7 +2665,8 @@ payment.japan.recipient=ชื่อ payment.australia.payid=PayID payment.payid=PayID linked to financial institution. Like email address or mobile phone. payment.payid.info=A PayID like a phone number, email address or an Australian Business Number (ABN), that you can securely link to your bank, credit union or building society account. You need to have already created a PayID with your Australian financial institution. Both sending and receiving financial institutions must support PayID. For more information please check [HYPERLINK:https://payid.com.au/faqs/] -payment.amazonGiftCard.info=To pay with Amazon eGift Card you need to purchase an Amazon eGift Card at your Amazon account and use the BTC seller''s email or mobile nr. as receiver. Amazon sends then an email or text message to the receiver. Use the trade ID for the message field.\n\nAmazon eGift Cards can only be redeemed by Amazon accounts with the same currency.\n\nFor more information visit the Amazon eGift Card webpage. [HYPERLINK:https://www.amazon.com/Amazon-1_US_Email-eGift-Card/dp/B004LLIKVU] +payment.amazonGiftCard.info=To pay with Amazon eGift Card, you will need to send an Amazon eGift Card to the BTC seller via your Amazon account. \n\nBisq will show the BTC seller''s email address or phone number where the gift card should be sent, and you must include the trade ID in the gift card''s message field. Please see the wiki [HYPERLINK:https://bisq.wiki/Amazon_eGift_card] for further details and best practices. \n\nThree important notes:\n- try to send gift cards with amounts of 100 USD or smaller, as Amazon is known to flag larger gift cards as fraudulent\n- try to use creative, believable text for the gift card''s message (e.g., "Happy birthday Susan!") along with the trade ID (and use trader chat to tell your trading peer the reference text you picked so they can verify your payment)\n- Amazon eGift Cards can only be redeemed on the Amazon website they were purchased on (e.g., a gift card purchased on amazon.it can only be redeemed on amazon.it) + # We use constants from the code so we do not use our normal naming convention # dynamic values are not recognized by IntelliJ diff --git a/core/src/main/resources/i18n/displayStrings_vi.properties b/core/src/main/resources/i18n/displayStrings_vi.properties index 4533181518..5eb3b05182 100644 --- a/core/src/main/resources/i18n/displayStrings_vi.properties +++ b/core/src/main/resources/i18n/displayStrings_vi.properties @@ -71,6 +71,7 @@ shared.amountWithCur=Thành tiền bằng {0} shared.volumeWithCur=Khối lượng bằng {0} shared.currency=Tiền tệ shared.market=Thị trường +shared.deviation=Deviation shared.paymentMethod=Hình thức thanh toán shared.tradeCurrency=Loại tiền tệ giao dịch shared.offerType=Loại chào giá @@ -104,7 +105,6 @@ shared.selectTradingAccount=Chọn tài khoản giao dịch shared.fundFromSavingsWalletButton=Chuyển tiền từ Ví Bisq shared.fundFromExternalWalletButton=Mở ví ngoài để nộp tiền shared.openDefaultWalletFailed=Failed to open a Bitcoin wallet application. Are you sure you have one installed? -shared.distanceInPercent=Chênh lệch % so với giá thị trường shared.belowInPercent=Thấp hơn % so với giá thị trường shared.aboveInPercent=Cao hơn % so với giá thị trường shared.enterPercentageValue=Nhập giá trị % @@ -191,7 +191,7 @@ shared.tradeWalletBalance=Số dư ví giao dịch shared.makerTxFee=Người tạo: {0} shared.takerTxFee=Người nhận: {0} shared.iConfirm=Tôi xác nhận -shared.tradingFeeInBsqInfo=equivalent to {0} used as trading fee +shared.tradingFeeInBsqInfo=≈ {0} shared.openURL=Mở {0} shared.fiat=Tiền pháp định shared.crypto=Tiền mã hóa @@ -218,6 +218,9 @@ shared.refundAgentForSupportStaff=Refund agent shared.delayedPayoutTxId=Delayed payout transaction ID shared.delayedPayoutTxReceiverAddress=Delayed payout transaction sent to shared.unconfirmedTransactionsLimitReached=You have too many unconfirmed transactions at the moment. Please try again later. +shared.numItemsLabel=Number of entries: {0} +shared.filter=Filter +shared.enabled=Enabled #################################################################### @@ -248,14 +251,14 @@ mainView.balance.locked=Khóa trong giao dịch mainView.balance.reserved.short=Bảo lưu mainView.balance.locked.short=Bị khóa -mainView.footer.usingTor=(sử dụng Tor) +mainView.footer.usingTor=(via Tor) mainView.footer.localhostBitcoinNode=(Máy chủ nội bộ) -mainView.footer.btcInfo={0} {1} {2} -mainView.footer.btcFeeRate=/ Current fee rate: {0} sat/vB +mainView.footer.btcInfo={0} {1} +mainView.footer.btcFeeRate=/ Fee rate: {0} sat/vB mainView.footer.btcInfo.initializing=Đang kết nối với mạng Bitcoin mainView.footer.bsqInfo.synchronizing=/ Đang đồng bộ hóa DAO -mainView.footer.btcInfo.synchronizingWith=Synchronizing with -mainView.footer.btcInfo.synchronizedWith=Synced with +mainView.footer.btcInfo.synchronizingWith=Synchronizing with {0} at block: {1} / {2} +mainView.footer.btcInfo.synchronizedWith=Synced with {0} at block {1} mainView.footer.btcInfo.connectingTo=Đang kết nối với mainView.footer.btcInfo.connectionFailed=Connection failed to mainView.footer.p2pInfo=Bitcoin network peers: {0} / Bisq network peers: {1} @@ -336,10 +339,10 @@ offerbook.offerersAcceptedBankSeats=Các quốc gia có ngân hàng được ch offerbook.availableOffers=Các chào giá hiện có offerbook.filterByCurrency=Lọc theo tiền tệ offerbook.filterByPaymentMethod=Lọc theo phương thức thanh toán -offerbook.timeSinceSigning=Signed since +offerbook.timeSinceSigning=Account info offerbook.timeSinceSigning.info=This account was verified and {0} offerbook.timeSinceSigning.info.arbitrator=signed by an arbitrator and can sign peer accounts -offerbook.timeSinceSigning.info.peer=signed by a peer, waiting for limits to be lifted +offerbook.timeSinceSigning.info.peer=signed by a peer, waiting %d days for limits to be lifted offerbook.timeSinceSigning.info.peerLimitLifted=signed by a peer and limits were lifted offerbook.timeSinceSigning.info.signer=signed by peer and can sign peer accounts (limits lifted) offerbook.timeSinceSigning.info.banned=account was banned @@ -349,9 +352,12 @@ offerbook.xmrAutoConf=Is auto-confirm enabled offerbook.timeSinceSigning.help=When you successfully complete a trade with a peer who has a signed payment account, your payment account is signed.\n{0} days later, the initial limit of {1} is lifted and your account can sign other peers'' payment accounts. offerbook.timeSinceSigning.notSigned=Not signed yet +offerbook.timeSinceSigning.notSigned.ageDays={0} ngày offerbook.timeSinceSigning.notSigned.noNeed=Không áp dụng -shared.notSigned=This account hasn't been signed yet -shared.notSigned.noNeed=This account type doesn't use signing +shared.notSigned=This account has not been signed yet and was created {0} days ago +shared.notSigned.noNeed=This account type does not require signing +shared.notSigned.noNeedDays=This account type does not require signing and was created {0} days ago +shared.notSigned.noNeedAlts=Altcoin accounts do not feature signing or aging offerbook.nrOffers=Số chào giá: {0} offerbook.volume={0} (min - max) @@ -435,11 +441,15 @@ createOffer.warning.sellBelowMarketPrice=Bạn sẽ luôn nhận {0}% thấp hơ createOffer.warning.buyAboveMarketPrice=Bạn sẽ luôn trả {0}% cao hơn so với giá thị trường hiện tại vì báo giá của bạn sẽ luôn được cập nhật. createOffer.tradeFee.descriptionBTCOnly=Phí giao dịch createOffer.tradeFee.descriptionBSQEnabled=Chọn loại tiền trả phí giao dịch -createOffer.tradeFee.fiatAndPercent=≈ {0} / {1} giá trị giao dịch + +createOffer.triggerPrice.prompt=Set optional trigger price +createOffer.triggerPrice.label=Deactivate offer if market price is {0} +createOffer.triggerPrice.tooltip=As protecting against drastic price movements you can set a trigger price which deactivates the offer if the market price reaches that value. +createOffer.triggerPrice.invalid.tooLow=Value must be higher than {0} +createOffer.triggerPrice.invalid.tooHigh=Value must be lower than {0} # new entries createOffer.placeOfferButton=Kiểm tra:: Đặt báo giá cho {0} bitcoin -createOffer.alreadyFunded=Bạn đã nộp tiền cho chào giá.\nSố tiền của bạn đã được chuyển sang ví Bisq nội bộ và luôn sẵn sàng để rút ra tại màn hình \"Vốn/Gửi vốn\" screen. createOffer.createOfferFundWalletInfo.headline=Nộp tiền cho báo giá của bạn # suppress inspection "TrailingSpacesInProperty" createOffer.createOfferFundWalletInfo.tradeAmount=- Khoản tiền giao dịch: {0} \n @@ -496,7 +506,6 @@ takeOffer.error.message=Có lỗi xảy ra khi nhận báo giá.\n\n{0} # new entries takeOffer.takeOfferButton=Rà soát: Nhận báo giá cho {0} bitcoin takeOffer.noPriceFeedAvailable=Bạn không thể nhận báo giá này do sử dụng giá phần trăm dựa trên giá thị trường nhưng không có giá cung cấp. -takeOffer.alreadyFunded.movedFunds=Bạn đã nộp tiền cho báo giá này.\nKhoản tiền này sẽ được chuyển sang ví Bisq nội bộ của bạn và sẵn sàng để rút tại màn hình \"Vốn/Gửi vốn\". takeOffer.takeOfferFundWalletInfo.headline=Nộp tiền cho giao dịch của bạn # suppress inspection "TrailingSpacesInProperty" takeOffer.takeOfferFundWalletInfo.tradeAmount=- Giá trị giao dịch: {0} \n @@ -524,6 +533,10 @@ takeOffer.tac=Bằng cách nhận báo giá này, tôi đồng ý với các đi # Offerbook / Edit offer #################################################################### +openOffer.header.triggerPrice=Giá khởi phát +openOffer.triggerPrice=Trigger price {0} +openOffer.triggered=The offer has been deactivated because the market price reached your trigger price.\nPlease edit the offer to define a new trigger price + editOffer.setPrice=Cài đặt giá editOffer.confirmEdit=Xác nhận: Chỉnh sửa báo giá editOffer.publishOffer=Công bố báo giá. @@ -541,6 +554,8 @@ portfolio.tab.history=Lịch sử portfolio.tab.failed=Không thành công portfolio.tab.editOpenOffer=Chỉnh sửa báo giá +portfolio.closedTrades.deviation.help=Percentage price deviation from market + portfolio.pending.invalidDelayedPayoutTx=There is an issue with a missing or invalid transaction.\n\nPlease do NOT send the fiat or altcoin payment. Contact Bisq developers on Keybase [HYPERLINK:https://keybase.io/team/bisq] or on the forum [HYPERLINK:https://bisq.community] for further assistance.\n\nError message: {0} portfolio.pending.step1.waitForConf=Đợi xác nhận blockchain @@ -886,12 +901,11 @@ funds.tx.noTxAvailable=Không có giao dịch nào funds.tx.revert=Khôi phục funds.tx.txSent=GIao dịch đã gửi thành công tới địa chỉ mới trong ví Bisq nội bộ. funds.tx.direction.self=Gửi cho chính bạn -funds.tx.daoTxFee=Phí đào cho giao dịch DAO +funds.tx.daoTxFee=Phí đào cho giao dịch BSQ funds.tx.reimbursementRequestTxFee=Yêu cầu bồi hoàn funds.tx.compensationRequestTxFee=Yêu cầu bồi thường funds.tx.dustAttackTx=Số dư nhỏ đã nhận -funds.tx.dustAttackTx.popup=Giao dịch này đang gửi một lượng BTC rất nhỏ vào ví của bạn và có thể đây là cách các công ty phân tích chuỗi đang tìm cách theo dõi ví của bạn.\nNếu bạn sử dụng đầu ra giao dịch đó cho một giao dịch chi tiêu, họ sẽ phát hiện ra rằng rất có thể bạn cũng là người sở hửu cái ví kia (nhập coin). \n\nĐể bảo vệ quyền riêng tư của bạn, ví Bisq sẽ bỏ qua các đầu ra có số dư nhỏ dành cho mục đích chi tiêu cũng như hiển thị số dư. Bạn có thể thiết lập ngưỡng khi một đầu ra được cho là có số dư nhỏ trong phần cài đặt. - +funds.tx.dustAttackTx.popup=Giao dịch này đang gửi một lượng BTC rất nhỏ vào ví của bạn và có thể đây là cách các công ty phân tích chuỗi đang tìm cách theo dõi ví của bạn.\nNếu bạn sử dụng đầu ra giao dịch đó cho một giao dịch chi tiêu, họ sẽ phát hiện ra rằng rất có thể bạn cũng là người sở hửu cái ví kia (nhập coin). \n\nĐể bảo vệ quyền riêng tư của bạn, ví Bisq sẽ bỏ qua các đầu ra có số dư nhỏ dành cho mục đích chi tiêu cũng như hiển thị số dư. Bạn có thể thiết lập ngưỡng khi một đầu ra được cho là có số dư nhỏ trong phần cài đặt. #################################################################### # Support @@ -943,6 +957,7 @@ support.error=Người nhận không thể tiến hành gửi tin nhắn: Lỗi: support.buyerAddress=Địa chỉ người mua BTC support.sellerAddress=Địa chỉ người bán BTC support.role=Vai trò +support.agent=Support agent support.state=Trạng thái support.closed=Đóng support.open=Mở @@ -1052,6 +1067,7 @@ settings.net.creationDateColumn=Đã thiết lập settings.net.connectionTypeColumn=Vào/Ra settings.net.sentDataLabel=Sent data statistics settings.net.receivedDataLabel=Received data statistics +settings.net.chainHeightLabel=Latest BTC block height settings.net.roundTripTimeColumn=Khứ hồi settings.net.sentBytesColumn=Đã gửi settings.net.receivedBytesColumn=Đã nhận @@ -1066,6 +1082,7 @@ settings.net.needRestart=Bạn cần khởi động lại ứng dụng để tha settings.net.notKnownYet=Chưa biết... settings.net.sentData=Sent data: {0}, {1} messages, {2} messages/sec settings.net.receivedData=Received data: {0}, {1} messages, {2} messages/sec +settings.net.chainHeight=Bisq: {0} | Peers: {1} settings.net.ips=[Địa chỉ IP:tên cổng | máy chủ:cổng | Địa chỉ onion:cổng] (tách bằng dấu phẩy). Cổng có thể bỏ qua nếu sử dụng mặc định (8333). settings.net.seedNode=nút cung cấp thông tin settings.net.directPeer=Đối tác (trực tiếp) @@ -1074,7 +1091,7 @@ settings.net.inbound=chuyến về settings.net.outbound=chuyến đi settings.net.reSyncSPVChainLabel=Đồng bộ hóa lại SPV chain settings.net.reSyncSPVChainButton=Xóa file SPV và đồng bộ hóa lại -settings.net.reSyncSPVSuccess=The SPV chain file will be deleted on the next startup. You need to restart your application now.\n\nAfter the restart it can take a while to resync with the network and you will only see all transactions once the resync is completed.\n\nDepending on the number of transactions and the age of your wallet the resync can take up to a few hours and consumes 100% of CPU. Do not interrupt the process otherwise you have to repeat it. +settings.net.reSyncSPVSuccess=Are you sure you want to do an SPV resync? If you proceed, the SPV chain file will be deleted on the next startup.\n\nAfter the restart it can take a while to resync with the network and you will only see all transactions once the resync is completed.\n\nDepending on the number of transactions and the age of your wallet the resync can take up to a few hours and consumes 100% of CPU. Do not interrupt the process otherwise you have to repeat it. settings.net.reSyncSPVAfterRestart=File chuỗi SPV đã được xóa. Vui lòng đợi, có thể mất một lúc để đồng bộ hóa với mạng. settings.net.reSyncSPVAfterRestartCompleted=Đồng bộ hóa đã xong. Vui lòng khởi động lại ứng dụng. settings.net.reSyncSPVFailed=Không thể xóa SPV chain file.\nLỗi: {0} @@ -1161,9 +1178,19 @@ account.menu.paymentAccount=Tài khoản tiền tệ quốc gia account.menu.altCoinsAccountView=Tài khoản Altcoin account.menu.password=Password ví account.menu.seedWords=Mã sao lưu dự phòng ví +account.menu.walletInfo=Wallet info account.menu.backup=Dự phòng account.menu.notifications=Thông báo +account.menu.walletInfo.balance.headLine=Wallet balances +account.menu.walletInfo.balance.info=This shows the internal wallet balance including unconfirmed transactions.\nFor BTC, the internal wallet balance shown below should match the sum of the 'Available' and 'Reserved' balances shown in the top right of this window. +account.menu.walletInfo.xpub.headLine=Watch keys (xpub keys) +account.menu.walletInfo.walletSelector={0} {1} wallet +account.menu.walletInfo.path.headLine=HD keychain paths +account.menu.walletInfo.path.info=If you import seed words into another wallet (like Electrum), you'll need to define the path. This should only be done in emergency cases when you lose access to the Bisq wallet and data directory.\nKeep in mind that spending funds from a non-Bisq wallet can bungle the internal Bisq data structures associated with the wallet data, which can lead to failed trades.\n\nNEVER send BSQ from a non-Bisq wallet, as it will probably lead to an invalid BSQ transaction and losing your BSQ. + +account.menu.walletInfo.openDetails=Show raw wallet details and private keys + ## TODO should we rename the following to a gereric name? account.arbitratorRegistration.pubKey=Public key (địa chỉ ví) @@ -1203,9 +1230,9 @@ account.altcoin.popup.ZEC.msg=When using Zcash you can only use the transparent # suppress inspection "UnusedProperty" account.altcoin.popup.XZC.msg=When using Zcoin you can only use the transparent (traceable) addresses, not the untraceable addresses, because the mediator or arbitrator would not be able to verify the transaction with untraceable addresses at a block explorer. # suppress inspection "UnusedProperty" -account.altcoin.popup.grin.msg=GRIN yêu cầu một quá trình tương tác giữa người gửi và người nhận để thực hiện một giao dịch. Vui lòng làm theo hướng dẫn từ trang web của dự án GRIN để gửi và nhận GRIN đúng cách. (người nhận cần phải trực tuyến hoặc ít nhất là trực tuyến trong một khung thời gian nhất định).\n\nBisq chỉ hỗ trợ ví Grinbox(wallet713) theo định dạng URL.\n\nNgười gửi GRIN phải cung cấp bằng chứng là họ đã gửi GRIN thành công. Nếu ví không thể cung cấp bằng chứng đó, nếu có tranh chấp thì sẽ được giải quyết theo hướng có lợi cho người nhận GRIN. Vui lòng đảm bảo rằng bạn sử dụng phần mềm Grinbox mới nhất có hỗ trợ bằng chứng giao dịch và bạn hiểu quy trình chuyển và nhận GRIN cũng như tạo bằng chứng. \n\nXem https://github.com/vault713/wallet713/blob/master/docs/usage.md#transaction-proofs-grinbox-only để biết thêm thông tin về công cụ bằng chứng Grinbox. +account.altcoin.popup.grin.msg=GRIN yêu cầu một quá trình tương tác giữa người gửi và người nhận để thực hiện một giao dịch. Vui lòng làm theo hướng dẫn từ trang web của dự án GRIN để gửi và nhận GRIN đúng cách. (người nhận cần phải trực tuyến hoặc ít nhất là trực tuyến trong một khung thời gian nhất định).\n\nBisq chỉ hỗ trợ ví Grinbox(wallet713) theo định dạng URL.\n\nNgười gửi GRIN phải cung cấp bằng chứng là họ đã gửi GRIN thành công. Nếu ví không thể cung cấp bằng chứng đó, nếu có tranh chấp thì sẽ được giải quyết theo hướng có lợi cho người nhận GRIN. Vui lòng đảm bảo rằng bạn sử dụng phần mềm Grinbox mới nhất có hỗ trợ bằng chứng giao dịch và bạn hiểu quy trình chuyển và nhận GRIN cũng như tạo bằng chứng. \n\nXem https://github.com/vault713/wallet713/blob/master/docs/usage.md#transaction-proofs-grinbox-only để biết thêm thông tin về công cụ bằng chứng Grinbox. # suppress inspection "UnusedProperty" -account.altcoin.popup.beam.msg=BEAM yêu cầu một quá trình tương tác giữa người gửi và người nhận để thực hiện một giao dịch. \n\nVui lòng làm theo hướng dẫn từ trang web của dự án BEAM để gửi và nhận BEAM đúng cách. (người nhận cần phải trực tuyến hoặc ít nhất là trực tuyến trong một khung thời gian nhất định).\n\nNgười gửi BEAM phải cung cấp bằng chứng là họ đã gửi BEAM thành công. Vui lòng đảm bảo là bạn sử dụng phần mềm ví có thể tạo ra một bằng chứng như vậy. Nếu ví không thể cung cấp bằng chứng đó, nếu có tranh chấp thì sẽ được giải quyết theo hướng có lợi cho người nhận BEAM. +account.altcoin.popup.beam.msg=BEAM yêu cầu một quá trình tương tác giữa người gửi và người nhận để thực hiện một giao dịch. \n\nVui lòng làm theo hướng dẫn từ trang web của dự án BEAM để gửi và nhận BEAM đúng cách. (người nhận cần phải trực tuyến hoặc ít nhất là trực tuyến trong một khung thời gian nhất định).\n\nNgười gửi BEAM phải cung cấp bằng chứng là họ đã gửi BEAM thành công. Vui lòng đảm bảo là bạn sử dụng phần mềm ví có thể tạo ra một bằng chứng như vậy. Nếu ví không thể cung cấp bằng chứng đó, nếu có tranh chấp thì sẽ được giải quyết theo hướng có lợi cho người nhận BEAM. # suppress inspection "UnusedProperty" account.altcoin.popup.pars.msg=Trading ParsiCoin on Bisq requires that you understand and fulfill the following requirements:\n\nTo send PARS you must use the official ParsiCoin Wallet version 3.0.0 or higher. \n\nYou can Check your Transaction Hash and Transaction Key on Transactions Section on your GUI Wallet (ParsiPay) You need to right Click on the Transaction and then click on show details. \n\nIn the event that arbitration is necessary, you must present the following to an mediator or arbitrator: 1) the Transaction Hash, 2) the Transaction Key, and 3) the recipient's PARS address. The mediator or arbitrator will then verify the PARS transfer using the ParsiCoin Block Explorer (http://explorer.parsicoin.net/#check_payment).\n\nFailure to provide the required information to the mediator or arbitrator will result in losing the dispute case. In all cases of dispute, the ParsiCoin sender bears 100% of the burden of responsibility in verifying transactions to an mediator or arbitrator. \n\nIf you do not understand these requirements, do not trade on Bisq. First, seek help at the ParsiCoin Discord (https://discord.gg/c7qmFNh). @@ -1239,7 +1266,7 @@ account.seed.backup.warning=Please note that the seed words are NOT a replacemen account.seed.warn.noPw.msg=Bạn đã tạo mật khẩu ví để bảo vệ tránh hiển thị Seed words.\n\nBạn có muốn hiển thị Seed words? account.seed.warn.noPw.yes=Có và không hỏi lại account.seed.enterPw=Nhập mật khẩu để xem seed words -account.seed.restore.info=Vui lòng tạo sao lưu dự phòng trước khi tiến hành khôi phục ví từ các từ khởi tạo. Phải hiểu rằng việc khôi phục ví chỉ nên thực hiện trong các trường hợp khẩn cấp và có thể gây sự cố với cơ sở dữ liệu ví bên trong.\nĐây không phải là một cách sao lưu dự phòng! Vui lòng sử dụng sao lưu dự phòng từ thư mục dữ liệu của ứng dụng để khôi phục trạng thái ban đầu của ứng dụng.\n\nSau khi khôi phục ứng dụng sẽ tự động tắt. Sau khi bạn khởi động lại, ứng dụng sẽ tái đồng bộ với mạng Bitcoin. Quá trình này có thể mất một lúc và tiêu tốn khá nhiều CPU, đặc biệt là khi ví đã cũ và có nhiều giao dịch. Vui lòng không làm gián đoạn quá trình này, nếu không bạn có thể sẽ phảỉ xóa file chuỗi SPV một lần nữa hoặc lặp lại quy trình khôi phục. +account.seed.restore.info=Vui lòng tạo sao lưu dự phòng trước khi tiến hành khôi phục ví từ các từ khởi tạo. Phải hiểu rằng việc khôi phục ví chỉ nên thực hiện trong các trường hợp khẩn cấp và có thể gây sự cố với cơ sở dữ liệu ví bên trong.\nĐây không phải là một cách sao lưu dự phòng! Vui lòng sử dụng sao lưu dự phòng từ thư mục dữ liệu của ứng dụng để khôi phục trạng thái ban đầu của ứng dụng.\n\nSau khi khôi phục ứng dụng sẽ tự động tắt. Sau khi bạn khởi động lại, ứng dụng sẽ tái đồng bộ với mạng Bitcoin. Quá trình này có thể mất một lúc và tiêu tốn khá nhiều CPU, đặc biệt là khi ví đã cũ và có nhiều giao dịch. Vui lòng không làm gián đoạn quá trình này, nếu không bạn có thể sẽ phảỉ xóa file chuỗi SPV một lần nữa hoặc lặp lại quy trình khôi phục. account.seed.restore.ok=Được, hãy thực hiện khôi phục và tắt ứng dụng Bisq @@ -1796,7 +1823,7 @@ dao.wallet.send.setDestinationAddress=Điền địa chỉ đến của bạn dao.wallet.send.send=Gửi vốn BSQ dao.wallet.send.sendBtc=Gửi vốn BTC dao.wallet.send.sendFunds.headline=Xác nhận yêu cầu rút -dao.wallet.send.sendFunds.details=Sending: {0}\nTo receiving address: {1}.\nRequired transaction fee is: {2} ({3} satoshis/vbyte)\nTransaction vsize: {4} vKb\n\nThe recipient will receive: {5}\n\nAre you sure you want to withdraw that amount? +dao.wallet.send.sendFunds.details=Sending: {0}\nTo receiving address: {1}.\nRequired mining fee is: {2} ({3} satoshis/vbyte)\nTransaction vsize: {4} vKb\n\nThe recipient will receive: {5}\n\nAre you sure you want to withdraw that amount? dao.wallet.chainHeightSynced=Khối đã xác minh mới nhất: {0} dao.wallet.chainHeightSyncing=Đang chờ khối mới... Đã xác nhận{0} / {1} khối dao.wallet.tx.type=Loại @@ -1859,11 +1886,11 @@ dao.feeTx.confirm.details={0} fee: {1}\nMining fee: {2} ({3} Satoshis/vbyte)\nTr dao.feeTx.issuanceProposal.confirm.details={0} fee: {1}\nBTC needed for BSQ issuance: {2} ({3} Satoshis/BSQ)\nMining fee: {4} ({5} Satoshis/vbyte)\nTransaction vsize: {6} vKb\n\nIf your request is approved, you will receive the amount you requested net of the 2 BSQ proposal fee.\n\nAre you sure you want to publish the {7} transaction? dao.news.bisqDAO.title=DAO BISQ -dao.news.bisqDAO.description=Vì BIsq là sàn giao dịch phi tập trung và không bị kiểm duyệt, bởi vậy mô hình vận hành của nó, DAO Bisq và đồng BSQ là công cụ giúp điều này trở thành hiện thực. +dao.news.bisqDAO.description=Vì BIsq là sàn giao dịch phi tập trung và không bị kiểm duyệt, bởi vậy mô hình vận hành của nó, DAO Bisq và đồng BSQ là công cụ giúp điều này trở thành hiện thực. dao.news.bisqDAO.readMoreLink=Tìm hiểu thêm về DAO Bisq dao.news.pastContribution.title=BẠN ĐÃ THAM GIA ĐÓNG GÓP? YÊU CẦU BSQ -dao.news.pastContribution.description=Nếu như bạn đã tham giao đóng góp cho Bisq, vui lòng sử dụng ví BSQ phía dưới và thực hiện một yêu cầu tham gia vào sự kiện phát hành BSQ genesis. +dao.news.pastContribution.description=Nếu như bạn đã tham giao đóng góp cho Bisq, vui lòng sử dụng ví BSQ phía dưới và thực hiện một yêu cầu tham gia vào sự kiện phát hành BSQ genesis. dao.news.pastContribution.yourAddress=Ví BSQ của bạn dao.news.pastContribution.requestNow=Yêu cầu ngay @@ -1874,9 +1901,9 @@ dao.news.DAOOnTestnet.firstSection.content=1. Chuyển qua chế độ Testnet D dao.news.DAOOnTestnet.secondSection.title=2. Kiếm BSQ dao.news.DAOOnTestnet.secondSection.content=Yêu cầu BSQ trên Slack hoặc Mua BSQ trên Bisq dao.news.DAOOnTestnet.thirdSection.title=3. Tham gia một vòng bỏ phiếu -dao.news.DAOOnTestnet.thirdSection.content=Tạo đề xuất và bỏ phiếu cho đề xuất để thanh đổi nhiều khía cạnh của Bisq. +dao.news.DAOOnTestnet.thirdSection.content=Tạo đề xuất và bỏ phiếu cho đề xuất để thanh đổi nhiều khía cạnh của Bisq. dao.news.DAOOnTestnet.fourthSection.title=4. Tìm hiểu về BSQ Block Explorer -dao.news.DAOOnTestnet.fourthSection.content=Vì BSQ chỉa là bitcoin, bạn có thể thấy các giao dịch BSQ trên trình duyện bitcoin Block Explorer của chúng tôi. +dao.news.DAOOnTestnet.fourthSection.content=Vì BSQ chỉa là bitcoin, bạn có thể thấy các giao dịch BSQ trên trình duyện bitcoin Block Explorer của chúng tôi. dao.news.DAOOnTestnet.readMoreLink=Đọc tài liệu đầy đủ dao.monitor.daoState=Trạng thái DAO @@ -1894,7 +1921,7 @@ dao.monitor.table.seedPeers=Seed node: {0} dao.monitor.daoState.headline=Trạng thái DAO dao.monitor.daoState.table.headline=Chuỗi Hash trạng thái DAO -dao.monitor.daoState.table.blockHeight=Chiều cao khối +dao.monitor.daoState.table.blockHeight=Chiều cao khối dao.monitor.daoState.table.hash=Hash của trạng thái DAO dao.monitor.daoState.table.prev=Hash trước đó dao.monitor.daoState.conflictTable.headline=Hash trạng thái DAO từ đối tác đang trong xung dột @@ -1912,7 +1939,7 @@ dao.monitor.proposal.table.hash=Hash trạng thái đề xuất dao.monitor.proposal.table.prev=Hash trước đó dao.monitor.proposal.table.numProposals=Số đề xuất -dao.monitor.isInConflictWithSeedNode=Dữ liệu trên máy bạn không đồng bộ với ít nhất một seed node. Vui lòng đồng bộ lại trạng thái DAO. +dao.monitor.isInConflictWithSeedNode=Dữ liệu trên máy bạn không đồng bộ với ít nhất một seed node. Vui lòng đồng bộ lại trạng thái DAO. dao.monitor.isInConflictWithNonSeedNode=Một trong các đối tác của bạn không đồng bộ với mạng nhưng node của bạn vẫn đang đồng bộ với các seed node. dao.monitor.daoStateInSync=Node trên máy tính của bạn đang dồng bộ với mạng @@ -1928,9 +1955,9 @@ dao.factsAndFigures.menuItem.transactions=Giao dịch BSQ dao.factsAndFigures.dashboard.avgPrice90=90 days average BSQ/BTC trade price dao.factsAndFigures.dashboard.avgPrice30=30 days average BSQ/BTC trade price -dao.factsAndFigures.dashboard.avgUSDPrice90=90 days volume weighted average USD/BSQ trade price -dao.factsAndFigures.dashboard.avgUSDPrice30=30 days volume weighted average USD/BSQ trade price -dao.factsAndFigures.dashboard.marketCap=Vốn hóa thị trường (dựa trên giá giao dịch) +dao.factsAndFigures.dashboard.avgUSDPrice90=90 days volume weighted average USD/BSQ price +dao.factsAndFigures.dashboard.avgUSDPrice30=30 days volume weighted average USD/BSQ price +dao.factsAndFigures.dashboard.marketCap=Market capitalisation (based on 30 days average USD/BSQ price) dao.factsAndFigures.dashboard.availableAmount=Tổng lượng BSQ hiện có dao.factsAndFigures.supply.issuedVsBurnt=BSQ issued v. BSQ burnt @@ -2000,7 +2027,7 @@ disputeSummaryWindow.openDate=Ngày mở đơn disputeSummaryWindow.role=Vai trò của người giao dịch disputeSummaryWindow.payout=Khoản tiền giao dịch hoàn lại disputeSummaryWindow.payout.getsTradeAmount=BTC {0} nhận được khoản tiền giao dịch hoàn lại -disputeSummaryWindow.payout.getsAll=BTC {0} nhận tất cả +disputeSummaryWindow.payout.getsAll=Max. payout to BTC {0} disputeSummaryWindow.payout.custom=Thuế hoàn lại disputeSummaryWindow.payoutAmount.buyer=Khoản tiền hoàn lại của người mua disputeSummaryWindow.payoutAmount.seller=Khoản tiền hoàn lại của người bán @@ -2154,6 +2181,7 @@ tradeDetailsWindow.tradingPeersOnion=Địa chỉ onion Đối tác giao dịch tradeDetailsWindow.tradingPeersPubKeyHash=Trading peers pubkey hash tradeDetailsWindow.tradeState=Trạng thái giao dịch tradeDetailsWindow.agentAddresses=Arbitrator/Mediator +tradeDetailsWindow.detailData=Detail data walletPasswordWindow.headline=Nhập mật khẩu để mở khóa @@ -2183,6 +2211,8 @@ feeOptionWindow.info=Bạn có thể chọn thanh toán phí giao dịch bằng feeOptionWindow.optionsLabel=Chọn đồng tiền để thanh toán phí giao dịch feeOptionWindow.useBTC=Sử dụng BTC feeOptionWindow.fee={0} (≈ {1}) +feeOptionWindow.btcFeeWithFiatAndPercentage={0} (≈ {1} / {2}) +feeOptionWindow.btcFeeWithPercentage={0} ({1}) #################################################################### @@ -2226,6 +2256,7 @@ popup.warning.noMediatorsAvailable=There are no mediators available. popup.warning.notFullyConnected=Bạn cần phải đợi cho đến khi kết nối hoàn toàn với mạng.\nĐiều này mất khoảng 2 phút khi khởi động. popup.warning.notSufficientConnectionsToBtcNetwork=Bạn cần phải đợi cho đến khi bạn có ít nhất {0} kết nối với mạng Bitcoin. popup.warning.downloadNotComplete=Bạn cần phải đợi cho đến khi download xong các block Bitcoin còn thiếu. +popup.warning.chainNotSynced=The Bisq wallet blockchain height is not synced correctly. If you recently started the application, please wait until one Bitcoin block has been published.\n\nYou can check the blockchain height in Settings/Network Info. If more than one block passes and this problem persists it may be stalled, in which case you should do an SPV resync. [HYPERLINK:https://bisq.wiki/Resyncing_SPV_file] popup.warning.removeOffer=Bạn có chắc bạn muốn gỡ bỏ Báo giá này?\nPhí người khởi tạo {0} sẽ bị mất nếu bạn gỡ bỏ Báo giá. popup.warning.tooLargePercentageValue=Bạn không thể cài đặt phần trăm là 100% hoặc cao hơn. popup.warning.examplePercentageValue=Vui lòng nhập số phần trăm như \"5.4\" cho 5,4% @@ -2248,13 +2279,13 @@ popup.warning.seed=seed popup.warning.mandatoryUpdate.trading=Please update to the latest Bisq version. A mandatory update was released which disables trading for old versions. Please check out the Bisq Forum for more information. popup.warning.mandatoryUpdate.dao=Please update to the latest Bisq version. A mandatory update was released which disables the Bisq DAO and BSQ for old versions. Please check out the Bisq Forum for more information. popup.warning.disable.dao=The Bisq DAO and BSQ are temporary disabled. Please check out the Bisq Forum for more information. -popup.warning.burnBTC=Không thể thực hiện giao dịch, vì phí đào {0} vượt quá số lượng {1} cần chuyển. Vui lòng chờ tới khi phí đào thấp xuống hoặc khi bạn tích lũy đủ BTC để chuyển. +popup.warning.burnBTC=Không thể thực hiện giao dịch, vì phí đào {0} vượt quá số lượng {1} cần chuyển. Vui lòng chờ tới khi phí đào thấp xuống hoặc khi bạn tích lũy đủ BTC để chuyển. popup.warning.openOffer.makerFeeTxRejected=The maker fee transaction for offer with ID {0} was rejected by the Bitcoin network.\nTransaction ID={1}.\nThe offer has been removed to avoid further problems.\nPlease go to \"Settings/Network info\" and do a SPV resync.\nFor further help please contact the Bisq support channel at the Bisq Keybase team. popup.warning.trade.txRejected.tradeFee=trade fee popup.warning.trade.txRejected.deposit=deposit -popup.warning.trade.txRejected=The {0} transaction for trade with ID {1} was rejected by the Bitcoin network.\nTransaction ID={2}}\nThe trade has been moved to failed trades.\nPlease go to \"Settings/Network info\" and do a SPV resync.\nFor further help please contact the Bisq support channel at the Bisq Keybase team. +popup.warning.trade.txRejected=The {0} transaction for trade with ID {1} was rejected by the Bitcoin network.\nTransaction ID={2}\nThe trade has been moved to failed trades.\nPlease go to \"Settings/Network info\" and do a SPV resync.\nFor further help please contact the Bisq support channel at the Bisq Keybase team. popup.warning.openOfferWithInvalidMakerFeeTx=The maker fee transaction for offer with ID {0} is invalid.\nTransaction ID={1}.\nPlease go to \"Settings/Network info\" and do a SPV resync.\nFor further help please contact the Bisq support channel at the Bisq Keybase team. @@ -2264,14 +2295,15 @@ popup.info.cashDepositInfo=Chắc chắn rằng khu vực của bạn có chi nh popup.info.cashDepositInfo.confirm=Tôi xác nhận tôi đã gửi tiền popup.info.shutDownWithOpenOffers=Bisq đang đóng, nhưng vẫn có các chào giá đang mở. \n\nNhững chào giá này sẽ không có tại mạng P2P khi Bisq đang đóng, nhưng chúng sẽ được công bố lại trên mạng P2P vào lần tiếp theo bạn khởi động Bisq.\nĐể giữ các chào giá luôn trực tuyến, vui lòng để Bisq chạy và đảm bảo là máy tính của bạn cũng đang trực tuyến(có nghĩa là đảm bảo là máy tính của bạn không chuyển về chế độ chờ...nếu màn hình về chế độ chờ thì không sao). popup.info.qubesOSSetupInfo=It appears you are running Bisq on Qubes OS. \n\nPlease make sure your Bisq qube is setup according to our Setup Guide at [HYPERLINK:https://bisq.wiki/Running_Bisq_on_Qubes]. +popup.warn.downGradePrevention=Downgrade from version {0} to version {1} is not supported. Please use the latest Bisq version. +popup.warn.daoRequiresRestart=There was a problem with synchronizing the DAO state. You have to restart the application to fix the issue. popup.privateNotification.headline=Thông báo riêng tư quan trọng! popup.securityRecommendation.headline=Khuyến cáo an ninh quan trọng popup.securityRecommendation.msg=Chúng tôi muốn nhắc nhở bạn sử dụng bảo vệ bằng mật khẩu cho ví của bạn nếu bạn vẫn chưa sử dụng.\n\nChúng tôi cũng khuyên bạn nên viết Seed words ví của bạn ra giấy. Các Seed words này như là mật khẩu chủ để khôi phục ví Bitcoin của bạn.\nBạn có thể xem thông tin ở mục \"Wallet Seed\".\n\nNgoài ra bạn nên sao lưu dự phòng folder dữ liệu ứng dụng đầy đủ ở mục \"Backup\". -popup.bitcoinLocalhostNode.msg=Bisq phát hiện Node Bitcoin Core đang chạy (ở máy chủ cục bộ).\nHãy chắc chắn rằng Node này đã được đồng bộ hóa hoàn toàn trước khi bạn khởi động Bisq và không chạy trong chế độ pruning. -popup.bitcoinLocalhostNode.additionalRequirements=\n\nFor a well configured node, the requirements are for the node to have pruning disabled and bloom filters enabled. +popup.bitcoinLocalhostNode.msg=Bisq detected a Bitcoin Core node running on this machine (at localhost).\n\nPlease ensure:\n- the node is fully synced before starting Bisq\n- pruning is disabled ('prune=0' in bitcoin.conf)\n- bloom filters are enabled ('peerbloomfilters=1' in bitcoin.conf) popup.shutDownInProgress.headline=Đang tắt ứng dụng popup.shutDownInProgress.msg=Tắt ứng dụng sẽ mất vài giây.\nVui lòng không gián đoạn quá trình này. @@ -2303,15 +2335,12 @@ popup.accountSigning.signedByPeer=One of your payment accounts has been verified popup.accountSigning.peerLimitLifted=The initial limit for one of your accounts has been lifted.\n\n{0} popup.accountSigning.peerSigner=One of your accounts is mature enough to sign other payment accounts and the initial limit for one of your accounts has been lifted.\n\n{0} -popup.accountSigning.singleAccountSelect.headline=Select account age witness -popup.accountSigning.singleAccountSelect.description=Search for account age witness. -popup.accountSigning.singleAccountSelect.datePicker=Select point of time for signing +popup.accountSigning.singleAccountSelect.headline=Import unsigned account age witness popup.accountSigning.confirmSingleAccount.headline=Confirm selected account age witness popup.accountSigning.confirmSingleAccount.selectedHash=Selected witness hash popup.accountSigning.confirmSingleAccount.button=Sign account age witness popup.accountSigning.successSingleAccount.description=Witness {0} was signed popup.accountSigning.successSingleAccount.success.headline=Success -popup.accountSigning.successSingleAccount.signError=Failed to sign witness, {0} popup.accountSigning.unsignedPubKeys.headline=Unsigned Pubkeys popup.accountSigning.unsignedPubKeys.sign=Sign Pubkeys @@ -2447,8 +2476,8 @@ navigation.dao.wallet.receive=\"DAO/Ví BSQ/Nhận\" formatter.formatVolumeLabel={0} giá trị {1} formatter.makerTaker=Người tạo là {0} {1} / Người nhận là {2} {3} -formatter.youAreAsMaker=Bạn là {0} {1} như người tạo / Người nhận là {2} {3} -formatter.youAreAsTaker=Bạn là {0} {1} như người nhận / Người tạo là {2} {3} +formatter.youAreAsMaker=You are: {1} {0} (maker) / Taker is: {3} {2} +formatter.youAreAsTaker=You are: {1} {0} (taker) / Maker is: {3} {2} formatter.youAre=Bạn là {0} {1} ({2} {3}) formatter.youAreCreatingAnOffer.fiat=Bạn đang tạo một chào giá đến {0} {1} formatter.youAreCreatingAnOffer.altcoin=Bạn đang tạo một chào giá đến {0} {1} ({2} {3}) @@ -2561,6 +2590,7 @@ payment.venmo.venmoUserName=Tên người dùng Venmo payment.popmoney.accountId=Email hoặc số điện thoại payment.promptPay.promptPayId=ID công dân/ ID thuế hoặc số điện thoại payment.supportedCurrencies=Tiền tệ hỗ trợ +payment.supportedCurrenciesForReceiver=Currencies for receiving funds payment.limitations=Hạn chế payment.salt=Salt để xác minh tuổi tài khoản payment.error.noHexSalt=The salt needs to be in HEX format.\nIt is only recommended to edit the salt field if you want to transfer the salt from an old account to keep your account age. The account age is verified by using the account salt and the identifying account data (e.g. IBAN). @@ -2635,7 +2665,8 @@ payment.japan.recipient=Tên payment.australia.payid=PayID payment.payid=PayID linked to financial institution. Like email address or mobile phone. payment.payid.info=A PayID like a phone number, email address or an Australian Business Number (ABN), that you can securely link to your bank, credit union or building society account. You need to have already created a PayID with your Australian financial institution. Both sending and receiving financial institutions must support PayID. For more information please check [HYPERLINK:https://payid.com.au/faqs/] -payment.amazonGiftCard.info=To pay with Amazon eGift Card you need to purchase an Amazon eGift Card at your Amazon account and use the BTC seller''s email or mobile nr. as receiver. Amazon sends then an email or text message to the receiver. Use the trade ID for the message field.\n\nAmazon eGift Cards can only be redeemed by Amazon accounts with the same currency.\n\nFor more information visit the Amazon eGift Card webpage. [HYPERLINK:https://www.amazon.com/Amazon-1_US_Email-eGift-Card/dp/B004LLIKVU] +payment.amazonGiftCard.info=To pay with Amazon eGift Card, you will need to send an Amazon eGift Card to the BTC seller via your Amazon account. \n\nBisq will show the BTC seller''s email address or phone number where the gift card should be sent, and you must include the trade ID in the gift card''s message field. Please see the wiki [HYPERLINK:https://bisq.wiki/Amazon_eGift_card] for further details and best practices. \n\nThree important notes:\n- try to send gift cards with amounts of 100 USD or smaller, as Amazon is known to flag larger gift cards as fraudulent\n- try to use creative, believable text for the gift card''s message (e.g., "Happy birthday Susan!") along with the trade ID (and use trader chat to tell your trading peer the reference text you picked so they can verify your payment)\n- Amazon eGift Cards can only be redeemed on the Amazon website they were purchased on (e.g., a gift card purchased on amazon.it can only be redeemed on amazon.it) + # We use constants from the code so we do not use our normal naming convention # dynamic values are not recognized by IntelliJ diff --git a/core/src/main/resources/i18n/displayStrings_zh-hans.properties b/core/src/main/resources/i18n/displayStrings_zh-hans.properties index 59aca890d8..f85d885d8e 100644 --- a/core/src/main/resources/i18n/displayStrings_zh-hans.properties +++ b/core/src/main/resources/i18n/displayStrings_zh-hans.properties @@ -71,6 +71,7 @@ shared.amountWithCur={0} 数量 shared.volumeWithCur={0} 总量 shared.currency=货币类型 shared.market=交易项目 +shared.deviation=偏差 shared.paymentMethod=付款方式 shared.tradeCurrency=交易货币 shared.offerType=报价类型 @@ -104,7 +105,6 @@ shared.selectTradingAccount=选择交易账户 shared.fundFromSavingsWalletButton=从 Bisq 钱包资金划转 shared.fundFromExternalWalletButton=从您的外部钱包充值 shared.openDefaultWalletFailed=打开默认的比特币钱包应用程序失败了。您确定您安装了吗? -shared.distanceInPercent=与市场价格的差价 % shared.belowInPercent=低于市场价格 % shared.aboveInPercent=高于市场价格 % shared.enterPercentageValue=输入 % 值 @@ -123,7 +123,7 @@ shared.noDateAvailable=没有可用数据 shared.noDetailsAvailable=没有可用详细 shared.notUsedYet=尚未使用 shared.date=日期 -shared.sendFundsDetailsWithFee=Sending: {0}\nFrom address: {1}\nTo receiving address: {2}.\nRequired mining fee is: {3} ({4} satoshis/vbyte)\nTransaction vsize: {5} vKb\n\nThe recipient will receive: {6}\n\nAre you sure you want to withdraw this amount? +shared.sendFundsDetailsWithFee=发送:{0}\n来自:{1}\n接收地址:{2}\n要求的最低交易费:{3}({4} 聪/byte)\n交易大小:{5} Kb\n\n收款方将收到:{6}\n\n您确定您想要提现吗? # suppress inspection "TrailingSpacesInProperty" shared.sendFundsDetailsDust=Bisq 检测到,该交易将产生一个低于最低零头阈值的输出(不被比特币共识规则所允许)。相反,这些零头({0}satoshi{1})将被添加到挖矿手续费中。 shared.copyToClipboard=复制到剪贴板 @@ -191,7 +191,7 @@ shared.tradeWalletBalance=交易钱包余额 shared.makerTxFee=卖家:{0} shared.takerTxFee=买家:{0} shared.iConfirm=我确认 -shared.tradingFeeInBsqInfo=相当于使用 {0} 交易手续费 +shared.tradingFeeInBsqInfo=≈ {0} shared.openURL=打开 {0} shared.fiat=法定货币 shared.crypto=加密 @@ -218,6 +218,9 @@ shared.refundAgentForSupportStaff=退款助理 shared.delayedPayoutTxId=延迟支付交易 ID shared.delayedPayoutTxReceiverAddress=延迟交易交易已发送至 shared.unconfirmedTransactionsLimitReached=你现在有过多的未确认交易。请稍后尝试 +shared.numItemsLabel=实体数:{0} +shared.filter=过滤 +shared.enabled=启用 #################################################################### @@ -248,14 +251,14 @@ mainView.balance.locked=冻结余额 mainView.balance.reserved.short=保证 mainView.balance.locked.short=冻结 -mainView.footer.usingTor=(使用 Tor 中) +mainView.footer.usingTor=(通过 Tor) mainView.footer.localhostBitcoinNode=(本地主机) -mainView.footer.btcInfo={0} {1} {2} -mainView.footer.btcFeeRate=/ 当前矿工手续费费率:{0} sat/vB +mainView.footer.btcInfo={0} {1} +mainView.footer.btcFeeRate=/ 矿工手费率:{0} 聪/字节 mainView.footer.btcInfo.initializing=连接至比特币网络 mainView.footer.bsqInfo.synchronizing=正在同步 DAO -mainView.footer.btcInfo.synchronizingWith=正在同步至 -mainView.footer.btcInfo.synchronizedWith=已同步至 +mainView.footer.btcInfo.synchronizingWith=正在通过{0}同步区块:{1}/{2} +mainView.footer.btcInfo.synchronizedWith=已通过{0}同步至区块{1} mainView.footer.btcInfo.connectingTo=连接至 mainView.footer.btcInfo.connectionFailed=连接失败: mainView.footer.p2pInfo=比特币网络节点:{0} / Bisq 网络节点:{1} @@ -336,10 +339,10 @@ offerbook.offerersAcceptedBankSeats=接受的银行所在国家(买家):\n offerbook.availableOffers=可用报价 offerbook.filterByCurrency=以货币筛选 offerbook.filterByPaymentMethod=以支付方式筛选 -offerbook.timeSinceSigning=已验证,从 +offerbook.timeSinceSigning=账户信息 offerbook.timeSinceSigning.info=此账户已验证,{0} offerbook.timeSinceSigning.info.arbitrator=由仲裁员验证,并可以验证伙伴账户 -offerbook.timeSinceSigning.info.peer=由对方验证,等待限制被解除 +offerbook.timeSinceSigning.info.peer=由对方验证,等待%d天限制被解除 offerbook.timeSinceSigning.info.peerLimitLifted=由对方验证,限制被取消 offerbook.timeSinceSigning.info.signer=由对方验证,并可验证对方账户(限制已取消) offerbook.timeSinceSigning.info.banned=账户已被封禁 @@ -349,19 +352,22 @@ offerbook.xmrAutoConf=是否开启自动确认 offerbook.timeSinceSigning.help=当您成功地完成与拥有已验证付款帐户的伙伴交易时,您的付款帐户已验证。\n{0} 天后,最初的 {1} 的限制解除以及你的账户可以验证其他人的付款账户。 offerbook.timeSinceSigning.notSigned=尚未验证 +offerbook.timeSinceSigning.notSigned.ageDays={0} 天 offerbook.timeSinceSigning.notSigned.noNeed=N/A -shared.notSigned=此账户还没有被验证 +shared.notSigned=此账户还没有被验证以及在{0}前创建 shared.notSigned.noNeed=此账户类型不适用验证 +shared.notSigned.noNeedDays=此账户类型不适用验证且在{0}天创建 +shared.notSigned.noNeedAlts=数字货币不适用账龄与签名 offerbook.nrOffers=报价数量:{0} offerbook.volume={0}(最小 - 最大) offerbook.deposit=BTC 保证金(%) offerbook.deposit.help=交易双方均已支付保证金确保这个交易正常进行。这会在交易完成时退还。 -offerbook.createOfferToBuy=创建新的报价来买入 {0} -offerbook.createOfferToSell=创建新的报价来卖出 {0} +offerbook.createOfferToBuy=创建新的报价来买入 {0} +offerbook.createOfferToSell=创建新的报价来卖出 {0} offerbook.createOfferToBuy.withFiat=创建新的报价用 {1} 购买 {0} -offerbook.createOfferToSell.forFiat=创建新的报价以 {1} 出售 {0} +offerbook.createOfferToSell.forFiat=创建新的报价以 {1} 出售 {0} offerbook.createOfferToBuy.withCrypto=创建新的卖出报价 {0} (买入 {1}) offerbook.createOfferToSell.forCrypto=创建新的买入报价 {0}(卖出 {1}) @@ -435,11 +441,15 @@ createOffer.warning.sellBelowMarketPrice=由于您的价格是持续更新的, createOffer.warning.buyAboveMarketPrice=由于您的价格是持续更新的,因此您将始终支付高于市场价 {0}% 的价格。 createOffer.tradeFee.descriptionBTCOnly=挂单费 createOffer.tradeFee.descriptionBSQEnabled=选择手续费币种 -createOffer.tradeFee.fiatAndPercent=≈ {0} / {1} 交易数量 + +createOffer.triggerPrice.prompt=Set optional trigger price +createOffer.triggerPrice.label=Deactivate offer if market price is {0} +createOffer.triggerPrice.tooltip=As protecting against drastic price movements you can set a trigger price which deactivates the offer if the market price reaches that value. +createOffer.triggerPrice.invalid.tooLow=Value must be higher than {0} +createOffer.triggerPrice.invalid.tooHigh=Value must be lower than {0} # new entries createOffer.placeOfferButton=复审:报价挂单 {0} 比特币 -createOffer.alreadyFunded=您已经为该报价充值了。\n您的资金已经划转到您的本地 Bisq 钱包并在“资金/提现”界面可以提现。 createOffer.createOfferFundWalletInfo.headline=为您的报价充值 # suppress inspection "TrailingSpacesInProperty" createOffer.createOfferFundWalletInfo.tradeAmount=- 交易数量:{0}\n @@ -496,7 +506,6 @@ takeOffer.error.message=下单时发生了一个错误。\n\n{0} # new entries takeOffer.takeOfferButton=复审:报价下单 {0} 比特币 takeOffer.noPriceFeedAvailable=您不能对这笔报价下单,因为它使用交易所价格百分比定价,但是您没有获得可用的价格。 -takeOffer.alreadyFunded.movedFunds=您已经为该报价值了。\n您的资金已经划转到您的本地 Bisq 钱包,并可以在“资金/提现”界面提现。 takeOffer.takeOfferFundWalletInfo.headline=为交易充值 # suppress inspection "TrailingSpacesInProperty" takeOffer.takeOfferFundWalletInfo.tradeAmount=- 交易数量:{0}\n @@ -524,6 +533,10 @@ takeOffer.tac=接受该报价,意味着我同意这交易界面中的条件。 # Offerbook / Edit offer #################################################################### +openOffer.header.triggerPrice=触发价格 +openOffer.triggerPrice=Trigger price {0} +openOffer.triggered=The offer has been deactivated because the market price reached your trigger price.\nPlease edit the offer to define a new trigger price + editOffer.setPrice=设定价格 editOffer.confirmEdit=确认:编辑报价 editOffer.publishOffer=发布您的报价。 @@ -541,7 +554,9 @@ portfolio.tab.history=历史记录 portfolio.tab.failed=失败 portfolio.tab.editOpenOffer=编辑报价 -portfolio.pending.invalidDelayedPayoutTx=这里有一个缺失或不可用交易导致的问题\n\n请不要发送法币或者任何数字货币。联系 Bisq 开发者在 Keybase 上 https://keybase.io/team/bisq 或者在论坛上https://bisq.community 以寻求更多协助。\n\n错误信息:{0} +portfolio.closedTrades.deviation.help=与市场价格偏差百分比 + +portfolio.pending.invalidDelayedPayoutTx=这里有一个缺失或不可用交易导致的问题\n\n请不要发送法币或者任何数字货币。联系 Bisq 开发者在 Keybase 上 https://keybase.io/team/bisq 或者在论坛上https://bisq.community 以寻求更多协助。\n\n错误信息:{0} portfolio.pending.step1.waitForConf=等待区块链确认 portfolio.pending.step2_buyer.startPayment=开始付款 @@ -607,7 +622,7 @@ portfolio.pending.step2_buyer.moneyGram.extra=重要要求:\n完成支付后 portfolio.pending.step2_buyer.westernUnion=请使用 Western Union 向 BTC 卖家支付 {0}。\n\n portfolio.pending.step2_buyer.westernUnion.extra=重要要求:\n完成支付后,请通过电邮发送 MTCN(追踪号码)和照片给 BTC 卖家。\n收据必须清楚地向卖家写明您的全名、城市、国家或地区、数量。卖方的电子邮件是:{0}。 # suppress inspection "TrailingSpacesInProperty" -portfolio.pending.step2_buyer.amazonGiftCard=Please purchase an Amazon eGift Card for {0} at your Amazon account and use the BTC seller''s email or mobile number as receiver. In case the trade amount exceeds the permitted amount send multiple cards.\n\n +portfolio.pending.step2_buyer.amazonGiftCard=请使用您的账户购买{0}亚马逊电子礼品卡并使用 BTC 卖家的邮箱或手机号作为接收方。如果交易额超过允许的数量请发送多个礼品卡。\n\n # suppress inspection "TrailingSpacesInProperty" portfolio.pending.step2_buyer.postal=请用“美国邮政汇票”发送 {0} 给 BTC 卖家。\n\n @@ -629,7 +644,7 @@ portfolio.pending.step2_buyer.moneyGramMTCNInfo.headline=发送授权编号和 portfolio.pending.step2_buyer.moneyGramMTCNInfo.msg=请通过电邮发送授权编号和照片给 BTC 卖家。\n收据必须清楚地向卖家写明您的全名、城市、国家或地区、数量。卖方的电子邮件是:{0}。\n\n您把授权编号和合同发给卖方了吗? portfolio.pending.step2_buyer.westernUnionMTCNInfo.headline=发送 MTCN 和收据 portfolio.pending.step2_buyer.westernUnionMTCNInfo.msg=请通过电邮发送 MTCN(追踪号码)和照片给 BTC 卖家。\n收据必须清楚地向卖家写明您的全名、城市、国家或地区、数量。卖方的电子邮件是:{0}。\n\n您把 MTCN 和合同发给卖方了吗? -portfolio.pending.step2_buyer.halCashInfo.headline=请发送 HalCash 代码 +portfolio.pending.step2_buyer.halCashInfo.headline=请发送 HalCash 代码 portfolio.pending.step2_buyer.halCashInfo.msg=您需要向 BTC 卖家发送带有 HalCash 代码和交易 ID({0})的文本消息。\n\n卖方的手机号码是 {1} 。\n\n您是否已经将代码发送至卖家? portfolio.pending.step2_buyer.fasterPaymentsHolderNameInfo=有些银行可能会要求接收方的姓名。在较旧的 Bisq 客户端创建的快速支付帐户没有提供收款人的姓名,所以请使用交易聊天来获得收款人姓名(如果需要)。 portfolio.pending.step2_buyer.confirmStart.headline=确定您已经付款 @@ -680,7 +695,7 @@ portfolio.pending.step3_seller.cash=因为付款是通过现金存款完成的 portfolio.pending.step3_seller.moneyGram=买方必须发送授权编码和一张收据的照片。\n收据必须清楚地显示您的全名、城市、国家或地区、数量。如果您收到授权编码,请查收邮件。\n\n关闭弹窗后,您将看到 BTC 买家的姓名和在 MoneyGram 的收款地址。\n\n只有在您成功收到钱之后,再确认收据! portfolio.pending.step3_seller.westernUnion=买方必须发送 MTCN(跟踪号码)和一张收据的照片。\n收据必须清楚地显示您的全名、城市、国家或地区、数量。如果您收到 MTCN,请查收邮件。\n\n关闭弹窗后,您将看到 BTC 买家的姓名和在 Western Union 的收款地址。\n\n只有在您成功收到钱之后,再确认收据! portfolio.pending.step3_seller.halCash=买方必须将 HalCash代码 用短信发送给您。除此之外,您将收到来自 HalCash 的消息,其中包含从支持 HalCash 的 ATM 中提取欧元所需的信息\n从 ATM 取款后,请在此确认付款收据! -portfolio.pending.step3_seller.amazonGiftCard=The buyer has sent you an Amazon eGift Card by email or by text message to your mobile phone. Please redeem now the Amazon eGift Card at your Amazon account and once accepted confirm the payment receipt. +portfolio.pending.step3_seller.amazonGiftCard=BTC 买家已经发送了一张亚马逊电子礼品卡到您的邮箱或手机短信。请现在立即兑换亚马逊电子礼品卡到您的亚马逊账户中以及确认交易信息。 portfolio.pending.step3_seller.bankCheck=\n\n还请确认您的银行对帐单中的发件人姓名与委托合同中的发件人姓名相符:\n发件人姓名:{0}\n\n如果名称与此处显示的名称不同,则 {1} # suppress inspection "TrailingSpacesInProperty" @@ -886,13 +901,12 @@ funds.tx.noTxAvailable=没有可用交易 funds.tx.revert=还原 funds.tx.txSent=交易成功发送到本地 Bisq 钱包中的新地址。 funds.tx.direction.self=内部钱包交易 -funds.tx.daoTxFee=DAO tx 的矿工手续费支付 +funds.tx.daoTxFee=BSQ tx 的矿工手续费支付 funds.tx.reimbursementRequestTxFee=退还申请 funds.tx.compensationRequestTxFee=报偿申请 funds.tx.dustAttackTx=接受零头 funds.tx.dustAttackTx.popup=这笔交易是发送一个非常小的比特币金额到您的钱包,可能是区块链分析公司尝试监控您的交易。\n\n如果您在交易中使用该交易输出,他们将了解到您很可能也是其他地址的所有者(资金归集)。\n\n为了保护您的隐私,Bisq 钱包忽略了这种零头的消费和余额显示。可以在设置中将输出视为零头时设置阈值量。 - #################################################################### # Support #################################################################### @@ -943,6 +957,7 @@ support.error=收件人无法处理消息。错误:{0} support.buyerAddress=BTC 买家地址 support.sellerAddress=BTC 卖家地址 support.role=角色 +support.agent=Support agent support.state=状态 support.closed=关闭 support.open=打开 @@ -978,7 +993,7 @@ setting.preferences.general=通用偏好 setting.preferences.explorer=比特币区块浏览器 setting.preferences.explorer.bsq=Bisq 区块浏览器 setting.preferences.deviation=与市场价格最大差价 -setting.preferences.bsqAverageTrimThreshold=Outlier threshold for BSQ rate +setting.preferences.bsqAverageTrimThreshold=BSQ 率已超过阈值 setting.preferences.avoidStandbyMode=避免待机模式 setting.preferences.autoConfirmXMR=XMR 自动确认 setting.preferences.autoConfirmEnabled=启用 @@ -986,10 +1001,10 @@ setting.preferences.autoConfirmRequiredConfirmations=已要求确认 setting.preferences.autoConfirmMaxTradeSize=最大交易量(BTC) setting.preferences.autoConfirmServiceAddresses=Monero Explorer 链接(使用Tor,但本地主机,LAN IP地址和 *.local 主机名除外) setting.preferences.deviationToLarge=值不允许大于30% -setting.preferences.txFee=Withdrawal transaction fee (satoshis/vbyte) +setting.preferences.txFee=提现交易手续费(聪/字节) setting.preferences.useCustomValue=使用自定义值 -setting.preferences.txFeeMin=Transaction fee must be at least {0} satoshis/vbyte -setting.preferences.txFeeTooLarge=Your input is above any reasonable value (>5000 satoshis/vbyte). Transaction fee is usually in the range of 50-400 satoshis/vbyte. +setting.preferences.txFeeMin=交易手续费必须至少为{0} 聪/字节 +setting.preferences.txFeeTooLarge=您输入的数额超过可接受值(>5000 聪/字节)。交易手续费一般在 50-400 聪/字节、 setting.preferences.ignorePeers=忽略节点 [洋葱地址:端口] setting.preferences.ignoreDustThreshold=最小无零头输出值 setting.preferences.currenciesInList=市场价的货币列表 @@ -1052,6 +1067,7 @@ settings.net.creationDateColumn=已建立连接 settings.net.connectionTypeColumn=入/出 settings.net.sentDataLabel=统计数据已发送 settings.net.receivedDataLabel=统计数据已接收 +settings.net.chainHeightLabel=最新 BTC 区块高度 settings.net.roundTripTimeColumn=延迟 settings.net.sentBytesColumn=发送 settings.net.receivedBytesColumn=接收 @@ -1066,6 +1082,7 @@ settings.net.needRestart=您需要重启应用程序以同意这次变更。\n settings.net.notKnownYet=至今未知... settings.net.sentData=已发送数据 {0},{1} 条消息,{2} 条消息/秒 settings.net.receivedData=已接收数据 {0},{1} 条消息,{2} 条消息/秒 +settings.net.chainHeight=Bisq :{0}|节点:{1} settings.net.ips=添加逗号分隔的 IP 地址及端口,如使用8333端口可不填写。 settings.net.seedNode=种子节点 settings.net.directPeer=节点(直连) @@ -1074,7 +1091,7 @@ settings.net.inbound=接收数据包 settings.net.outbound=发送数据包 settings.net.reSyncSPVChainLabel=重新同步 SPV 链 settings.net.reSyncSPVChainButton=删除 SPV 链文件并重新同步 -settings.net.reSyncSPVSuccess=SPV 链文件将在下一次启动时被删除。您现在需要重新启动应用程序。\n\n重新启动后,可能需要一段时间才能与网络重新同步,只有重新同步完成后才会看到所有的交易。\n\n根据交易的数量和钱包账龄,重新同步可能会花费几个小时,并消耗100%的 CPU。不要打断这个过程,否则你会不断地重复它。 +settings.net.reSyncSPVSuccess=您确定要进行 SPV 重新同步?如果您继续,SPV 链文件将会在下一次启动前删除。\n\n重新启动后,可能需要一段时间才能与网络重新同步,只有重新同步完成后才会看到所有的交易。\n\n根据交易的数量和钱包账龄,重新同步可能会花费几个小时,并消耗100%的 CPU。不要打断这个过程,否则你会不断地重复它。 settings.net.reSyncSPVAfterRestart=SPV 链文件已被删除。请耐心等待,与网络重新同步可能需要一段时间。 settings.net.reSyncSPVAfterRestartCompleted=重新同步刚刚完成,请重启应用程序。 settings.net.reSyncSPVFailed=无法删除 SPV 链文件。\n错误:{0} @@ -1161,9 +1178,19 @@ account.menu.paymentAccount=法定货币账户 account.menu.altCoinsAccountView=数字货币账户 account.menu.password=钱包密码 account.menu.seedWords=钱包密钥 +account.menu.walletInfo=钱包信息 account.menu.backup=备份 account.menu.notifications=通知 +account.menu.walletInfo.balance.headLine=钱包余额 +account.menu.walletInfo.balance.info=这里包括内部钱包余额包括未确认交易。\n对于 BTC,下方显示的内部钱包的余额将会是窗口右上方的“可用”与“保留”余额的总和。 +account.menu.walletInfo.xpub.headLine=监控密钥(xpub keys) +account.menu.walletInfo.walletSelector={0} {1} 钱包 +account.menu.walletInfo.path.headLine=HD 密钥链路径 +account.menu.walletInfo.path.info=如果您导入其他钱包(例如 Electrum)的种子词,你需要去确认路径。这个操作只能用于你失去 Bisq 钱包和数据目录的控制的紧急情况。\n请记住使用非 Bisq 钱包的资金可能会打乱 Bisq 内部与之相连的钱包数据结构,这可能导致交易失败。\n\n请不要将 BSQ 发送至非 Bisq 钱包,因为这可能让您的 BSQ 交易记录失效以及损失 BSQ. + +account.menu.walletInfo.openDetails=显示原始钱包详情与私钥 + ## TODO should we rename the following to a gereric name? account.arbitratorRegistration.pubKey=公钥 @@ -1498,9 +1525,9 @@ dao.bond.reputation.salt=盐 dao.bond.reputation.hash=哈希 dao.bond.reputation.lockupButton=锁定 dao.bond.reputation.lockup.headline=确认锁定交易 -dao.bond.reputation.lockup.details=Lockup amount: {0}\nUnlock time: {1} block(s) (≈{2})\n\nMining fee: {3} ({4} Satoshis/vbyte)\nTransaction vsize: {5} Kb\n\nAre you sure you want to proceed? +dao.bond.reputation.lockup.details=锁定数量:{0}\n解锁时间:{1} 区块(≈{2})\n\n矿工手续费:{3}({4} 聪/字节)\n交易大小:{5} 字节\n\n你确定想要继续? dao.bond.reputation.unlock.headline=确认解锁交易 -dao.bond.reputation.unlock.details=Unlock amount: {0}\nUnlock time: {1} block(s) (≈{2})\n\nMining fee: {3} ({4} Satoshis/vbyte)\nTransaction vsize: {5} Kb\n\nAre you sure you want to proceed? +dao.bond.reputation.unlock.details=解锁金额:{0}\n解锁时间:{1} 区块(≈{2})\n\n挖矿手续费:{3}({4} 聪/Byte)\n交易大小:{5} Kb\n\n你想继续这个操作吗? dao.bond.allBonds.header=所有担保 @@ -1796,7 +1823,7 @@ dao.wallet.send.setDestinationAddress=输入您的目标地址 dao.wallet.send.send=发送 BSQ 资金 dao.wallet.send.sendBtc=发送 BTC 资金 dao.wallet.send.sendFunds.headline=确定提现申请 -dao.wallet.send.sendFunds.details=Sending: {0}\nTo receiving address: {1}.\nRequired transaction fee is: {2} ({3} satoshis/vbyte)\nTransaction vsize: {4} vKb\n\nThe recipient will receive: {5}\n\nAre you sure you want to withdraw that amount? +dao.wallet.send.sendFunds.details=发送:{0}\n来自:{1}\n要求的矿工手续费:{2}({3}比特/节)\n交易大小:{4}字节\n\n接收方会收到:{5}\n\n您确定您想要提现这些数量吗? dao.wallet.chainHeightSynced=最新确认区块:{0} dao.wallet.chainHeightSyncing=等待区块... 已确认{0}/{1}区块 dao.wallet.tx.type=类型 @@ -1854,9 +1881,9 @@ dao.proposal.create.missingMinerFeeFunds=您没有足够的BTC资金来支付该 dao.proposal.create.missingIssuanceFunds=您没有足够的BTC资金来支付该提案交易。所有的 BSQ交易需要用 BTC 支付挖矿手续费以及发起交易也需要用 BTC 支付所需的 BSQ 数量({0} 聪/BSQ)\n缺少:{1} dao.feeTx.confirm=确认 {0} 交易 -dao.feeTx.confirm.details={0} fee: {1}\nMining fee: {2} ({3} Satoshis/vbyte)\nTransaction vsize: {4} vKb\n\nAre you sure you want to publish the {5} transaction? +dao.feeTx.confirm.details={0}手续费:{1}\n矿工手续费:{2}({3} 聪/byte)\n交易大小:{4} Kb\n\n您确定您要发送这个 {5} 交易吗? -dao.feeTx.issuanceProposal.confirm.details={0} fee: {1}\nBTC needed for BSQ issuance: {2} ({3} Satoshis/BSQ)\nMining fee: {4} ({5} Satoshis/vbyte)\nTransaction vsize: {6} vKb\n\nIf your request is approved, you will receive the amount you requested net of the 2 BSQ proposal fee.\n\nAre you sure you want to publish the {7} transaction? +dao.feeTx.issuanceProposal.confirm.details={0}手续费:{1}\n为 BSQ 提案所需要的BTC:{2}({3}聪 / BSQ)\n挖矿手续费:{4}({5}聪 /字节)\n交易大小:{6}Kb\n\n如果你的要求被批准,你将收到你要求数量的 2 个 BSQ 提议的费用。\n\n你确定你想要发布{7}交易? dao.news.bisqDAO.title=Bisq DAO dao.news.bisqDAO.description=正如 Bisq交易是分散的,并且不受审查,它的治理模型也是如此—— Bisq DAO 和 BSQ 是使其成为可能的工具。 @@ -1930,15 +1957,15 @@ dao.factsAndFigures.dashboard.avgPrice90=90天平均 BSQ/BTC 交易价格 dao.factsAndFigures.dashboard.avgPrice30=30天平均 BSQ/BTC 交易价格 dao.factsAndFigures.dashboard.avgUSDPrice90=90 天成交量加权平均 USD/BSQ 交易价格 dao.factsAndFigures.dashboard.avgUSDPrice30=30 天成交量加权平均 USD/BSQ 交易价格 -dao.factsAndFigures.dashboard.marketCap=市值(基于市场价) -dao.factsAndFigures.dashboard.availableAmount=总共可用的 BSQ +dao.factsAndFigures.dashboard.marketCap=市值(基于 30天平均 USD/BSQ 价格) +dao.factsAndFigures.dashboard.availableAmount=总共可用的 BSQ dao.factsAndFigures.supply.issuedVsBurnt=已发放的 BSQ 已销毁的 BSQ dao.factsAndFigures.supply.issued=已发放的 BSQ dao.factsAndFigures.supply.genesisIssueAmount=在初始交易中心有问题的 BSQ -dao.factsAndFigures.supply.compRequestIssueAmount=报偿申请发放的 BSQ -dao.factsAndFigures.supply.reimbursementAmount=退还申请发放的 BSQ +dao.factsAndFigures.supply.compRequestIssueAmount=报偿申请发放的 BSQ +dao.factsAndFigures.supply.reimbursementAmount=退还申请发放的 BSQ dao.factsAndFigures.supply.burnt=BSQ 烧毁总量 dao.factsAndFigures.supply.burntMovingAverage=15天动态平均线 @@ -2000,7 +2027,7 @@ disputeSummaryWindow.openDate=工单创建时间 disputeSummaryWindow.role=交易者的角色 disputeSummaryWindow.payout=交易金额支付 disputeSummaryWindow.payout.getsTradeAmount=BTC {0} 获得交易金额支付 -disputeSummaryWindow.payout.getsAll=BTC {0} 获取全部 +disputeSummaryWindow.payout.getsAll=最大 BTC 支付数 {0} disputeSummaryWindow.payout.custom=自定义支付 disputeSummaryWindow.payoutAmount.buyer=买家支付金额 disputeSummaryWindow.payoutAmount.seller=卖家支付金额 @@ -2052,7 +2079,7 @@ disputeSummaryWindow.close.txDetails.headline=发布交易退款 disputeSummaryWindow.close.txDetails.buyer=买方收到{0}在地址:{1} # suppress inspection "TrailingSpacesInProperty" disputeSummaryWindow.close.txDetails.seller=卖方收到{0}在地址:{1} -disputeSummaryWindow.close.txDetails=Spending: {0}\n{1}{2}Transaction fee: {3} ({4} satoshis/vbyte)\nTransaction vsize: {5} vKb\n\nAre you sure you want to publish this transaction? +disputeSummaryWindow.close.txDetails=费用:{0}\n{1}{2}交易费:{3}({4}satoshis/byte)\n事务大小:{5} Kb\n\n您确定要发布此交易吗? disputeSummaryWindow.close.noPayout.headline=未支付关闭 disputeSummaryWindow.close.noPayout.text=你想要在未作支付的情况下关闭吗? @@ -2154,6 +2181,7 @@ tradeDetailsWindow.tradingPeersOnion=交易伙伴匿名地址 tradeDetailsWindow.tradingPeersPubKeyHash=交易伙伴公钥哈希值 tradeDetailsWindow.tradeState=交易状态 tradeDetailsWindow.agentAddresses=仲裁员/调解员 +tradeDetailsWindow.detailData=详情数据 walletPasswordWindow.headline=输入密码解锁 @@ -2183,6 +2211,8 @@ feeOptionWindow.info=您可以选择用 BSQ 或 BTC 支付交易费用。如果 feeOptionWindow.optionsLabel=选择货币支付交易手续费 feeOptionWindow.useBTC=使用 BTC feeOptionWindow.fee={0}(≈ {1}) +feeOptionWindow.btcFeeWithFiatAndPercentage={0} (≈ {1} / {2}) +feeOptionWindow.btcFeeWithPercentage={0} ({1}) #################################################################### @@ -2213,7 +2243,7 @@ error.closedTradeWithUnconfirmedDepositTx=交易 ID 为 {0} 的已关闭交易 error.closedTradeWithNoDepositTx=交易 ID 为 {0} 的保证金交易已被确认。\n\n请重新启动应用程序来清理已关闭的交易列表。 popup.warning.walletNotInitialized=钱包至今未初始化 -popup.warning.osxKeyLoggerWarning=由于 MacOS 10.14 及更高版本中的安全措施更加严格,因此启动 Java 应用程序(Bisq 使用Java)会在 MacOS 中引发弹出警告(``Bisq 希望从任何应用程序接收击键'').\n\n为了避免该问题,请打开“ MacOS 设置”,然后转到“安全和隐私”->“隐私”->“输入监视”,然后从右侧列表中删除“ Bisq”。\n\n一旦解决了技术限制(所需的 Java 版本的 Java 打包程序尚未交付),Bisq将升级到新的 Java 版本,以避免该问题。 +popup.warning.osxKeyLoggerWarning=由于 MacOS 10.14 及更高版本中的安全措施更加严格,因此启动 Java 应用程序(Bisq 使用Java)会在 MacOS 中引发弹出警告(``Bisq 希望从任何应用程序接收击键'').\n\n为了避免该问题,请打开“ MacOS 设置”,然后转到“安全和隐私”->“隐私”->“输入监视”,然后从右侧列表中删除“ Bisq”。\n\n一旦解决了技术限制(所需的 Java 版本的 Java 打包程序尚未交付),Bisq将升级到新的 Java 版本,以避免该问题。 popup.warning.wrongVersion=您这台电脑上可能有错误的 Bisq 版本。\n您的电脑的架构是:{0}\n您安装的 Bisq 二进制文件是:{1}\n请关闭并重新安装正确的版本({2})。 popup.warning.incompatibleDB=我们检测到不兼容的数据库文件!\n\n那些数据库文件与我们当前的代码库不兼容:\n{0}\n\n我们对损坏的文件进行了备份,并将默认值应用于新的数据库版本。\n\n备份位于:\n{1}/db/backup_of_corrupted_data。\n\n请检查您是否安装了最新版本的 Bisq\n您可以下载:\nhttps://bisq.network/downloads\n\n请重新启动应用程序。 popup.warning.startupFailed.twoInstances=Bisq 已经在运行。 您不能运行两个 Bisq 实例。 @@ -2226,6 +2256,7 @@ popup.warning.noMediatorsAvailable=没有调解员可用。 popup.warning.notFullyConnected=您需要等到您完全连接到网络\n在启动时可能需要2分钟。 popup.warning.notSufficientConnectionsToBtcNetwork=你需要等待至少有{0}个与比特币网络的连接点。 popup.warning.downloadNotComplete=您需要等待,直到丢失的比特币区块被下载完毕。 +popup.warning.chainNotSynced=Bisq 钱包区块链高度没有正确地同步。如果最近才打开应用,请等待一个新发布的比特币区块。\n\n你可以检查区块链高度在设置/网络信息。如果经过了一个区块但问题还是没有解决,你应该及时的完成 SPV 链重新同步。https://bisq.wiki/Resyncing_SPV_file popup.warning.removeOffer=您确定要移除该报价吗?\n如果您删除该报价,{0} 的挂单费将会丢失。 popup.warning.tooLargePercentageValue=您不能设置100%或更大的百分比。 popup.warning.examplePercentageValue=请输入百分比数字,如 5.4% 是“5.4” @@ -2254,7 +2285,7 @@ popup.warning.openOffer.makerFeeTxRejected=交易 ID 为 {0} 的挂单费交易 popup.warning.trade.txRejected.tradeFee=交易手续费 popup.warning.trade.txRejected.deposit=押金 -popup.warning.trade.txRejected=使用 ID {1} 进行交易的 {0} 交易被比特币网络拒绝。\n交易 ID = {2}}\n交易已被移至失败交易。\n请到“设置/网络信息”进行 SPV 重新同步。\n如需更多帮助,请联系 Bisq Keybase 团队的 Support 频道 +popup.warning.trade.txRejected=使用 ID {1} 进行交易的 {0} 交易被比特币网络拒绝。\n交易 ID = {2}\n交易已被移至失败交易。\n请到“设置/网络信息”进行 SPV 重新同步。\n如需更多帮助,请联系 Bisq Keybase 团队的 Support 频道 popup.warning.openOfferWithInvalidMakerFeeTx=交易 ID 为 {0} 的挂单费交易无效。\n交易 ID = {1}。\n请到“设置/网络信息”进行 SPV 重新同步。\n如需更多帮助,请联系 Bisq Keybase 团队的 Support 频道 @@ -2264,14 +2295,15 @@ popup.info.cashDepositInfo=请确保您在您的地区有一个银行分行, popup.info.cashDepositInfo.confirm=我确认我可以支付保证金 popup.info.shutDownWithOpenOffers=Bisq 正在被关闭,但仍有公开的报价。\n\n当 Bisq 关闭时,这些提供将不能在 P2P 网络上使用,但是它们将在您下次启动 Bisq 时重新发布到 P2P 网络上。\n\n为了让您的报价在线,保持 Bisq 运行,并确保这台计算机也在线(即,确保它不会进入待机模式…显示器待机不是问题)。 popup.info.qubesOSSetupInfo=你似乎好像在 Qubes OS 上运行 Bisq。\n\n请确保您的 Bisq qube 是参考设置指南的说明设置的 https://bisq.wiki/Running_Bisq_on_Qubes +popup.warn.downGradePrevention=不支持从 {0} 版本降级到 {1} 版本。请使用最新的 Bisq 版本。 +popup.warn.daoRequiresRestart=在同步 DAO 状态时发生问题。你需要重启应用以修复此问题。 popup.privateNotification.headline=重要私人通知! popup.securityRecommendation.headline=重要安全建议 popup.securityRecommendation.msg=如果您还没有启用,我们想提醒您考虑为您的钱包使用密码保护。\n\n强烈建议你写下钱包还原密钥。 那些还原密钥就是恢复你的比特币钱包的主密码。\n在“钱包密钥”部分,您可以找到更多信息\n\n此外,您应该在“备份”界面备份完整的应用程序数据文件夹。 -popup.bitcoinLocalhostNode.msg=Bisq 检测到一个本地运行的比特币核心节点(在本地主机)。\n在启动 Bisq 之前,请确保此节点已完全同步,并且没有在删除模式下运行。 -popup.bitcoinLocalhostNode.additionalRequirements=\n\n对于配置完整的节点,要求该节点禁用 pruning 并启用 bloom filters。 +popup.bitcoinLocalhostNode.msg=Bisq 侦测到一个比特币核心节点在本机(本地)运行\n\n请确保:\n- 这个节点已经在运行 Bisq 之前已全部同步\n- 修饰已被禁用 ('prune=0' 在 bitcoin.conf 文件中)\n- Bloom 过滤器已经启用('peerbloomfilters=1' 在 bitcoin.conf 文件中) popup.shutDownInProgress.headline=正在关闭 popup.shutDownInProgress.msg=关闭应用可能会花一点时间。\n请不要打断关闭过程。 @@ -2303,15 +2335,12 @@ popup.accountSigning.signedByPeer=您的一个付款帐户已经被交易伙伴 popup.accountSigning.peerLimitLifted=您其中一个帐户的初始限额已被取消。\n\n{0} popup.accountSigning.peerSigner=您的一个帐户已足够成熟,可以验证其他付款帐户,您的一个帐户的初始限额已被取消。\n\n{0} -popup.accountSigning.singleAccountSelect.headline=选择账龄证据 -popup.accountSigning.singleAccountSelect.description=寻找账龄证据 -popup.accountSigning.singleAccountSelect.datePicker=选择要验证的帐户的时间点 +popup.accountSigning.singleAccountSelect.headline=导入未验证账龄证据 popup.accountSigning.confirmSingleAccount.headline=确认所选账龄证据 popup.accountSigning.confirmSingleAccount.selectedHash=已选择证据哈希值 popup.accountSigning.confirmSingleAccount.button=验证账龄证据 popup.accountSigning.successSingleAccount.description=证据 {0} 已被验证 popup.accountSigning.successSingleAccount.success.headline=成功 -popup.accountSigning.successSingleAccount.signError=未能成功验证证据,{0} popup.accountSigning.unsignedPubKeys.headline=未验证公钥 popup.accountSigning.unsignedPubKeys.sign=验证公钥 @@ -2354,7 +2383,7 @@ systemTray.tooltip=Bisq:去中心化比特币交易网络 # GUI Util #################################################################### -guiUtil.miningFeeInfo=Please be sure that the mining fee used by your external wallet is at least {0} satoshis/vbyte. Otherwise the trade transactions may not be confirmed in time and the trade will end up in a dispute. +guiUtil.miningFeeInfo=请确保您的外部钱包使用的矿工手续费费用足够高至少为 {0} 聪/字节,以便矿工接受资金交易。\n否则交易所交易无法确认,交易最终将会出现纠纷。 guiUtil.accountExport.savedToPath=交易账户保存在路径:\n{0} guiUtil.accountExport.noAccountSetup=您没有交易账户设置导出。 @@ -2447,8 +2476,8 @@ navigation.dao.wallet.receive=“DAO/BSQ 钱包/接收” formatter.formatVolumeLabel={0} 数量 {1} formatter.makerTaker=卖家 {0} {1} / 买家 {2} {3} -formatter.youAreAsMaker=您是 {0} {1} 卖家 / 买家是 {2} {3} -formatter.youAreAsTaker=您是 {0} {1} 买家 / 卖家是 {2} {3} +formatter.youAreAsMaker=您是 {1} {0} 卖家 / 买家是 {3} {2} +formatter.youAreAsTaker=您是 {1} {0} 买家 / 卖家是 {3} {2} formatter.youAre=您是 {0} {1} ({2} {3}) formatter.youAreCreatingAnOffer.fiat=您创建新的报价 {0} {1} formatter.youAreCreatingAnOffer.altcoin=您正创建报价 {0} {1}({2} {3}) @@ -2510,7 +2539,7 @@ seed.date=钱包时间 seed.restore.title=使用还原密钥恢复钱包 seed.restore=恢复钱包 seed.creationDate=创建时间 -seed.warn.walletNotEmpty.msg=Your Bitcoin wallet is not empty.\n\nYou must empty this wallet before attempting to restore an older one, as mixing wallets together can lead to invalidated backups.\n\nPlease finalize your trades, close all your open offers and go to the Funds section to withdraw your bitcoin.\nIn case you cannot access your bitcoin you can use the emergency tool to empty the wallet.\nTo open the emergency tool press \"Alt+e\" or \"Cmd/Ctrl+e\". +seed.warn.walletNotEmpty.msg=你的比特币钱包不是空的。\n\n在尝试恢复较旧的钱包之前,您必须清空此钱包,因为将钱包混在一起会导致无效的备份。\n\n请完成您的交易,关闭所有您的未完成报价,并转到资金界面撤回您的比特币。\n如果您无法访问您的比特币,您可以使用紧急工具清空钱包。\n要打开该应急工具,请按“alt + e”或“Cmd/Ctrl + e” 。 seed.warn.walletNotEmpty.restore=无论如何我要恢复 seed.warn.walletNotEmpty.emptyWallet=我先清空我的钱包 seed.warn.notEncryptedAnymore=你的钱包被加密了。\n\n恢复后,钱包将不再加密,您必须设置新的密码。\n\n你要继续吗? @@ -2551,7 +2580,7 @@ payment.altcoin.address=数字货币地址 payment.altcoin.tradeInstantCheckbox=使用数字货币进行即时交易( 1 小时内) payment.altcoin.tradeInstant.popup=对于即时交易,要求交易双方都在线,能够在不到1小时内完成交易。\n \n如果你已经有未完成的报价以及你不能即时完成,请在资料页面禁用这些报价。 payment.altcoin=数字货币 -payment.select.altcoin=Select or search Altcoin +payment.select.altcoin=选择或搜索数字货币 payment.secret=密保问题 payment.answer=答案 payment.wallet=钱包 ID @@ -2561,9 +2590,10 @@ payment.venmo.venmoUserName=Venmo 用户名: payment.popmoney.accountId=电子邮箱或者电话号码 payment.promptPay.promptPayId=公民身份证/税号或电话号码 payment.supportedCurrencies=支持的货币 +payment.supportedCurrenciesForReceiver=收款 payment.limitations=限制条件 payment.salt=帐户年龄验证盐值 -payment.error.noHexSalt=The salt needs to be in HEX format.\nIt is only recommended to edit the salt field if you want to transfer the salt from an old account to keep your account age. The account age is verified by using the account salt and the identifying account data (e.g. IBAN). +payment.error.noHexSalt=盐值需要十六进制的。\n如果您想要从旧帐户转移盐值以保留帐龄,只建议编辑盐值字段。帐龄通过帐户盐值和识别帐户数据(例如 IBAN )来验证。 payment.accept.euro=接受来自这些欧元国家的交易 payment.accept.nonEuro=接受来自这些非欧元国家的交易 payment.accepted.countries=接受的国家 @@ -2599,31 +2629,31 @@ payment.savings=保存 payment.personalId=个人 ID payment.clearXchange.info=Zelle是一项转账服务,转账到其他银行做的很好。\n\n1.检查此页面以查看您的银行是否(以及如何)与 Zelle 合作:\nhttps://www.zellepay.com/get-started\n\n2.特别注意您的转账限额-汇款限额因银行而异,银行通常分别指定每日,每周和每月的限额。\n\n3.如果您的银行不能使用 Zelle,您仍然可以通过 Zelle 移动应用程序使用它,但是您的转账限额会低得多。\n\n4.您的 Bisq 帐户上指定的名称必须与 Zelle/银行帐户上的名称匹配。 \n\n如果您无法按照贸易合同中的规定完成 Zelle 交易,则可能会损失部分(或全部)保证金。\n\n由于 Zelle 的拒付风险较高,因此建议卖家通过电子邮件或 SMS 与未签名的买家联系,以确认买家确实拥有 Bisq 中指定的 Zelle 帐户。 payment.fasterPayments.newRequirements.info=有些银行已经开始核实快捷支付收款人的全名。您当前的快捷支付帐户没有填写全名。\n\n请考虑在 Bisq 中重新创建您的快捷支付帐户,为将来的 {0} 买家提供一个完整的姓名。\n\n重新创建帐户时,请确保将银行区号、帐户编号和帐龄验证盐值从旧帐户复制到新帐户。这将确保您现有的帐龄和签名状态得到保留。 -payment.moneyGram.info=When using MoneyGram the BTC buyer has to send the Authorisation number and a photo of the receipt by email to the BTC seller. The receipt must clearly show the seller's full name, country, state and the amount. The seller's email will be displayed to the buyer during the trade process. -payment.westernUnion.info=When using Western Union the BTC buyer has to send the MTCN (tracking number) and a photo of the receipt by email to the BTC seller. The receipt must clearly show the seller's full name, city, country and the amount. The seller's email will be displayed to the buyer during the trade process. +payment.moneyGram.info=使用 MoneyGram 时,BTC 买方必须将授权号码和收据的照片通过电子邮件发送给 BTC 卖方。收据必须清楚地显示卖方的全名、国家或地区、州和金额。买方将在交易过程中显示卖方的电子邮件。 +payment.westernUnion.info=使用 Western Union 时,BTC 买方必须通过电子邮件将 MTCN(运单号)和收据照片发送给 BTC 卖方。收据上必须清楚地显示卖方的全名、城市、国家或地区和金额。买方将在交易过程中显示卖方的电子邮件。 payment.halCash.info=使用 HalCash 时,BTC 买方需要通过手机短信向 BTC 卖方发送 HalCash 代码。\n\n请确保不要超过银行允许您用半现金汇款的最高金额。每次取款的最低金额是 10 欧元,最高金额是 10 欧元。金额是 600 欧元。对于重复取款,每天每个接收者 3000 欧元,每月每个接收者 6000 欧元。请与您的银行核对这些限额,以确保它们使用与此处所述相同的限额。\n\n提现金额必须是 10 欧元的倍数,因为您不能从 ATM 机提取其他金额。 创建报价和下单屏幕中的 UI 将调整 BTC 金额,使 EUR 金额正确。你不能使用基于市场的价格,因为欧元的数量会随着价格的变化而变化。\n # suppress inspection "UnusedMessageFormatParameter" -payment.limits.info=Please be aware that all bank transfers carry a certain amount of chargeback risk. To mitigate this risk, Bisq sets per-trade limits based on the estimated level of chargeback risk for the payment method used.\n\nFor this payment method, your per-trade limit for buying and selling is {2}.\n\nThis limit only applies to the size of a single trade—you can place as many trades as you like.\n\nSee more details on the wiki [HYPERLINK:https://bisq.wiki/Account_limits]. +payment.limits.info=请注意,所有银行转账都有一定的退款风险。为了降低这一风险,Bisq 基于使用的付款方式的退款风险。\n\n对于付款方式,您的每笔交易的出售和购买的限额为{2}\n\n限制只应用在单笔交易,你可以尽可能多的进行交易。\n\n在 Bisq Wiki 查看更多信息[HYPERLINK:https://bisq.wiki/Account_limits]。 # suppress inspection "UnusedProperty" -payment.limits.info.withSigning=To limit chargeback risk, Bisq sets per-trade limits for this payment account type based on the following 2 factors:\n\n1. General chargeback risk for the payment method\n2. Account signing status\n\nThis payment account is not yet signed, so it is limited to buying {0} per trade. After signing, buy limits will increase as follows:\n\n● Before signing, and for 30 days after signing, your per-trade buy limit will be {0}\n● 30 days after signing, your per-trade buy limit will be {1}\n● 60 days after signing, your per-trade buy limit will be {2}\n\nSell limits are not affected by account signing. You can sell {2} in a single trade immediately.\n\nThese limits only apply to the size of a single trade—you can place as many trades as you like. \n\nSee more details on the wiki [HYPERLINK:https://bisq.wiki/Account_limits]. +payment.limits.info.withSigning=为了降低这一风险,Bisq 基于两个因素对该付款方式每笔交易设置了限制:\n\n1. 使用的付款方法的预估退款风险水平\n2. 您的付款方式的账龄\n\n这个付款账户还没有被验证,所以他每个交易最多购买{0}。在验证之后,购买限制会以以下规则逐渐增加:\n\n●签署前,以及签署后30天内,您的每笔最大交易将限制为{0}\n●签署后30天,每笔最大交易将限制为{1}\n●签署后60天,每笔最大交易将限制为{2}\n\n出售限制不会被账户验证状态限制,你可以理科进行单笔为{2}的交易\n\n限制只应用在单笔交易,你可以尽可能多的进行交易。\n\n在 Bisq Wiki 上查看更多:\nhttps://bisq.wiki/Account_limits payment.cashDeposit.info=请确认您的银行允许您将现金存款汇入他人账户。例如,美国银行和富国银行不再允许此类存款。 payment.revolut.info=Revolut 要求使用“用户名”作为帐户 ID,而不是像以往的电话号码或电子邮件。 -payment.account.revolut.addUserNameInfo={0}\nYour existing Revolut account ({1}) does not have a ''User name''.\nPlease enter your Revolut ''User name'' to update your account data.\nThis will not affect your account age signing status. +payment.account.revolut.addUserNameInfo={0}\n您现有的 Revolut 帐户({1})尚未设置“用户名”。\n请输入您的 Revolut ``用户名''以更新您的帐户数据。\n这不会影响您的账龄验证状态。 payment.revolut.addUserNameInfo.headLine=更新 Revolut 账户 payment.usPostalMoneyOrder.info=在 Bisq 上交易 US Postal Money Orders (USPMO)您必须理解下述条款:\n\n- BTC 买方必须在发送方和收款人字段中都写上 BTC 卖方的名称,并在发送之前对 USPMO 和信封进行高分辨率照片拍照,并带有跟踪证明。\n- BTC 买方必须将 USPMO 连同交货确认书一起发送给 BTC 卖方。\n\n如果需要调解,或有交易纠纷,您将需要将照片连同 USPMO 编号,邮局编号和交易金额一起发送给 Bisq 调解员或退款代理,以便他们进行验证美国邮局网站上的详细信息。\n\n如未能提供要求的交易数据将在纠纷中直接判负\n\n在所有争议案件中,USPMO 发送方在向调解人或仲裁员提供证据/证明时承担 100% 的责任。\n\n如果您不理解这些要求,请不要在 Bisq 上使用 USPMO 进行交易。 payment.f2f.contact=联系方式 -payment.f2f.contact.prompt=How would you like to be contacted by the trading peer? (email address, phone number,...) +payment.f2f.contact.prompt=您希望如何与交易伙伴联系?(电子邮箱、电话号码、…) payment.f2f.city=“面对面”会议的城市 payment.f2f.city.prompt=城市将与报价一同显示 payment.f2f.optionalExtra=可选的附加信息 payment.f2f.extra=附加信息 payment.f2f.extra.prompt=交易方可以定义“条款和条件”或添加公共联系信息。它将与报价一同显示。 -payment.f2f.info='Face to Face' trades have different rules and come with different risks than online transactions.\n\nThe main differences are:\n● The trading peers need to exchange information about the meeting location and time by using their provided contact details.\n● The trading peers need to bring their laptops and do the confirmation of 'payment sent' and 'payment received' at the meeting place.\n● If a maker has special 'terms and conditions' they must state those in the 'Additional information' text field in the account.\n● By taking an offer the taker agrees to the maker's stated 'terms and conditions'.\n● In case of a dispute the mediator or arbitrator cannot be of much assistance as it is usually difficult to get tamper-proof evidence of what happened at the meeting. In such cases the BTC funds might get locked indefinitely or until the trading peers come to an agreement.\n\nTo be sure you fully understand the differences with 'Face to Face' trades please read the instructions and recommendations at: [HYPERLINK:https://docs.bisq.network/trading-rules.html#f2f-trading] +payment.f2f.info=与网上交易相比,“面对面”交易有不同的规则,也有不同的风险。\n\n主要区别是:\n●交易伙伴需要使用他们提供的联系方式交换关于会面地点和时间的信息。\n●交易双方需要携带笔记本电脑,在会面地点确认“已发送付款”和“已收到付款”。\n●如果交易方有特殊的“条款和条件”,他们必须在账户的“附加信息”文本框中声明这些条款和条件。\n●在发生争议时,调解员或仲裁员不能提供太多帮助,因为通常很难获得有关会面上所发生情况的篡改证据。在这种情况下,BTC 资金可能会被无限期锁定,或者直到交易双方达成协议。\n\n为确保您完全理解“面对面”交易的不同之处,请阅读以下说明和建议:“https://docs.bisq.network/trading-rules.html#f2f-trading” payment.f2f.info.openURL=打开网页 payment.f2f.offerbook.tooltip.countryAndCity=国家或地区及城市:{0} / {1} payment.f2f.offerbook.tooltip.extra=附加信息:{0} @@ -2633,9 +2663,10 @@ payment.japan.branch=分行 payment.japan.account=账户 payment.japan.recipient=名称 payment.australia.payid=PayID -payment.payid=PayID linked to financial institution. Like email address or mobile phone. -payment.payid.info=A PayID like a phone number, email address or an Australian Business Number (ABN), that you can securely link to your bank, credit union or building society account. You need to have already created a PayID with your Australian financial institution. Both sending and receiving financial institutions must support PayID. For more information please check [HYPERLINK:https://payid.com.au/faqs/] -payment.amazonGiftCard.info=To pay with Amazon eGift Card you need to purchase an Amazon eGift Card at your Amazon account and use the BTC seller''s email or mobile nr. as receiver. Amazon sends then an email or text message to the receiver. Use the trade ID for the message field.\n\nAmazon eGift Cards can only be redeemed by Amazon accounts with the same currency.\n\nFor more information visit the Amazon eGift Card webpage. [HYPERLINK:https://www.amazon.com/Amazon-1_US_Email-eGift-Card/dp/B004LLIKVU] +payment.payid=PayID 需链接至金融机构。例如电子邮件地址或手机。 +payment.payid.info=PayID,如电话号码、电子邮件地址或澳大利亚商业号码(ABN),您可以安全地连接到您的银行、信用合作社或建立社会帐户。你需要在你的澳大利亚金融机构创建一个 PayID。发送和接收金融机构都必须支持 PayID。更多信息请查看[HYPERLINK:https://payid.com.au/faqs/] +payment.amazonGiftCard.info=To pay with Amazon eGift Card, you will need to send an Amazon eGift Card to the BTC seller via your Amazon account. \n\nBisq will show the BTC seller''s email address or phone number where the gift card should be sent, and you must include the trade ID in the gift card''s message field. Please see the wiki [HYPERLINK:https://bisq.wiki/Amazon_eGift_card] for further details and best practices. \n\nThree important notes:\n- try to send gift cards with amounts of 100 USD or smaller, as Amazon is known to flag larger gift cards as fraudulent\n- try to use creative, believable text for the gift card''s message (e.g., "Happy birthday Susan!") along with the trade ID (and use trader chat to tell your trading peer the reference text you picked so they can verify your payment)\n- Amazon eGift Cards can only be redeemed on the Amazon website they were purchased on (e.g., a gift card purchased on amazon.it can only be redeemed on amazon.it) + # We use constants from the code so we do not use our normal naming convention # dynamic values are not recognized by IntelliJ @@ -2650,7 +2681,7 @@ MONEY_GRAM=MoneyGram WESTERN_UNION=西联汇款 F2F=面对面(当面交易) JAPAN_BANK=日本银行汇款 -AUSTRALIA_PAYID=Australian PayID +AUSTRALIA_PAYID=澳大利亚 PayID # suppress inspection "UnusedProperty" NATIONAL_BANK_SHORT=国内银行 @@ -2671,7 +2702,7 @@ F2F_SHORT=F2F # suppress inspection "UnusedProperty" JAPAN_BANK_SHORT=Japan Furikomi # suppress inspection "UnusedProperty" -AUSTRALIA_PAYID_SHORT=PayID +AUSTRALIA_PAYID_SHORT=支付 ID # Do not translate brand names # suppress inspection "UnusedProperty" @@ -2713,7 +2744,7 @@ ADVANCED_CASH=Advanced Cash # suppress inspection "UnusedProperty" TRANSFERWISE=TransferWise # suppress inspection "UnusedProperty" -AMAZON_GIFT_CARD=Amazon eGift Card +AMAZON_GIFT_CARD=亚马逊电子礼品卡 # suppress inspection "UnusedProperty" BLOCK_CHAINS_INSTANT=Altcoins Instant @@ -2765,7 +2796,7 @@ ADVANCED_CASH_SHORT=Advanced Cash # suppress inspection "UnusedProperty" TRANSFERWISE_SHORT=TransferWise # suppress inspection "UnusedProperty" -AMAZON_GIFT_CARD_SHORT=Amazon eGift Card +AMAZON_GIFT_CARD_SHORT=亚马逊电子礼品卡 # suppress inspection "UnusedProperty" BLOCK_CHAINS_INSTANT_SHORT=Altcoins Instant @@ -2789,10 +2820,10 @@ validation.zero=不允许输入0。 validation.negative=不允许输入负值。 validation.fiat.toSmall=不允许输入比最小可能值还小的数值。 validation.fiat.toLarge=不允许输入比最大可能值还大的数值。 -validation.btc.fraction=Input will result in a bitcoin value of less than 1 satoshi +validation.btc.fraction=此充值将会产生小于 1 聪的比特币数量。 validation.btc.toLarge=不允许充值大于{0} validation.btc.toSmall=不允许充值小于{0} -validation.passwordTooShort=The password you entered is too short. It needs to have a min. of 8 characters. +validation.passwordTooShort=你输入的密码太短。最少 8 个字符。 validation.passwordTooLong=你输入的密码太长。最长不要超过50个字符。 validation.sortCodeNumber={0} 必须由 {1} 个数字构成。 validation.sortCodeChars={0} 必须由 {1} 个字符构成。 @@ -2813,34 +2844,34 @@ validation.accountNrFormat=帐号必须是格式:{0} # suppress inspection "UnusedProperty" validation.altcoin.wrongStructure=地址验证失败,因为它与 {0} 地址的结构不匹配。 # suppress inspection "UnusedProperty" -validation.altcoin.ltz.zAddressesNotSupported=LTZ address must start with L. Addresses starting with z are not supported. +validation.altcoin.ltz.zAddressesNotSupported=LTZ 地址需要以 L 开头。 不支持以 Z 开头的地址。 # suppress inspection "UnusedProperty" -validation.altcoin.zAddressesNotSupported=ZEC addresses must start with t. Addresses starting with z are not supported. +validation.altcoin.zAddressesNotSupported=LTZ 地址需要以 L 开头。 不支持以 Z 开头的地址。 # suppress inspection "UnusedProperty" validation.altcoin.invalidAddress=这个地址不是有效的{0}地址!{1} # suppress inspection "UnusedProperty" validation.altcoin.liquidBitcoin.invalidAddress=不支持本地 segwit 地址(以“lq”开头的地址)。 -validation.bic.invalidLength=Input length must be 8 or 11 +validation.bic.invalidLength=输入长度既不是 8 也不是 11 validation.bic.letters=必须输入银行和国家或地区代码 validation.bic.invalidLocationCode=BIC 包含无效的地址代码 validation.bic.invalidBranchCode=BIC 包含无效的分行代码 validation.bic.sepaRevolutBic=不支持 Revolut Sepa 账户 -validation.btc.invalidFormat=Invalid format for a Bitcoin address. -validation.bsq.invalidFormat=Invalid format for a BSQ address. +validation.btc.invalidFormat=无效格式的比特币地址 +validation.bsq.invalidFormat=无效格式的 BSQ 地址 validation.email.invalidAddress=无效地址 validation.iban.invalidCountryCode=国家或地区代码无效 validation.iban.checkSumNotNumeric=校验必须是数字 validation.iban.nonNumericChars=检测到非字母数字字符 validation.iban.checkSumInvalid=IBAN 校验无效 -validation.iban.invalidLength=Number must have a length of 15 to 34 chars. +validation.iban.invalidLength=数字的长度必须为15到34个字符。 validation.interacETransfer.invalidAreaCode=非加拿大区号 -validation.interacETransfer.invalidPhone=Please enter a valid 11 digit phone number (ex: 1-123-456-7890) or an email address +validation.interacETransfer.invalidPhone=请输入可用的 11 为电话号码(例如 1-123-456-7890)或邮箱地址 validation.interacETransfer.invalidQuestion=必须只包含字母、数字、空格和/或符号“_ , . ? -” validation.interacETransfer.invalidAnswer=必须是一个单词,只包含字母、数字和/或符号- validation.inputTooLarge=输入不能大于 {0} validation.inputTooSmall=输入必须大于 {0} validation.inputToBeAtLeast=输入必须至少为 {0} -validation.amountBelowDust=An amount below the dust limit of {0} satoshi is not allowed. +validation.amountBelowDust=不允许低于 {0} 聪的零头限制。 validation.length=长度必须在 {0} 和 {1} 之间 validation.pattern=输入格式必须为:{0} validation.noHexString=输入不是十六进制格式。 @@ -2852,7 +2883,7 @@ validation.numberFormatException=数字格式异常 {0} validation.mustNotBeNegative=不能输入负值 validation.phone.missingCountryCode=需要两个字母的国家或地区代码来验证电话号码 validation.phone.invalidCharacters=电话号码 {0} 包含无效字符 -validation.phone.insufficientDigits=There are not enough digits in {0} to be a valid phone number -validation.phone.tooManyDigits=There are too many digits in {0} to be a valid phone number -validation.phone.invalidDialingCode=Country dialing code for number {0} is invalid for country {1}. The correct dialing code is {2}. +validation.phone.insufficientDigits={0} 中没有足够的数字作为有效的电话号码 +validation.phone.tooManyDigits={0} 中的数字太多,不是有效的电话号码 +validation.phone.invalidDialingCode=数字 {0} 中的国际拨号代码对于 {1} 无效。正确的拨号号码是 {2} 。 validation.invalidAddressList=使用逗号分隔有效地址列表 diff --git a/core/src/main/resources/i18n/displayStrings_zh-hant.properties b/core/src/main/resources/i18n/displayStrings_zh-hant.properties index 98e92d5782..3a532343c7 100644 --- a/core/src/main/resources/i18n/displayStrings_zh-hant.properties +++ b/core/src/main/resources/i18n/displayStrings_zh-hant.properties @@ -24,9 +24,9 @@ # Shared #################################################################### -shared.readMore=閱讀更多 -shared.openHelp=開啟幫助 -shared.warning=警告 +shared.readMore=閲讀更多 +shared.openHelp=打開幫助 +shared.warning=警吿 shared.close=關閉 shared.cancel=取消 shared.ok=好的 @@ -35,7 +35,7 @@ shared.no=否 shared.iUnderstand=我瞭解 shared.na=N/A shared.shutDown=完全關閉 -shared.reportBug=在 Github 報告錯誤 +shared.reportBug=在 Github 報吿錯誤 shared.buyBitcoin=買入比特幣 shared.sellBitcoin=賣出比特幣 shared.buyCurrency=買入 {0} @@ -52,7 +52,7 @@ shared.P2P=P2P shared.oneOffer=報價 shared.multipleOffers=報價 shared.Offer=報價 -shared.offerVolumeCode={0} Offer Volume +shared.offerVolumeCode={0} 報價量 shared.openOffers=可用報價 shared.trade=交易 shared.trades=交易 @@ -69,16 +69,17 @@ shared.buyerSecurityDeposit=買家保證金 shared.sellerSecurityDeposit=賣家保證金 shared.amountWithCur={0} 數量 shared.volumeWithCur={0} 總量 -shared.currency=貨幣型別 -shared.market=交易專案 +shared.currency=貨幣類型 +shared.market=交易項目 +shared.deviation=Deviation shared.paymentMethod=付款方式 shared.tradeCurrency=交易貨幣 -shared.offerType=報價型別 +shared.offerType=報價類型 shared.details=詳情 shared.address=地址 shared.balanceWithCur={0} 餘額 shared.txId=交易記錄 ID -shared.confirmations=稽核 +shared.confirmations=審核 shared.revert=還原 Tx shared.select=選擇 shared.usage=使用狀況 @@ -95,16 +96,15 @@ shared.BTCMinMax=BTC(最小 - 最大) shared.removeOffer=移除報價 shared.dontRemoveOffer=不要移除報價 shared.editOffer=編輯報價 -shared.openLargeQRWindow=開啟放大二維碼視窗 -shared.tradingAccount=交易賬戶 +shared.openLargeQRWindow=打開放大二維碼窗口 +shared.tradingAccount=交易賬户 shared.faq=訪問 FAQ 頁面 shared.yesCancel=是的,取消 shared.nextStep=下一步 -shared.selectTradingAccount=選擇交易賬戶 +shared.selectTradingAccount=選擇交易賬户 shared.fundFromSavingsWalletButton=從 Bisq 錢包資金劃轉 shared.fundFromExternalWalletButton=從您的外部錢包充值 -shared.openDefaultWalletFailed=開啟預設的比特幣錢包應用程式失敗了。您確定您安裝了嗎? -shared.distanceInPercent=與市場價格的差價 % +shared.openDefaultWalletFailed=打開默認的比特幣錢包應用程序失敗了。您確定您安裝了嗎? shared.belowInPercent=低於市場價格 % shared.aboveInPercent=高於市場價格 % shared.enterPercentageValue=輸入 % 值 @@ -115,43 +115,43 @@ shared.depositTransactionId=存款交易 ID shared.TheBTCBuyer=BTC 買家 shared.You=您 shared.reasonForPayment=付款原因 -shared.sendingConfirmation=傳送確認... -shared.sendingConfirmationAgain=請再次傳送確認 -shared.exportCSV=匯出儲存為 .csv -shared.exportJSON=匯出儲存至 JSON -shared.noDateAvailable=沒有可用資料 +shared.sendingConfirmation=發送確認... +shared.sendingConfirmationAgain=請再次發送確認 +shared.exportCSV=導出保存為 .csv +shared.exportJSON=導出保存至 JSON +shared.noDateAvailable=沒有可用數據 shared.noDetailsAvailable=沒有可用詳細 shared.notUsedYet=尚未使用 shared.date=日期 -shared.sendFundsDetailsWithFee=Sending: {0}\nFrom address: {1}\nTo receiving address: {2}.\nRequired mining fee is: {3} ({4} satoshis/vbyte)\nTransaction vsize: {5} vKb\n\nThe recipient will receive: {6}\n\nAre you sure you want to withdraw this amount? +shared.sendFundsDetailsWithFee=發送:{0}\n來自:{1}\n接收地址:{2}\n要求的最低交易費:{3}({4} 聰/byte)\n交易大小:{5} Kb\n\n收款方將收到:{6}\n\n您確定您想要提現嗎? # suppress inspection "TrailingSpacesInProperty" -shared.sendFundsDetailsDust=Bisq 檢測到,該交易將產生一個低於最低零頭閾值的輸出(不被比特幣共識規則所允許)。相反,這些零頭({0}satoshi{1})將被新增到挖礦手續費中。 -shared.copyToClipboard=複製到剪貼簿 +shared.sendFundsDetailsDust=Bisq 檢測到,該交易將產生一個低於最低零頭閾值的輸出(不被比特幣共識規則所允許)。相反,這些零頭({0}satoshi{1})將被添加到挖礦手續費中。 +shared.copyToClipboard=複製到剪貼板 shared.language=語言 shared.country=國家或地區 shared.applyAndShutDown=同意並關閉 shared.selectPaymentMethod=選擇付款方式 -shared.accountNameAlreadyUsed=這個賬戶名稱已經被已儲存的賬戶佔用。\n請使用另外一個名稱。 +shared.accountNameAlreadyUsed=這個賬户名稱已經被已保存的賬户佔用。\n請使用另外一個名稱。 shared.askConfirmDeleteAccount=您確定想要刪除被選定的賬號嗎? -shared.cannotDeleteAccount=您不能刪除這個賬戶,因為它正在被使用於報價或交易中。 -shared.noAccountsSetupYet=還沒有建立帳戶。 -shared.manageAccounts=管理賬戶 -shared.addNewAccount=新增新的賬戶 -shared.ExportAccounts=匯出賬戶 -shared.importAccounts=匯入賬戶 -shared.createNewAccount=建立新的賬戶 -shared.saveNewAccount=儲存新的賬戶 -shared.selectedAccount=選中的賬戶 -shared.deleteAccount=刪除賬戶 -shared.errorMessageInline=\n錯誤資訊:{0} -shared.errorMessage=錯誤資訊 +shared.cannotDeleteAccount=您不能刪除這個賬户,因為它正在被使用於報價或交易中。 +shared.noAccountsSetupYet=還沒有建立帳户。 +shared.manageAccounts=管理賬户 +shared.addNewAccount=添加新的賬户 +shared.ExportAccounts=導出賬户 +shared.importAccounts=導入賬户 +shared.createNewAccount=創建新的賬户 +shared.saveNewAccount=保存新的賬户 +shared.selectedAccount=選中的賬户 +shared.deleteAccount=刪除賬户 +shared.errorMessageInline=\n錯誤信息:{0} +shared.errorMessage=錯誤信息 shared.information=資料 shared.name=名稱 shared.id=ID shared.dashboard=儀表盤 shared.accept=接受 shared.balance=餘額 -shared.save=儲存 +shared.save=保存 shared.onionAddress=匿名地址 shared.supportTicket=幫助話題 shared.dispute=糾紛 @@ -169,21 +169,21 @@ shared.makerFeeTxId=掛單費交易 ID shared.takerFeeTxId=買單費交易 ID shared.payoutTxId=支出交易 ID shared.contractAsJson=JSON 格式的合同 -shared.viewContractAsJson=檢視 JSON 格式的合同 +shared.viewContractAsJson=查看 JSON 格式的合同 shared.contract.title=交易 ID:{0} 的合同 shared.paymentDetails=BTC {0} 支付詳情 shared.securityDeposit=保證金 shared.yourSecurityDeposit=你的保證金 shared.contract=合同 -shared.messageArrived=訊息送達。 -shared.messageStoredInMailbox=訊息儲存在郵箱中。 -shared.messageSendingFailed=訊息傳送失敗。錯誤:{0} +shared.messageArrived=消息送達。 +shared.messageStoredInMailbox=消息保存在郵箱中。 +shared.messageSendingFailed=消息發送失敗。錯誤:{0} shared.unlock=解鎖 shared.toReceive=接收 shared.toSpend=花費 shared.btcAmount=BTC 總額 shared.yourLanguage=你的語言 -shared.addLanguage=新增語言 +shared.addLanguage=添加語言 shared.total=合計 shared.totalsNeeded=需要資金 shared.tradeWalletAddress=交易錢包地址 @@ -191,13 +191,13 @@ shared.tradeWalletBalance=交易錢包餘額 shared.makerTxFee=賣家:{0} shared.takerTxFee=買家:{0} shared.iConfirm=我確認 -shared.tradingFeeInBsqInfo=相當於使用 {0} 交易手續費 -shared.openURL=開啟 {0} +shared.tradingFeeInBsqInfo=≈ {0} +shared.openURL=打開 {0} shared.fiat=法定貨幣 shared.crypto=加密 shared.all=全部 shared.edit=編輯 -shared.advancedOptions=高階選項 +shared.advancedOptions=高級選項 shared.interval=取消 shared.actions=操作 shared.buyerUpperCase=買家 @@ -216,8 +216,11 @@ shared.arbitrator=仲裁員 shared.refundAgent=仲裁員 shared.refundAgentForSupportStaff=退款助理 shared.delayedPayoutTxId=延遲支付交易 ID -shared.delayedPayoutTxReceiverAddress=延遲交易交易已傳送至 +shared.delayedPayoutTxReceiverAddress=延遲交易交易已發送至 shared.unconfirmedTransactionsLimitReached=你現在有過多的未確認交易。請稍後嘗試 +shared.numItemsLabel=Number of entries: {0} +shared.filter=Filter +shared.enabled=啟用 #################################################################### @@ -228,14 +231,14 @@ shared.unconfirmedTransactionsLimitReached=你現在有過多的未確認交易 # MainView #################################################################### -mainView.menu.market=交易專案 +mainView.menu.market=交易項目 mainView.menu.buyBtc=買入 BTC mainView.menu.sellBtc=賣出 BTC mainView.menu.portfolio=業務 mainView.menu.funds=資金 mainView.menu.support=幫助 -mainView.menu.settings=設定 -mainView.menu.account=賬戶 +mainView.menu.settings=設置 +mainView.menu.account=賬户 mainView.menu.dao=DAO mainView.marketPriceWithProvider.label=交易所價格提供商:{0} @@ -248,38 +251,38 @@ mainView.balance.locked=凍結餘額 mainView.balance.reserved.short=保證 mainView.balance.locked.short=凍結 -mainView.footer.usingTor=(使用 Tor 中) +mainView.footer.usingTor=(via Tor) mainView.footer.localhostBitcoinNode=(本地主機) -mainView.footer.btcInfo={0} {1} {2} -mainView.footer.btcFeeRate=/ Current fee rate: {0} sat/vB -mainView.footer.btcInfo.initializing=連線至比特幣網路 +mainView.footer.btcInfo={0} {1} +mainView.footer.btcFeeRate=/ Fee rate: {0} sat/vB +mainView.footer.btcInfo.initializing=連接至比特幣網絡 mainView.footer.bsqInfo.synchronizing=正在同步 DAO -mainView.footer.btcInfo.synchronizingWith=正在同步至 -mainView.footer.btcInfo.synchronizedWith=Synced with -mainView.footer.btcInfo.connectingTo=連線至 -mainView.footer.btcInfo.connectionFailed=連線失敗: -mainView.footer.p2pInfo=Bitcoin network peers: {0} / Bisq network peers: {1} +mainView.footer.btcInfo.synchronizingWith=Synchronizing with {0} at block: {1} / {2} +mainView.footer.btcInfo.synchronizedWith=Synced with {0} at block {1} +mainView.footer.btcInfo.connectingTo=連接至 +mainView.footer.btcInfo.connectionFailed=連接失敗: +mainView.footer.p2pInfo=比特幣網絡節點:{0} / Bisq 網絡節點:{1} mainView.footer.daoFullNode=DAO 全節點 -mainView.bootstrapState.connectionToTorNetwork=(1/4) 連線至 Tor 網路... -mainView.bootstrapState.torNodeCreated=(2/4) Tor 節點已建立 -mainView.bootstrapState.hiddenServicePublished=(3/4) 隱藏的服務已釋出 -mainView.bootstrapState.initialDataReceived=(4/4) 初始資料已接收 +mainView.bootstrapState.connectionToTorNetwork=(1/4) 連接至 Tor 網絡... +mainView.bootstrapState.torNodeCreated=(2/4) Tor 節點已創建 +mainView.bootstrapState.hiddenServicePublished=(3/4) 隱藏的服務已發佈 +mainView.bootstrapState.initialDataReceived=(4/4) 初始數據已接收 mainView.bootstrapWarning.noSeedNodesAvailable=沒有可用的種子節點 mainView.bootstrapWarning.noNodesAvailable=沒有可用的種子節點和節點 -mainView.bootstrapWarning.bootstrappingToP2PFailed=啟動 Bisq 網路失敗 +mainView.bootstrapWarning.bootstrappingToP2PFailed=啟動 Bisq 網絡失敗 -mainView.p2pNetworkWarnMsg.noNodesAvailable=沒有可用種子節點或永久節點可請求資料。\n請檢查您的網際網路連線或嘗試重啟應用程式。 -mainView.p2pNetworkWarnMsg.connectionToP2PFailed=連線至 Bisq 網路失敗(錯誤報告:{0})。\n請檢查您的網際網路連線或嘗試重啟應用程式。 +mainView.p2pNetworkWarnMsg.noNodesAvailable=沒有可用種子節點或永久節點可請求數據。\n請檢查您的互聯網連接或嘗試重啟應用程序。 +mainView.p2pNetworkWarnMsg.connectionToP2PFailed=連接至 Bisq 網絡失敗(錯誤報吿:{0})。\n請檢查您的互聯網連接或嘗試重啟應用程序。 -mainView.walletServiceErrorMsg.timeout=比特幣網路連線超時。 -mainView.walletServiceErrorMsg.connectionError=錯誤:{0} 比特幣網路連線失敗。 +mainView.walletServiceErrorMsg.timeout=比特幣網絡連接超時。 +mainView.walletServiceErrorMsg.connectionError=錯誤:{0} 比特幣網絡連接失敗。 -mainView.walletServiceErrorMsg.rejectedTxException=交易被網路拒絕。\n\n{0} +mainView.walletServiceErrorMsg.rejectedTxException=交易被網絡拒絕。\n\n{0} -mainView.networkWarning.allConnectionsLost=您失去了所有與 {0} 網路節點的連線。\n您失去了網際網路連線或您的計算機處於待機狀態。 -mainView.networkWarning.localhostBitcoinLost=您丟失了與本地主機比特幣節點的連線。\n請重啟 Bisq 應用程式連線到其他比特幣節點或重新啟動主機比特幣節點。 +mainView.networkWarning.allConnectionsLost=您失去了所有與 {0} 網絡節點的連接。\n您失去了互聯網連接或您的計算機處於待機狀態。 +mainView.networkWarning.localhostBitcoinLost=您丟失了與本地主機比特幣節點的連接。\n請重啟 Bisq 應用程序連接到其他比特幣節點或重新啟動主機比特幣節點。 mainView.version.update=(有更新可用) @@ -311,7 +314,7 @@ market.spread.spreadColumn=差價 # TradesChartsView market.trades.nrOfTrades=交易:{0} market.trades.tooltip.volumeBar=數量:{0}\n交易序號:{1}\n日期:{2} -market.trades.tooltip.candle.open=開啟: +market.trades.tooltip.candle.open=打開: market.trades.tooltip.candle.close=關閉: market.trades.tooltip.candle.high=高: market.trades.tooltip.candle.low=低: @@ -323,7 +326,7 @@ market.trades.tooltip.candle.date=日期: # OfferView #################################################################### -offerbook.createOffer=建立報價 +offerbook.createOffer=創建報價 offerbook.takeOffer=接受報價 offerbook.takeOfferToBuy=接受報價來收購 {0} offerbook.takeOfferToSell=接受報價來出售 {0} @@ -336,63 +339,66 @@ offerbook.offerersAcceptedBankSeats=接受的銀行所在國家(買家):\n offerbook.availableOffers=可用報價 offerbook.filterByCurrency=以貨幣篩選 offerbook.filterByPaymentMethod=以支付方式篩選 -offerbook.timeSinceSigning=已驗證,從 -offerbook.timeSinceSigning.info=此賬戶已驗證,{0} -offerbook.timeSinceSigning.info.arbitrator=由仲裁員驗證,並可以驗證夥伴賬戶 -offerbook.timeSinceSigning.info.peer=由對方驗證,等待限制被解除 +offerbook.timeSinceSigning=賬户信息 +offerbook.timeSinceSigning.info=此賬户已驗證,{0} +offerbook.timeSinceSigning.info.arbitrator=由仲裁員驗證,並可以驗證夥伴賬户 +offerbook.timeSinceSigning.info.peer=由對方驗證,等待%d天限制被解除 offerbook.timeSinceSigning.info.peerLimitLifted=由對方驗證,限制被取消 -offerbook.timeSinceSigning.info.signer=由對方驗證,並可驗證對方賬戶(限制已取消) -offerbook.timeSinceSigning.info.banned=賬戶已被封禁 +offerbook.timeSinceSigning.info.signer=由對方驗證,並可驗證對方賬户(限制已取消) +offerbook.timeSinceSigning.info.banned=賬户已被封禁 offerbook.timeSinceSigning.daysSinceSigning={0} 天 offerbook.timeSinceSigning.daysSinceSigning.long=自驗證{0} offerbook.xmrAutoConf=是否開啟自動確認 -offerbook.timeSinceSigning.help=當您成功地完成與擁有已驗證付款帳戶的夥伴交易時,您的付款帳戶已驗證。\n{0} 天后,最初的 {1} 的限制解除以及你的賬戶可以驗證其他人的付款賬戶。 +offerbook.timeSinceSigning.help=當您成功地完成與擁有已驗證付款帳户的夥伴交易時,您的付款帳户已驗證。\n{0} 天后,最初的 {1} 的限制解除以及你的賬户可以驗證其他人的付款賬户。 offerbook.timeSinceSigning.notSigned=尚未驗證 +offerbook.timeSinceSigning.notSigned.ageDays={0} 天 offerbook.timeSinceSigning.notSigned.noNeed=N/A -shared.notSigned=此賬戶還沒有被驗證 -shared.notSigned.noNeed=此賬戶型別不適用驗證 +shared.notSigned=此賬户還沒有被驗證以及在{0}前創建 +shared.notSigned.noNeed=此賬户類型不適用驗證 +shared.notSigned.noNeedDays=此賬户類型不適用驗證且在{0}天創建 +shared.notSigned.noNeedAlts=數字貨幣不適用賬齡與簽名 offerbook.nrOffers=報價數量:{0} offerbook.volume={0}(最小 - 最大) offerbook.deposit=BTC 保證金(%) offerbook.deposit.help=交易雙方均已支付保證金確保這個交易正常進行。這會在交易完成時退還。 -offerbook.createOfferToBuy=建立新的報價來買入 {0} -offerbook.createOfferToSell=建立新的報價來賣出 {0} -offerbook.createOfferToBuy.withFiat=建立新的報價用 {1} 購買 {0} -offerbook.createOfferToSell.forFiat=建立新的報價以 {1} 出售 {0} -offerbook.createOfferToBuy.withCrypto=建立新的賣出報價 {0} (買入 {1}) -offerbook.createOfferToSell.forCrypto=建立新的買入報價 {0}(賣出 {1}) +offerbook.createOfferToBuy=創建新的報價來買入 {0} +offerbook.createOfferToSell=創建新的報價來賣出 {0} +offerbook.createOfferToBuy.withFiat=創建新的報價用 {1} 購買 {0} +offerbook.createOfferToSell.forFiat=創建新的報價以 {1} 出售 {0} +offerbook.createOfferToBuy.withCrypto=創建新的賣出報價 {0} (買入 {1}) +offerbook.createOfferToSell.forCrypto=創建新的買入報價 {0}(賣出 {1}) offerbook.takeOfferButton.tooltip=下單買入 {0} -offerbook.yesCreateOffer=是的,建立報價 -offerbook.setupNewAccount=設定新的交易賬戶 +offerbook.yesCreateOffer=是的,創建報價 +offerbook.setupNewAccount=設置新的交易賬户 offerbook.removeOffer.success=撤銷報價成功。 offerbook.removeOffer.failed=撤銷報價失敗:\n{0} offerbook.deactivateOffer.failed=報價停用失敗:\n{0} -offerbook.activateOffer.failed=報價釋出失敗:\n{0} +offerbook.activateOffer.failed=報價發佈失敗:\n{0} offerbook.withdrawFundsHint=您可以從 {0} 中撤回您支付的資金。 -offerbook.warning.noTradingAccountForCurrency.headline=選擇的貨幣沒有支付賬戶 -offerbook.warning.noTradingAccountForCurrency.msg=您選擇的貨幣還沒有建立支付賬戶。\n\n你想要用其他貨幣建立一個報價嗎? -offerbook.warning.noMatchingAccount.headline=沒有匹配的支付賬戶。 -offerbook.warning.noMatchingAccount.msg=這個報價使用了您未建立過的支付方式。\n\n你現在想要建立一個新的支付賬戶嗎? +offerbook.warning.noTradingAccountForCurrency.headline=選擇的貨幣沒有支付賬户 +offerbook.warning.noTradingAccountForCurrency.msg=您選擇的貨幣還沒有建立支付賬户。\n\n你想要用其他貨幣創建一個報價嗎? +offerbook.warning.noMatchingAccount.headline=沒有匹配的支付賬户。 +offerbook.warning.noMatchingAccount.msg=這個報價使用了您未創建過的支付方式。\n\n你現在想要創建一個新的支付賬户嗎? offerbook.warning.counterpartyTradeRestrictions=由於交易夥伴的交易限制,這個報價不能接受 -offerbook.warning.newVersionAnnouncement=使用這個版本的軟體,交易夥伴可以驗證和驗證彼此的支付帳戶,以建立一個可信的支付帳戶網路。\n\n交易成功後,您的支付帳戶將被驗證以及交易限制將在一定時間後解除(此時間基於驗證方法)。\n\n有關驗證帳戶的更多資訊,請參見文件 https://docs.bisq.network/payment-methods#account-signing +offerbook.warning.newVersionAnnouncement=使用這個版本的軟件,交易夥伴可以驗證和驗證彼此的支付帳户,以創建一個可信的支付帳户網絡。\n\n交易成功後,您的支付帳户將被驗證以及交易限制將在一定時間後解除(此時間基於驗證方法)。\n\n有關驗證帳户的更多信息,請參見文檔 https://docs.bisq.network/payment-methods#account-signing -popup.warning.tradeLimitDueAccountAgeRestriction.seller=基於以下標準的安全限制,允許的交易金額限制為 {0}:\n- 買方的帳目沒有由仲裁員或夥伴驗證\n- 買方帳戶自驗證之日起不足30天\n- 本報價的付款方式被認為存在銀行退款的風險\n\n{1} -popup.warning.tradeLimitDueAccountAgeRestriction.buyer=基於以下標準的安全限制,允許的交易金額限制為{0}:\n- 你的買家帳戶沒有由仲裁員或夥伴驗證\n- 自驗證你的帳戶以來的時間少於30天\n- 本報價的付款方式被認為存在銀行退款的風險\n\n{1} +popup.warning.tradeLimitDueAccountAgeRestriction.seller=基於以下標準的安全限制,允許的交易金額限制為 {0}:\n- 買方的帳目沒有由仲裁員或夥伴驗證\n- 買方帳户自驗證之日起不足30天\n- 本報價的付款方式被認為存在銀行退款的風險\n\n{1} +popup.warning.tradeLimitDueAccountAgeRestriction.buyer=基於以下標準的安全限制,允許的交易金額限制為{0}:\n- 你的買家帳户沒有由仲裁員或夥伴驗證\n- 自驗證你的帳户以來的時間少於30天\n- 本報價的付款方式被認為存在銀行退款的風險\n\n{1} -offerbook.warning.wrongTradeProtocol=該報價要求的軟體版本與您現在執行的版本不一致。\n\n請檢查您是否執行最新版本,或者是該報價使用者在使用一箇舊的版本。\n使用者不能與不相容的交易協議版本進行交易。 -offerbook.warning.userIgnored=您已新增該使用者的匿名地址在您的忽略列表裡。 +offerbook.warning.wrongTradeProtocol=該報價要求的軟件版本與您現在運行的版本不一致。\n\n請檢查您是否運行最新版本,或者是該報價用户在使用一箇舊的版本。\n用户不能與不兼容的交易協議版本進行交易。 +offerbook.warning.userIgnored=您已添加該用户的匿名地址在您的忽略列表裏。 offerbook.warning.offerBlocked=該報價被 Bisq 開發人員限制。\n接受該報價時,可能有一個未處理的漏洞導致了問題。 -offerbook.warning.currencyBanned=該報價中使用的貨幣被 Bisq 開發人員阻止。\n請訪問 Bisq 論壇瞭解更多資訊。 -offerbook.warning.paymentMethodBanned=該報價中使用的付款方式被 Bisq 開發人員阻止。\n請訪問 Bisq 論壇瞭解更多資訊。 +offerbook.warning.currencyBanned=該報價中使用的貨幣被 Bisq 開發人員阻止。\n請訪問 Bisq 論壇瞭解更多信息。 +offerbook.warning.paymentMethodBanned=該報價中使用的付款方式被 Bisq 開發人員阻止。\n請訪問 Bisq 論壇瞭解更多信息。 offerbook.warning.nodeBlocked=該交易者的匿名地址被 Bisq 開發人員限制。\n當獲取來自該交易者的報價,可能有一個未處理的漏洞導致了問題。 -offerbook.warning.requireUpdateToNewVersion=您的 Bisq 版本不再相容交易。\n請通過 https://bisq.network/downloads 更新到最新的 Bisq 版本。 +offerbook.warning.requireUpdateToNewVersion=您的 Bisq 版本不再兼容交易。\n請通過 https://bisq.network/downloads 更新到最新的 Bisq 版本。 offerbook.warning.offerWasAlreadyUsedInTrade=您不能吃單因為您已經完成了該操作。可能是你之前的吃單嘗試導致了交易失敗。 offerbook.info.sellAtMarketPrice=您會以市場價格進行出售(每分鐘更新) @@ -403,7 +409,7 @@ offerbook.info.sellAboveMarketPrice=您將以高於市場價 {0} 的價格進行 offerbook.info.buyBelowMarketPrice=您將以低於市場價 {0} 的價格進行支付(每分鐘更新) offerbook.info.buyAtFixedPrice=您會以這個固定價格購買。 offerbook.info.sellAtFixedPrice=您會以這個固定價格出售。 -offerbook.info.noArbitrationInUserLanguage=如有任何爭議,請注意此報價的仲裁將在 {0} 內處理。語言目前設定為{1}。 +offerbook.info.noArbitrationInUserLanguage=如有任何爭議,請注意此報價的仲裁將在 {0} 內處理。語言目前設置為{1}。 offerbook.info.roundedFiatVolume=金額四捨五入是為了增加您的交易隱私。 #################################################################### @@ -421,7 +427,7 @@ createOffer.securityDeposit.prompt=保證金 createOffer.fundsBox.title=為您的報價充值 createOffer.fundsBox.offerFee=掛單費 createOffer.fundsBox.networkFee=礦工手續費 -createOffer.fundsBox.placeOfferSpinnerInfo=正在釋出報價中... +createOffer.fundsBox.placeOfferSpinnerInfo=正在發佈報價中... createOffer.fundsBox.paymentLabel=Bisq 交易 ID {0} createOffer.fundsBox.fundsStructure=({0} 保證金,{1} 交易費,{2} 採礦費) createOffer.fundsBox.fundsStructure.BSQ=({0} 保證金,{1} 採礦費)+ {2} 交易費 @@ -435,34 +441,38 @@ createOffer.warning.sellBelowMarketPrice=由於您的價格是持續更新的, createOffer.warning.buyAboveMarketPrice=由於您的價格是持續更新的,因此您將始終支付高於市場價 {0}% 的價格。 createOffer.tradeFee.descriptionBTCOnly=掛單費 createOffer.tradeFee.descriptionBSQEnabled=選擇手續費幣種 -createOffer.tradeFee.fiatAndPercent=≈ {0} / {1} 交易數量 + +createOffer.triggerPrice.prompt=Set optional trigger price +createOffer.triggerPrice.label=Deactivate offer if market price is {0} +createOffer.triggerPrice.tooltip=As protecting against drastic price movements you can set a trigger price which deactivates the offer if the market price reaches that value. +createOffer.triggerPrice.invalid.tooLow=Value must be higher than {0} +createOffer.triggerPrice.invalid.tooHigh=Value must be lower than {0} # new entries createOffer.placeOfferButton=複審:報價掛單 {0} 比特幣 -createOffer.alreadyFunded=您已經為該報價充值了。\n您的資金已經劃轉到您的本地 Bisq 錢包並在“資金/提現”介面可以提現。 createOffer.createOfferFundWalletInfo.headline=為您的報價充值 # suppress inspection "TrailingSpacesInProperty" createOffer.createOfferFundWalletInfo.tradeAmount=- 交易數量:{0}\n -createOffer.createOfferFundWalletInfo.msg=這個報價您需要 {0} 作為保證金。\n\n這些資金保留在您的本地錢包並會被凍結到多重驗證保證金地址直到報價交易成功。\n\n總數量:{1}\n- 保證金:{2}\n- 掛單費:{3}\n- 礦工手續費:{4}\n\n您有兩種選項可以充值您的交易:\n- 使用您的 Bisq 錢包(方便,但交易可能會被連結到)或者\n- 從外部錢包轉入(或許這樣更隱祕一些)\n\n關閉此彈出視窗後,您將看到所有資金選項和詳細資訊。 +createOffer.createOfferFundWalletInfo.msg=這個報價您需要 {0} 作為保證金。\n\n這些資金保留在您的本地錢包並會被凍結到多重驗證保證金地址直到報價交易成功。\n\n總數量:{1}\n- 保證金:{2}\n- 掛單費:{3}\n- 礦工手續費:{4}\n\n您有兩種選項可以充值您的交易:\n- 使用您的 Bisq 錢包(方便,但交易可能會被鏈接到)或者\n- 從外部錢包轉入(或許這樣更隱祕一些)\n\n關閉此彈出窗口後,您將看到所有資金選項和詳細信息。 # only first part "An error occurred when placing the offer:" has been used before. We added now the rest (need update in existing translations!) -createOffer.amountPriceBox.error.message=提交報價發生錯誤:\n\n{0}\n\n沒有資金從您錢包中扣除。\n請檢查您的網際網路連線或嘗試重啟應用程式。 -createOffer.setAmountPrice=設定數量和價格 -createOffer.warnCancelOffer=您已經為該報價充值了。\n如果您想立即取消,您的資金將劃轉到您的本地 Bisq 錢包並在“資金/提現”介面可以提現。\n您確定要取消嗎? -createOffer.timeoutAtPublishing=釋出報價時產生了一個錯誤。 -createOffer.errorInfo=\n\n掛單費已經支付,在最壞的情況下,你會失去了這筆費用。 我們很抱歉,但請記住,這是一個很小的數量。\n請嘗試重新啟動應用程式並檢查您的網路連線,看看是否可以解決問題。 -createOffer.tooLowSecDeposit.warning=您設定的保證金低於推薦預設值 {0}。\n您確定要使用較低的保證金嗎? +createOffer.amountPriceBox.error.message=提交報價發生錯誤:\n\n{0}\n\n沒有資金從您錢包中扣除。\n請檢查您的互聯網連接或嘗試重啟應用程序。 +createOffer.setAmountPrice=設置數量和價格 +createOffer.warnCancelOffer=您已經為該報價充值了。\n如果您想立即取消,您的資金將劃轉到您的本地 Bisq 錢包並在“資金/提現”界面可以提現。\n您確定要取消嗎? +createOffer.timeoutAtPublishing=發佈報價時產生了一個錯誤。 +createOffer.errorInfo=\n\n掛單費已經支付,在最壞的情況下,你會失去了這筆費用。 我們很抱歉,但請記住,這是一個很小的數量。\n請嘗試重新啟動應用程序並檢查您的網絡連接,看看是否可以解決問題。 +createOffer.tooLowSecDeposit.warning=您設置的保證金低於推薦默認值 {0}。\n您確定要使用較低的保證金嗎? createOffer.tooLowSecDeposit.makerIsSeller=在交易對手不遵循交易協議時,這給予您較少的保護。 -createOffer.tooLowSecDeposit.makerIsBuyer=對於遵守交易協議的交易物件,您的保護金額較低,因為風險存款較小。 其他使用者可能更喜歡採取其他報價,而不是您的。 -createOffer.resetToDefault=不,恢復預設值 +createOffer.tooLowSecDeposit.makerIsBuyer=對於遵守交易協議的交易對象,您的保護金額較低,因為風險存款較小。 其他用户可能更喜歡採取其他報價,而不是您的。 +createOffer.resetToDefault=不,恢復默認值 createOffer.useLowerValue=是的,使用我較低的值 createOffer.priceOutSideOfDeviation=您輸入的價格超過了市場價差價的最大值。\n最大值為 {0},您可以在偏好中進行調整。 createOffer.changePrice=改變價格 -createOffer.tac=釋出該報價,我同意與滿足該條件的任何交易者進行交易。 +createOffer.tac=發佈該報價,我同意與滿足該條件的任何交易者進行交易。 createOffer.currencyForFee=掛單費 -createOffer.setDeposit=設定買家的保證金(%) -createOffer.setDepositAsBuyer=設定自己作為買家的保證金(%) -createOffer.setDepositForBothTraders=設定雙方的保證金比例(%) +createOffer.setDeposit=設置買家的保證金(%) +createOffer.setDepositAsBuyer=設置自己作為買家的保證金(%) +createOffer.setDepositForBothTraders=設置雙方的保證金比例(%) createOffer.securityDepositInfo=您的買家的保證金將會是 {0} createOffer.securityDepositInfoAsBuyer=您作為買家的保證金將會是 {0} createOffer.minSecurityDepositUsed=已使用最低買家保證金 @@ -478,7 +488,7 @@ takeOffer.amountPriceBox.sell.amountDescription=買入比特幣數量 takeOffer.amountPriceBox.priceDescription=每個比特幣的 {0} 價格 takeOffer.amountPriceBox.amountRangeDescription=可用數量範圍 takeOffer.amountPriceBox.warning.invalidBtcDecimalPlaces=你輸入的數量超過允許的小數位數。\n數量已被調整為4位小數。 -takeOffer.validation.amountSmallerThanMinAmount=數量不能比報價內設定的最小數量小。 +takeOffer.validation.amountSmallerThanMinAmount=數量不能比報價內設置的最小數量小。 takeOffer.validation.amountLargerThanOfferAmount=數量不能比報價提供的總量大。 takeOffer.validation.amountLargerThanOfferAmountMinusFee=該輸入數量可能會給賣家造成比特幣碎片。 takeOffer.fundsBox.title=為交易充值 @@ -490,43 +500,46 @@ takeOffer.fundsBox.takeOfferSpinnerInfo=正在下單... takeOffer.fundsBox.paymentLabel=Bisq 交易 ID {0} takeOffer.fundsBox.fundsStructure=({0} 保證金,{1} 交易費,{2} 採礦費) takeOffer.success.headline=你已成功下單一個報價。 -takeOffer.success.info=你可以在“業務/未完成交易”頁面內檢視您的未完成交易。 +takeOffer.success.info=你可以在“業務/未完成交易”頁面內查看您的未完成交易。 takeOffer.error.message=下單時發生了一個錯誤。\n\n{0} # new entries takeOffer.takeOfferButton=複審:報價下單 {0} 比特幣 takeOffer.noPriceFeedAvailable=您不能對這筆報價下單,因為它使用交易所價格百分比定價,但是您沒有獲得可用的價格。 -takeOffer.alreadyFunded.movedFunds=您已經為該報價值了。\n您的資金已經劃轉到您的本地 Bisq 錢包,並可以在“資金/提現”介面提現。 takeOffer.takeOfferFundWalletInfo.headline=為交易充值 # suppress inspection "TrailingSpacesInProperty" takeOffer.takeOfferFundWalletInfo.tradeAmount=- 交易數量:{0}\n -takeOffer.takeOfferFundWalletInfo.msg=這個報價您需要付出 {0} 保證金。\n\n這些資金保留在您的本地錢包並會被凍結到多重驗證保證金地址直到報價交易成功。\n\n總數量:{1}\n- 保證金:{2}\n- 掛單費:{3}\n- 礦工手續費:{4}\n\n您有兩種選項可以充值您的交易:\n- 使用您的 Bisq 錢包(方便,但交易可能會被連結到)或者\n- 從外部錢包轉入(或許這樣更隱祕一些)\n\n關閉此彈出視窗後,您將看到所有資金選項和詳細資訊。 +takeOffer.takeOfferFundWalletInfo.msg=這個報價您需要付出 {0} 保證金。\n\n這些資金保留在您的本地錢包並會被凍結到多重驗證保證金地址直到報價交易成功。\n\n總數量:{1}\n- 保證金:{2}\n- 掛單費:{3}\n- 礦工手續費:{4}\n\n您有兩種選項可以充值您的交易:\n- 使用您的 Bisq 錢包(方便,但交易可能會被鏈接到)或者\n- 從外部錢包轉入(或許這樣更隱祕一些)\n\n關閉此彈出窗口後,您將看到所有資金選項和詳細信息。 takeOffer.alreadyPaidInFunds=如果你已經支付,你可以在“資金/提現”提現它。 -takeOffer.paymentInfo=付款資訊 -takeOffer.setAmountPrice=設定數量 -takeOffer.alreadyFunded.askCancel=您已經為該報價充值了。\n如果您想立即取消,您的資金將劃轉到您的本地 Bisq 錢包並在“資金/提現”介面可以提現。\n您確定要取消嗎? +takeOffer.paymentInfo=付款信息 +takeOffer.setAmountPrice=設置數量 +takeOffer.alreadyFunded.askCancel=您已經為該報價充值了。\n如果您想立即取消,您的資金將劃轉到您的本地 Bisq 錢包並在“資金/提現”界面可以提現。\n您確定要取消嗎? takeOffer.failed.offerNotAvailable=請求失敗,由於報價不再可用。 也許有交易者在此期間已經下單。 takeOffer.failed.offerTaken=您不能對該報價下單,因為該報價已經被其他交易者下單。 takeOffer.failed.offerRemoved=您不能對該報價下單,因為該報價已經在此期間被刪除。 -takeOffer.failed.offererNotOnline=下單失敗,因為賣家已經不線上。 +takeOffer.failed.offererNotOnline=下單失敗,因為賣家已經不在線。 takeOffer.failed.offererOffline=您不能下單,因為賣家已經下線。 -takeOffer.warning.connectionToPeerLost=您與賣家失去連線。\n因為太多連線,他或許已經下線或者關掉了與您的連線。\n\n如果您還是能在報價列表中看到他的報價,您可以再次嘗試下單。 +takeOffer.warning.connectionToPeerLost=您與賣家失去連接。\n因為太多連接,他或許已經下線或者關掉了與您的連接。\n\n如果您還是能在報價列表中看到他的報價,您可以再次嘗試下單。 -takeOffer.error.noFundsLost=\n\n你的錢包裡還沒有錢。 \n請嘗試重啟您的應用程式或者檢查您的網路連線。 +takeOffer.error.noFundsLost=\n\n你的錢包裏還沒有錢。 \n請嘗試重啟您的應用程序或者檢查您的網絡連接。 # suppress inspection "TrailingSpacesInProperty" takeOffer.error.feePaid=\n!\n -takeOffer.error.depositPublished=\n\n您的保證金轉賬已經發布。\n請嘗試重啟您的應用程式或者檢查您的網路連線。\n如果始終存在問題,請到幫助介面聯絡開發者。 -takeOffer.error.payoutPublished=\n\n您的支付轉賬已經發布。\n請嘗試重啟您的應用程式或者檢查您的網路連線。\n如果始終存在問題,請到幫助介面聯絡開發者。 -takeOffer.tac=接受該報價,意味著我同意這交易介面中的條件。 +takeOffer.error.depositPublished=\n\n您的保證金轉賬已經發布。\n請嘗試重啟您的應用程序或者檢查您的網絡連接。\n如果始終存在問題,請到幫助界面聯繫開發者。 +takeOffer.error.payoutPublished=\n\n您的支付轉賬已經發布。\n請嘗試重啟您的應用程序或者檢查您的網絡連接。\n如果始終存在問題,請到幫助界面聯繫開發者。 +takeOffer.tac=接受該報價,意味着我同意這交易界面中的條件。 #################################################################### # Offerbook / Edit offer #################################################################### +openOffer.header.triggerPrice=觸發價格 +openOffer.triggerPrice=Trigger price {0} +openOffer.triggered=The offer has been deactivated because the market price reached your trigger price.\nPlease edit the offer to define a new trigger price + editOffer.setPrice=設定價格 editOffer.confirmEdit=確認:編輯報價 -editOffer.publishOffer=釋出您的報價。 +editOffer.publishOffer=發佈您的報價。 editOffer.failed=報價編輯失敗:\n{0} editOffer.success=您的報價已成功編輯。 editOffer.invalidDeposit=買方保證金不符合 Bisq DAO 規定,不能再次編輯。 @@ -541,7 +554,9 @@ portfolio.tab.history=歷史記錄 portfolio.tab.failed=失敗 portfolio.tab.editOpenOffer=編輯報價 -portfolio.pending.invalidDelayedPayoutTx=這裡有一個缺失或不可用交易導致的問題\n\n請不要傳送法幣或者任何數字貨幣。聯絡 Bisq 開發者在 Keybase 上 https://keybase.io/team/bisq 或者在論壇上https://bisq.community 以尋求更多協助。\n\n錯誤資訊:{0} +portfolio.closedTrades.deviation.help=Percentage price deviation from market + +portfolio.pending.invalidDelayedPayoutTx=這裏有一個缺失或不可用交易導致的問題\n\n請不要發送法幣或者任何數字貨幣。聯繫 Bisq 開發者在 Keybase 上 https://keybase.io/team/bisq 或者在論壇上https://bisq.community 以尋求更多協助。\n\n錯誤信息:{0} portfolio.pending.step1.waitForConf=等待區塊鏈確認 portfolio.pending.step2_buyer.startPayment=開始付款 @@ -553,10 +568,10 @@ portfolio.pending.step5.completed=完成 portfolio.pending.step3_seller.autoConf.status.label=自動確認狀態。 portfolio.pending.autoConf=自動確認 portfolio.pending.autoConf.blocks=XMR 確認數:{0} / 需求量:{2} -portfolio.pending.autoConf.state.xmr.txKeyReused=交易金鑰已重複使用。請發起糾紛處理。 +portfolio.pending.autoConf.state.xmr.txKeyReused=交易密鑰已重複使用。請發起糾紛處理。 portfolio.pending.autoConf.state.confirmations=XMR 確認:{0}/{1} -portfolio.pending.autoConf.state.txNotFound=交易並未在記憶體池中檢索。 -portfolio.pending.autoConf.state.txKeyOrTxIdInvalid=無有效交易 ID / 交易金鑰 +portfolio.pending.autoConf.state.txNotFound=交易並未在內存池中檢索。 +portfolio.pending.autoConf.state.txKeyOrTxIdInvalid=無有效交易 ID / 交易密鑰 portfolio.pending.autoConf.state.filterDisabledFeature=由開發者禁用 # suppress inspection "UnusedProperty" @@ -564,7 +579,7 @@ portfolio.pending.autoConf.state.FEATURE_DISABLED=自動確認功能已禁用。 # suppress inspection "UnusedProperty" portfolio.pending.autoConf.state.TRADE_LIMIT_EXCEEDED=交易金額超過自動確認金額限制。 # suppress inspection "UnusedProperty" -portfolio.pending.autoConf.state.INVALID_DATA=對等點提供不可用資料。{0} +portfolio.pending.autoConf.state.INVALID_DATA=對等點提供不可用數據。{0} # suppress inspection "UnusedProperty" portfolio.pending.autoConf.state.PAYOUT_TX_ALREADY_PUBLISHED=支付交易已經發布 # suppress inspection "UnusedProperty" @@ -582,16 +597,16 @@ portfolio.pending.autoConf.state.FAILED=服務返回失敗。沒有自動確認 portfolio.pending.step1.info=存款交易已經發布。\n開始付款之前,{0} 需要等待至少一個區塊鏈確認。 portfolio.pending.step1.warn=保證金交易仍未得到確認。這種情況可能會發生在外部錢包轉賬時使用的交易手續費用較低造成的。 -portfolio.pending.step1.openForDispute=保證金交易仍未得到確認。請聯絡調解員協助。 +portfolio.pending.step1.openForDispute=保證金交易仍未得到確認。請聯繫調解員協助。 # suppress inspection "TrailingSpacesInProperty" portfolio.pending.step2.confReached=您的交易已經達到至少一個區塊鏈確認。\n(如果需要,您可以等待更多的確認 - 6個確認被認為是非常安全的。)\n\n -portfolio.pending.step2_buyer.copyPaste=(您可以在關閉該彈出視窗後從主介面複製並貼上值。) -portfolio.pending.step2_buyer.refTextWarn=不要在比特幣、BTC 或 Bisq 的“付款原因”文字里新增任何提示。 +portfolio.pending.step2_buyer.copyPaste=(您可以在關閉該彈出窗口後從主界面複製並粘貼值。) +portfolio.pending.step2_buyer.refTextWarn=不要在比特幣、BTC 或 Bisq 的“付款原因”文本里添加任何提示。 # suppress inspection "TrailingSpacesInProperty" -portfolio.pending.step2_buyer.accountDetails=以下是 BTC 賣家的交易賬戶詳細資訊:\n -portfolio.pending.step2_buyer.tradeId=請不要忘記新增交易 ID +portfolio.pending.step2_buyer.accountDetails=以下是 BTC 賣家的交易賬户詳細信息:\n +portfolio.pending.step2_buyer.tradeId=請不要忘記添加交易 ID # suppress inspection "TrailingSpacesInProperty" portfolio.pending.step2_buyer.assign=作為“付款原因”,這樣接收方可以將您的付款分配給對應的交易。\n portfolio.pending.step2_buyer.fees=如果您的銀行收取費用,您必須支付這些費用。 @@ -599,104 +614,104 @@ portfolio.pending.step2_buyer.fees=如果您的銀行收取費用,您必須支 portfolio.pending.step2_buyer.altcoin=請從您的外部 {0} 錢包劃轉\n{1} 到 BTC 賣家。\n\n # suppress inspection "TrailingSpacesInProperty" portfolio.pending.step2_buyer.cash=請到銀行並支付 {0} 給 BTC 賣家。\n\n -portfolio.pending.step2_buyer.cash.extra=重要要求:\n完成付款後在紙質收據上寫下:不退款。\n然後將其撕成2份,拍照片併傳送給 BTC 賣家的電子郵件地址。 +portfolio.pending.step2_buyer.cash.extra=重要要求:\n完成付款後在紙質收據上寫下:不退款。\n然後將其撕成2份,拍照片併發送給 BTC 賣家的電子郵件地址。 # suppress inspection "TrailingSpacesInProperty" portfolio.pending.step2_buyer.moneyGram=請使用 MoneyGram 向 BTC 賣家支付 {0}。\n\n -portfolio.pending.step2_buyer.moneyGram.extra=重要要求:\n完成支付後,請通過電郵傳送授權編號和照片給 BTC 賣家。\n收據必須清楚地向賣家寫明您的全名、城市、國家或地區、數量。賣方的電子郵件是:{0}。 +portfolio.pending.step2_buyer.moneyGram.extra=重要要求:\n完成支付後,請通過電郵發送授權編號和照片給 BTC 賣家。\n收據必須清楚地向賣家寫明您的全名、城市、國家或地區、數量。賣方的電子郵件是:{0}。 # suppress inspection "TrailingSpacesInProperty" portfolio.pending.step2_buyer.westernUnion=請使用 Western Union 向 BTC 賣家支付 {0}。\n\n -portfolio.pending.step2_buyer.westernUnion.extra=重要要求:\n完成支付後,請通過電郵傳送 MTCN(追蹤號碼)和照片給 BTC 賣家。\n收據必須清楚地向賣家寫明您的全名、城市、國家或地區、數量。賣方的電子郵件是:{0}。 +portfolio.pending.step2_buyer.westernUnion.extra=重要要求:\n完成支付後,請通過電郵發送 MTCN(追蹤號碼)和照片給 BTC 賣家。\n收據必須清楚地向賣家寫明您的全名、城市、國家或地區、數量。賣方的電子郵件是:{0}。 # suppress inspection "TrailingSpacesInProperty" -portfolio.pending.step2_buyer.amazonGiftCard=Please purchase an Amazon eGift Card for {0} at your Amazon account and use the BTC seller''s email or mobile number as receiver. In case the trade amount exceeds the permitted amount send multiple cards.\n\n +portfolio.pending.step2_buyer.amazonGiftCard=請使用您的賬户購買{0}亞馬遜電子禮品卡並使用 BTC 賣家的郵箱或手機號作為接收方。如果交易額超過允許的數量請發送多個禮品卡。\n\n # suppress inspection "TrailingSpacesInProperty" -portfolio.pending.step2_buyer.postal=請用“美國郵政匯票”傳送 {0} 給 BTC 賣家。\n\n +portfolio.pending.step2_buyer.postal=請用“美國郵政匯票”發送 {0} 給 BTC 賣家。\n\n # suppress inspection "TrailingSpacesInProperty" -portfolio.pending.step2_buyer.bank=請到您的線上銀行網頁並支付 {0} 給 BTC 賣家。\n\n +portfolio.pending.step2_buyer.bank=請到您的在線銀行網頁並支付 {0} 給 BTC 賣家。\n\n # suppress inspection "TrailingSpacesInProperty" -portfolio.pending.step2_buyer.f2f=請通過提供的聯絡人與 BTC 賣家聯絡,並安排會議支付 {0}。\n\n +portfolio.pending.step2_buyer.f2f=請通過提供的聯繫人與 BTC 賣家聯繫,並安排會議支付 {0}。\n\n portfolio.pending.step2_buyer.startPaymentUsing=使用 {0} 開始付款 portfolio.pending.step2_buyer.recipientsAccountData=接受 {0} portfolio.pending.step2_buyer.amountToTransfer=劃轉數量 portfolio.pending.step2_buyer.sellersAddress=賣家的 {0} 地址 -portfolio.pending.step2_buyer.buyerAccount=您的付款帳戶將被使用 +portfolio.pending.step2_buyer.buyerAccount=您的付款帳户將被使用 portfolio.pending.step2_buyer.paymentStarted=付款開始 portfolio.pending.step2_buyer.warn=你還沒有完成你的 {0} 付款!\n請注意,交易必須在 {1} 之前完成。 -portfolio.pending.step2_buyer.openForDispute=您還沒有完成您的付款!\n最大交易期限已過。請聯絡調解員尋求幫助。 -portfolio.pending.step2_buyer.paperReceipt.headline=您是否將紙質收據傳送給 BTC 賣家? -portfolio.pending.step2_buyer.paperReceipt.msg=請牢記:\n完成付款後在紙質收據上寫下:不退款。\n然後將其撕成2份,拍照片併傳送給 BTC 賣家的電子郵件地址。 -portfolio.pending.step2_buyer.moneyGramMTCNInfo.headline=傳送授權編號和收據 -portfolio.pending.step2_buyer.moneyGramMTCNInfo.msg=請通過電郵傳送授權編號和照片給 BTC 賣家。\n收據必須清楚地向賣家寫明您的全名、城市、國家或地區、數量。賣方的電子郵件是:{0}。\n\n您把授權編號和合同發給賣方了嗎? -portfolio.pending.step2_buyer.westernUnionMTCNInfo.headline=傳送 MTCN 和收據 -portfolio.pending.step2_buyer.westernUnionMTCNInfo.msg=請通過電郵傳送 MTCN(追蹤號碼)和照片給 BTC 賣家。\n收據必須清楚地向賣家寫明您的全名、城市、國家或地區、數量。賣方的電子郵件是:{0}。\n\n您把 MTCN 和合同發給賣方了嗎? -portfolio.pending.step2_buyer.halCashInfo.headline=請傳送 HalCash 程式碼 -portfolio.pending.step2_buyer.halCashInfo.msg=您需要向 BTC 賣家傳送帶有 HalCash 程式碼和交易 ID({0})的文字訊息。\n\n賣方的手機號碼是 {1} 。\n\n您是否已經將程式碼傳送至賣家? -portfolio.pending.step2_buyer.fasterPaymentsHolderNameInfo=有些銀行可能會要求接收方的姓名。在較舊的 Bisq 客戶端建立的快速支付帳戶沒有提供收款人的姓名,所以請使用交易聊天來獲得收款人姓名(如果需要)。 +portfolio.pending.step2_buyer.openForDispute=您還沒有完成您的付款!\n最大交易期限已過。請聯繫調解員尋求幫助。 +portfolio.pending.step2_buyer.paperReceipt.headline=您是否將紙質收據發送給 BTC 賣家? +portfolio.pending.step2_buyer.paperReceipt.msg=請牢記:\n完成付款後在紙質收據上寫下:不退款。\n然後將其撕成2份,拍照片併發送給 BTC 賣家的電子郵件地址。 +portfolio.pending.step2_buyer.moneyGramMTCNInfo.headline=發送授權編號和收據 +portfolio.pending.step2_buyer.moneyGramMTCNInfo.msg=請通過電郵發送授權編號和照片給 BTC 賣家。\n收據必須清楚地向賣家寫明您的全名、城市、國家或地區、數量。賣方的電子郵件是:{0}。\n\n您把授權編號和合同發給賣方了嗎? +portfolio.pending.step2_buyer.westernUnionMTCNInfo.headline=發送 MTCN 和收據 +portfolio.pending.step2_buyer.westernUnionMTCNInfo.msg=請通過電郵發送 MTCN(追蹤號碼)和照片給 BTC 賣家。\n收據必須清楚地向賣家寫明您的全名、城市、國家或地區、數量。賣方的電子郵件是:{0}。\n\n您把 MTCN 和合同發給賣方了嗎? +portfolio.pending.step2_buyer.halCashInfo.headline=請發送 HalCash 代碼 +portfolio.pending.step2_buyer.halCashInfo.msg=您需要向 BTC 賣家發送帶有 HalCash 代碼和交易 ID({0})的文本消息。\n\n賣方的手機號碼是 {1} 。\n\n您是否已經將代碼發送至賣家? +portfolio.pending.step2_buyer.fasterPaymentsHolderNameInfo=有些銀行可能會要求接收方的姓名。在較舊的 Bisq 客户端創建的快速支付帳户沒有提供收款人的姓名,所以請使用交易聊天來獲得收款人姓名(如果需要)。 portfolio.pending.step2_buyer.confirmStart.headline=確定您已經付款 portfolio.pending.step2_buyer.confirmStart.msg=您是否向您的交易夥伴發起 {0} 付款? portfolio.pending.step2_buyer.confirmStart.yes=是的,我已經開始付款 portfolio.pending.step2_buyer.confirmStart.proof.warningTitle=你沒有提供任何付款證明 -portfolio.pending.step2_buyer.confirmStart.proof.noneProvided=您還沒有輸入交易 ID 以及交易金鑰\n\n如果不提供此資料您的交易夥伴無法在收到 XMR 後使用自動確認功能以快速釋放 BTC。\n另外,Bisq 要求 XMR 傳送者在發生糾紛的時候能夠向調解員和仲裁員提供這些資訊。\n更多細節在 Bisq Wiki:https://bisq.wiki/Trading_Monero#Auto-confirming_trades -portfolio.pending.step2_buyer.confirmStart.proof.invalidInput=輸入並不是一個 32 位元組的雜湊值 +portfolio.pending.step2_buyer.confirmStart.proof.noneProvided=您還沒有輸入交易 ID 以及交易密鑰\n\n如果不提供此數據您的交易夥伴無法在收到 XMR 後使用自動確認功能以快速釋放 BTC。\n另外,Bisq 要求 XMR 發送者在發生糾紛的時候能夠向調解員和仲裁員提供這些信息。\n更多細節在 Bisq Wiki:https://bisq.wiki/Trading_Monero#Auto-confirming_trades +portfolio.pending.step2_buyer.confirmStart.proof.invalidInput=輸入並不是一個 32 字節的哈希值 portfolio.pending.step2_buyer.confirmStart.warningButton=忽略並繼續 portfolio.pending.step2_seller.waitPayment.headline=等待付款 -portfolio.pending.step2_seller.f2fInfo.headline=買家的合同資訊 +portfolio.pending.step2_seller.f2fInfo.headline=買家的合同信息 portfolio.pending.step2_seller.waitPayment.msg=存款交易至少有一個區塊鏈確認。\n您需要等到 BTC 買家開始 {0} 付款。 portfolio.pending.step2_seller.warn=BTC 買家仍然沒有完成 {0} 付款。\n你需要等到他開始付款。\n如果 {1} 交易尚未完成,仲裁員將進行調查。 -portfolio.pending.step2_seller.openForDispute=BTC 買家尚未開始付款!\n允許的最長交易期限已經過去了。你可以繼續等待給予交易雙方更多時間,或聯絡仲裁員以爭取解決糾紛。 -tradeChat.chatWindowTitle=使用 ID “{0}” 進行交易的聊天視窗 -tradeChat.openChat=開啟聊天視窗 -tradeChat.rules=您可以與您的夥伴溝通,以解決該交易的潛在問題。\n在聊天中不強制回覆。\n如果交易員違反了下面的任何規則,開啟糾紛並向調解員或仲裁員報告。\n聊天規則:\n\n\t●不要傳送任何連結(有惡意軟體的風險)。您可以傳送交易 ID 和區塊資源管理器的名稱。\n\t●不要傳送還原金鑰、私鑰、密碼或其他敏感資訊!\n\t●不鼓勵 Bisq 以外的交易(無安全保障)。\n\t●不要參與任何形式的危害社會安全的計劃。\n\t●如果對方沒有迴應,也不願意通過聊天進行溝通,那就尊重對方的決定。\n\t●將談話範圍限制在行業內。這個聊天不是一個社交軟體替代品或troll-box。\n\t●保持友好和尊重的交談。 +portfolio.pending.step2_seller.openForDispute=BTC 買家尚未開始付款!\n允許的最長交易期限已經過去了。你可以繼續等待給予交易雙方更多時間,或聯繫仲裁員以爭取解決糾紛。 +tradeChat.chatWindowTitle=使用 ID “{0}” 進行交易的聊天窗口 +tradeChat.openChat=打開聊天窗口 +tradeChat.rules=您可以與您的夥伴溝通,以解決該交易的潛在問題。\n在聊天中不強制回覆。\n如果交易員違反了下面的任何規則,打開糾紛並向調解員或仲裁員報吿。\n聊天規則:\n\n\t●不要發送任何鏈接(有惡意軟件的風險)。您可以發送交易 ID 和區塊資源管理器的名稱。\n\t●不要發送還原密鑰、私鑰、密碼或其他敏感信息!\n\t●不鼓勵 Bisq 以外的交易(無安全保障)。\n\t●不要參與任何形式的危害社會安全的計劃。\n\t●如果對方沒有迴應,也不願意通過聊天進行溝通,那就尊重對方的決定。\n\t●將談話範圍限制在行業內。這個聊天不是一個社交軟件替代品或troll-box。\n\t●保持友好和尊重的交談。 # suppress inspection "UnusedProperty" message.state.UNDEFINED=未定義 # suppress inspection "UnusedProperty" -message.state.SENT=發出資訊 +message.state.SENT=發出信息 # suppress inspection "UnusedProperty" -message.state.ARRIVED=訊息已抵達 +message.state.ARRIVED=消息已抵達 # suppress inspection "UnusedProperty" -message.state.STORED_IN_MAILBOX=已傳送但尚未被對方接收的付款資訊 +message.state.STORED_IN_MAILBOX=已發送但尚未被對方接收的付款信息 # suppress inspection "UnusedProperty" -message.state.ACKNOWLEDGED=對方確認訊息回執 +message.state.ACKNOWLEDGED=對方確認消息回執 # suppress inspection "UnusedProperty" -message.state.FAILED=傳送訊息失敗 +message.state.FAILED=發送消息失敗 portfolio.pending.step3_buyer.wait.headline=等待 BTC 賣家付款確定 portfolio.pending.step3_buyer.wait.info=等待 BTC 賣家確認收到 {0} 付款。 -portfolio.pending.step3_buyer.wait.msgStateInfo.label=支付開始訊息狀態 +portfolio.pending.step3_buyer.wait.msgStateInfo.label=支付開始消息狀態 portfolio.pending.step3_buyer.warn.part1a=在 {0} 區塊鏈 portfolio.pending.step3_buyer.warn.part1b=在您的支付供應商(例如:銀行) -portfolio.pending.step3_buyer.warn.part2=BTC 賣家仍然沒有確認您的付款。如果付款傳送成功,請檢查 {0}。 +portfolio.pending.step3_buyer.warn.part2=BTC 賣家仍然沒有確認您的付款。如果付款發送成功,請檢查 {0}。 portfolio.pending.step3_buyer.openForDispute=BTC 賣家還沒有確認你的付款!最大交易期限已過。您可以等待更長時間,並給交易夥伴更多時間或請求調解員的幫助。 # suppress inspection "TrailingSpacesInProperty" portfolio.pending.step3_seller.part=您的交易夥伴已經確認他們已經發起了 {0} 付款。\n\n portfolio.pending.step3_seller.altcoin.explorer=在您最喜歡的 {0} 區塊鏈瀏覽器 portfolio.pending.step3_seller.altcoin.wallet=在您的 {0} 錢包 -portfolio.pending.step3_seller.altcoin={0} 請檢查 {1} 是否交易已經到您的接收地址\n{2}\n已經有足夠的區塊鏈確認了\n支付金額必須為 {3}\n\n關閉該彈出視窗後,您可以從主介面複製並貼上 {4} 地址。 -portfolio.pending.step3_seller.postal={0} 請檢查您是否已經從 BTC 買家收到了 {1} “美國郵政匯票”。\n\n交易 ID(“付款原因”文字)是:“{2}” +portfolio.pending.step3_seller.altcoin={0} 請檢查 {1} 是否交易已經到您的接收地址\n{2}\n已經有足夠的區塊鏈確認了\n支付金額必須為 {3}\n\n關閉該彈出窗口後,您可以從主界面複製並粘貼 {4} 地址。 +portfolio.pending.step3_seller.postal={0} 請檢查您是否已經從 BTC 買家收到了 {1} “美國郵政匯票”。\n\n交易 ID(“付款原因”文本)是:“{2}” # suppress inspection "TrailingSpacesInProperty" -portfolio.pending.step3_seller.bank=您的交易物件已確認他已啟動 {0} 付款\n\n請訪問您的網上銀行網頁,並檢查您是否已從 BTC 買家收到 {1}\n\n交易 ID(“付款原因”文字)是:“{2}”\n\n -portfolio.pending.step3_seller.cash=因為付款是通過現金存款完成的,BTC 買家必須在紙質收據上寫“不退款”,將其撕成2份,並通過電子郵件向您傳送照片。\n\n為避免退款風險,請僅確認您是否收到電子郵件,如果您確定收據有效。\n如果您不確定,{0} -portfolio.pending.step3_seller.moneyGram=買方必鬚髮送授權編碼和一張收據的照片。\n收據必須清楚地顯示您的全名、城市、國家或地區、數量。如果您收到授權編碼,請查收郵件。\n\n關閉彈窗後,您將看到 BTC 買家的姓名和在 MoneyGram 的收款地址。\n\n只有在您成功收到錢之後,再確認收據! -portfolio.pending.step3_seller.westernUnion=買方必鬚髮送 MTCN(跟蹤號碼)和一張收據的照片。\n收據必須清楚地顯示您的全名、城市、國家或地區、數量。如果您收到 MTCN,請查收郵件。\n\n關閉彈窗後,您將看到 BTC 買家的姓名和在 Western Union 的收款地址。\n\n只有在您成功收到錢之後,再確認收據! -portfolio.pending.step3_seller.halCash=買方必須將 HalCash程式碼 用簡訊傳送給您。除此之外,您將收到來自 HalCash 的訊息,其中包含從支援 HalCash 的 ATM 中提取歐元所需的資訊\n從 ATM 取款後,請在此確認付款收據! -portfolio.pending.step3_seller.amazonGiftCard=The buyer has sent you an Amazon eGift Card by email or by text message to your mobile phone. Please redeem now the Amazon eGift Card at your Amazon account and once accepted confirm the payment receipt. +portfolio.pending.step3_seller.bank=您的交易對象已確認他已啟動 {0} 付款\n\n請訪問您的網上銀行網頁,並檢查您是否已從 BTC 買家收到 {1}\n\n交易 ID(“付款原因”文本)是:“{2}”\n\n +portfolio.pending.step3_seller.cash=因為付款是通過現金存款完成的,BTC 買家必須在紙質收據上寫“不退款”,將其撕成2份,並通過電子郵件向您發送照片。\n\n為避免退款風險,請僅確認您是否收到電子郵件,如果您確定收據有效。\n如果您不確定,{0} +portfolio.pending.step3_seller.moneyGram=買方必須發送授權編碼和一張收據的照片。\n收據必須清楚地顯示您的全名、城市、國家或地區、數量。如果您收到授權編碼,請查收郵件。\n\n關閉彈窗後,您將看到 BTC 買家的姓名和在 MoneyGram 的收款地址。\n\n只有在您成功收到錢之後,再確認收據! +portfolio.pending.step3_seller.westernUnion=買方必須發送 MTCN(跟蹤號碼)和一張收據的照片。\n收據必須清楚地顯示您的全名、城市、國家或地區、數量。如果您收到 MTCN,請查收郵件。\n\n關閉彈窗後,您將看到 BTC 買家的姓名和在 Western Union 的收款地址。\n\n只有在您成功收到錢之後,再確認收據! +portfolio.pending.step3_seller.halCash=買方必須將 HalCash代碼 用短信發送給您。除此之外,您將收到來自 HalCash 的消息,其中包含從支持 HalCash 的 ATM 中提取歐元所需的信息\n從 ATM 取款後,請在此確認付款收據! +portfolio.pending.step3_seller.amazonGiftCard=BTC 買家已經發送了一張亞馬遜電子禮品卡到您的郵箱或手機短信。請現在立即兑換亞馬遜電子禮品卡到您的亞馬遜賬户中以及確認交易信息。 portfolio.pending.step3_seller.bankCheck=\n\n還請確認您的銀行對帳單中的發件人姓名與委託合同中的發件人姓名相符:\n發件人姓名:{0}\n\n如果名稱與此處顯示的名稱不同,則 {1} # suppress inspection "TrailingSpacesInProperty" -portfolio.pending.step3_seller.openDispute=請不要確認,而是通過鍵盤組合鍵“alt + o”或“option + o”來開啟糾紛。 +portfolio.pending.step3_seller.openDispute=請不要確認,而是通過鍵盤組合鍵“alt + o”或“option + o”來打開糾紛。 portfolio.pending.step3_seller.confirmPaymentReceipt=確定付款收據 portfolio.pending.step3_seller.amountToReceive=接收數量: portfolio.pending.step3_seller.yourAddress=您的 {0} 地址 portfolio.pending.step3_seller.buyersAddress=賣家的 {0} 地址 -portfolio.pending.step3_seller.yourAccount=您的交易賬戶 +portfolio.pending.step3_seller.yourAccount=您的交易賬户 portfolio.pending.step3_seller.xmrTxHash=交易記錄 ID -portfolio.pending.step3_seller.xmrTxKey=交易金鑰 -portfolio.pending.step3_seller.buyersAccount=買方賬號資料 +portfolio.pending.step3_seller.xmrTxKey=交易密鑰 +portfolio.pending.step3_seller.buyersAccount=買方賬號數據 portfolio.pending.step3_seller.confirmReceipt=確定付款收據 portfolio.pending.step3_seller.buyerStartedPayment=BTC 買家已經開始 {0} 的付款。\n{1} portfolio.pending.step3_seller.buyerStartedPayment.altcoin=檢查您的數字貨幣錢包或塊瀏覽器的區塊鏈確認,並確認付款時,您有足夠的塊鏈確認。 -portfolio.pending.step3_seller.buyerStartedPayment.fiat=檢查您的交易賬戶(例如銀行帳戶),並確認您何時收到付款。 +portfolio.pending.step3_seller.buyerStartedPayment.fiat=檢查您的交易賬户(例如銀行帳户),並確認您何時收到付款。 portfolio.pending.step3_seller.warn.part1a=在 {0} 區塊鏈 portfolio.pending.step3_seller.warn.part1b=在您的支付供應商(例如:銀行) portfolio.pending.step3_seller.warn.part2=你還沒有確認收到款項。如果您已經收到款項,請檢查 {0}。 @@ -704,14 +719,14 @@ portfolio.pending.step3_seller.openForDispute=您尚未確認付款的收據!\ # suppress inspection "TrailingSpacesInProperty" portfolio.pending.step3_seller.onPaymentReceived.part1=您是否收到了您交易夥伴的 {0} 付款?\n\n # suppress inspection "TrailingSpacesInProperty" -portfolio.pending.step3_seller.onPaymentReceived.fiat=交易 ID(“付款理由”文字)是“{0}”\n\n +portfolio.pending.step3_seller.onPaymentReceived.fiat=交易 ID(“付款理由”文本)是“{0}”\n\n # suppress inspection "TrailingSpacesInProperty" -portfolio.pending.step3_seller.onPaymentReceived.name=還請確認您的銀行對帳單中的發件人姓名與委託合同中的發件人姓名相符:\n每個交易合約的傳送者姓名:{0}\n\n如果名稱與此處顯示的名稱不一致,請不要通過確認付款,而是通過“alt + o”或“option + o”開啟糾紛。\n\n +portfolio.pending.step3_seller.onPaymentReceived.name=還請確認您的銀行對帳單中的發件人姓名與委託合同中的發件人姓名相符:\n每個交易合約的發送者姓名:{0}\n\n如果名稱與此處顯示的名稱不一致,請不要通過確認付款,而是通過“alt + o”或“option + o”打開糾紛。\n\n # suppress inspection "TrailingSpacesInProperty" portfolio.pending.step3_seller.onPaymentReceived.note=請注意,一旦您確認收到,凍結交易金額將被髮放給 BTC 買家,保證金將被退還。 portfolio.pending.step3_seller.onPaymentReceived.confirm.headline=確定您已經收到付款 portfolio.pending.step3_seller.onPaymentReceived.confirm.yes=是的,我已經收到付款。 -portfolio.pending.step3_seller.onPaymentReceived.signer=重要提示:通過確認收到付款,你也驗證了對方的賬戶,並獲得驗證。因為對方的賬戶還沒有驗證,所以你應該儘可能的延遲付款的確認,以減少退款的風險。 +portfolio.pending.step3_seller.onPaymentReceived.signer=重要提示:通過確認收到付款,你也驗證了對方的賬户,並獲得驗證。因為對方的賬户還沒有驗證,所以你應該儘可能的延遲付款的確認,以減少退款的風險。 portfolio.pending.step5_buyer.groupTitle=完成交易的概要 portfolio.pending.step5_buyer.tradeFee=掛單費 @@ -723,11 +738,11 @@ portfolio.pending.step5_buyer.amount=提現數量 portfolio.pending.step5_buyer.withdrawToAddress=提現地址 portfolio.pending.step5_buyer.moveToBisqWallet=在 Bisq 錢包中保留資金 portfolio.pending.step5_buyer.withdrawExternal=提現到外部錢包 -portfolio.pending.step5_buyer.alreadyWithdrawn=您的資金已經提現。\n請檢視交易歷史記錄。 +portfolio.pending.step5_buyer.alreadyWithdrawn=您的資金已經提現。\n請查看交易歷史記錄。 portfolio.pending.step5_buyer.confirmWithdrawal=確定提現請求 portfolio.pending.step5_buyer.amountTooLow=轉讓金額低於交易費用和最低可能的tx值(零頭)。 portfolio.pending.step5_buyer.withdrawalCompleted.headline=提現完成 -portfolio.pending.step5_buyer.withdrawalCompleted.msg=您完成的交易儲存在“業務/歷史記錄”下。\n您可以檢視“資金/交易”下的所有比特幣交易 +portfolio.pending.step5_buyer.withdrawalCompleted.msg=您完成的交易存儲在“業務/歷史記錄”下。\n您可以查看“資金/交易”下的所有比特幣交易 portfolio.pending.step5_buyer.bought=您已經買入 portfolio.pending.step5_buyer.paid=您已經支付 @@ -735,69 +750,69 @@ portfolio.pending.step5_seller.sold=您已經賣出 portfolio.pending.step5_seller.received=您已經收到 tradeFeedbackWindow.title=恭喜您完成交易 -tradeFeedbackWindow.msg.part1=我們很想聽聽您的體驗如何。這將幫助我們改進軟體,優化體驗不好的地方。如欲提供意見,請填寫這份簡短的問卷(無需註冊),網址: -tradeFeedbackWindow.msg.part2=如果您有任何疑問或遇到任何問題,請通過 Bisq 論壇與其他使用者和貢獻者聯絡: +tradeFeedbackWindow.msg.part1=我們很想聽聽您的體驗如何。這將幫助我們改進軟件,優化體驗不好的地方。如欲提供意見,請填寫這份簡短的問卷(無需註冊),網址: +tradeFeedbackWindow.msg.part2=如果您有任何疑問或遇到任何問題,請通過 Bisq 論壇與其他用户和貢獻者聯繫: tradeFeedbackWindow.msg.part3=感謝使用 Bisq portfolio.pending.role=我的角色 -portfolio.pending.tradeInformation=交易資訊 +portfolio.pending.tradeInformation=交易信息 portfolio.pending.remainingTime=剩餘時間 portfolio.pending.remainingTimeDetail={0}(直到 {1} ) portfolio.pending.tradePeriodInfo=在第一次區塊鏈確認之後,交易週期開始。根據所使用的付款方法,採用不同的最大允許交易週期。 portfolio.pending.tradePeriodWarning=如果超過了這個週期,雙方均可以提出糾紛。 portfolio.pending.tradeNotCompleted=交易不會及時完成(直到 {0} ) portfolio.pending.tradeProcess=交易流程 -portfolio.pending.openAgainDispute.msg=如果您不確定傳送給調解員或仲裁員的訊息是否已送達(例如,如果您在1天后沒有收到回覆),請放心使用 Cmd/Ctrl+o 再次開啟糾紛。你也可以在 Bisq 論壇上尋求額外的幫助,網址是 https://bisq.community。 +portfolio.pending.openAgainDispute.msg=如果您不確定發送給調解員或仲裁員的消息是否已送達(例如,如果您在1天后沒有收到回覆),請放心使用 Cmd/Ctrl+o 再次打開糾紛。你也可以在 Bisq 論壇上尋求額外的幫助,網址是 https://bisq.community。 portfolio.pending.openAgainDispute.button=再次出現糾紛 -portfolio.pending.openSupportTicket.headline=建立幫助話題 -portfolio.pending.openSupportTicket.msg=請僅在緊急情況下使用此功能,如果您沒有看到“提交支援”或“提交糾紛”按鈕。\n\n當您發出工單時,交易將被中斷並由調解員或仲裁員進行處理。 +portfolio.pending.openSupportTicket.headline=創建幫助話題 +portfolio.pending.openSupportTicket.msg=請僅在緊急情況下使用此功能,如果您沒有看到“提交支持”或“提交糾紛”按鈕。\n\n當您發出工單時,交易將被中斷並由調解員或仲裁員進行處理。 portfolio.pending.timeLockNotOver=你必須等到≈{0}(還需等待{1}個區塊)才能提交糾紛。 -portfolio.pending.error.depositTxNull=保證金交易無效。沒有有效的保證金交易,你使用建立糾紛。請到“設定/網路資訊”進行 SPV 重新同步。\n \n如需更多幫助,請聯絡 Bisq Keybase 團隊的 Support 頻道。 +portfolio.pending.error.depositTxNull=保證金交易無效。沒有有效的保證金交易,你使用創建糾紛。請到“設置/網絡信息”進行 SPV 重新同步。\n \n如需更多幫助,請聯繫 Bisq Keybase 團隊的 Support 頻道。 portfolio.pending.mediationResult.error.depositTxNull=保證金交易為空。你可以移動該交易至失敗的交易。 portfolio.pending.mediationResult.error.delayedPayoutTxNull=延遲支付交易為空。你可以移動該交易至失敗的交易。 -portfolio.pending.error.depositTxNotConfirmed=保證金交易未確認。未經確認的存款交易不能發起糾紛或仲裁請求。請耐心等待,直到它被確認或進入“設定/網路資訊”進行 SPV 重新同步。\n\n如需更多幫助,請聯絡 Bisq Keybase 團隊的 Support 頻道。 +portfolio.pending.error.depositTxNotConfirmed=保證金交易未確認。未經確認的存款交易不能發起糾紛或仲裁請求。請耐心等待,直到它被確認或進入“設置/網絡信息”進行 SPV 重新同步。\n\n如需更多幫助,請聯繫 Bisq Keybase 團隊的 Support 頻道。 portfolio.pending.support.headline.getHelp=需要幫助? -portfolio.pending.support.text.getHelp=如果您有任何問題,您可以嘗試在交易聊天中聯絡交易夥伴,或在 https://bisq.community 詢問 Bisq 社群。如果您的問題仍然沒有解決,您可以向調解員取得更多的幫助。 +portfolio.pending.support.text.getHelp=如果您有任何問題,您可以嘗試在交易聊天中聯繫交易夥伴,或在 https://bisq.community 詢問 Bisq 社區。如果您的問題仍然沒有解決,您可以向調解員取得更多的幫助。 portfolio.pending.support.button.getHelp=開啟交易聊天 portfolio.pending.support.headline.halfPeriodOver=確認付款 portfolio.pending.support.headline.periodOver=交易期結束 portfolio.pending.mediationRequested=已請求調解員協助 portfolio.pending.refundRequested=已請求退款 -portfolio.pending.openSupport=建立幫助話題 -portfolio.pending.supportTicketOpened=幫助話題已經建立 -portfolio.pending.communicateWithArbitrator=請在“幫助”介面上與仲裁員聯絡。 -portfolio.pending.communicateWithMediator=請在“支援”頁面中與調解員進行聯絡。 -portfolio.pending.disputeOpenedMyUser=您建立了一個糾紛。\n{0} -portfolio.pending.disputeOpenedByPeer=您的交易物件建立了一個糾紛。\n{0} +portfolio.pending.openSupport=創建幫助話題 +portfolio.pending.supportTicketOpened=幫助話題已經創建 +portfolio.pending.communicateWithArbitrator=請在“幫助”界面上與仲裁員聯繫。 +portfolio.pending.communicateWithMediator=請在“支持”頁面中與調解員進行聯繫。 +portfolio.pending.disputeOpenedMyUser=您創建了一個糾紛。\n{0} +portfolio.pending.disputeOpenedByPeer=您的交易對象創建了一個糾紛。\n{0} portfolio.pending.noReceiverAddressDefined=沒有定義接收地址 portfolio.pending.mediationResult.headline=調解費用的支出 portfolio.pending.mediationResult.info.noneAccepted=通過接受調解員關於交易的建議的支出來完成交易。 portfolio.pending.mediationResult.info.selfAccepted=你已經接受了調解員的建議。等待夥伴接受。 portfolio.pending.mediationResult.info.peerAccepted=你的夥伴已經接受了調解員的建議。你也接受嗎? -portfolio.pending.mediationResult.button=檢視建議的解決方案 +portfolio.pending.mediationResult.button=查看建議的解決方案 portfolio.pending.mediationResult.popup.headline=調解員在交易 ID:{0}上的建議 portfolio.pending.mediationResult.popup.headline.peerAccepted=你的夥伴已經接受了調解員的建議 portfolio.pending.mediationResult.popup.info=調解員建議的支出如下:\n你將支付:{0}\n你的交易夥伴將支付:{1}\n\n你可以接受或拒絕這筆調解費支出。\n\n通過接受,你驗證了合約的支付交易。如果你的交易夥伴也接受和驗證,支付將完成,交易將關閉。\n\n如果你們其中一人或雙方都拒絕該建議,你將必須等到(2)({3}區塊)與仲裁員展開第二輪糾紛討論,仲裁員將再次調查該案件,並根據他們的調查結果進行支付。\n\n仲裁員可以收取少量費用(費用上限:交易的保證金)作為其工作的補償。兩個交易者都同意調解員的建議是愉快的路徑請求仲裁是針對特殊情況的,比如如果一個交易者確信調解員沒有提出公平的賠償建議(或者如果另一個同伴沒有迴應)。\n\n關於新的仲裁模型的更多細節:https://docs.bisq.network/trading-rules.html#arbitration -portfolio.pending.mediationResult.popup.selfAccepted.lockTimeOver=您已經接受了調解員的建議支付但是似乎您的交易對手並沒有接受。\n\n一旦鎖定時間到{0}(區塊{1})您可以開啟第二輪糾紛讓仲裁員重新研究該案件並重新作出支出決定。\n\n您可以找到更多關於仲裁模型的資訊在:\nhttps://docs.bisq.network/trading-rules.html#arbitration +portfolio.pending.mediationResult.popup.selfAccepted.lockTimeOver=您已經接受了調解員的建議支付但是似乎您的交易對手並沒有接受。\n\n一旦鎖定時間到{0}(區塊{1})您可以打開第二輪糾紛讓仲裁員重新研究該案件並重新作出支出決定。\n\n您可以找到更多關於仲裁模型的信息在:\nhttps://docs.bisq.network/trading-rules.html#arbitration portfolio.pending.mediationResult.popup.openArbitration=拒絕並請求仲裁 portfolio.pending.mediationResult.popup.alreadyAccepted=您已經接受了。 portfolio.pending.failedTrade.taker.missingTakerFeeTx=吃單交易費未找到。\n\n如果沒有 tx,交易不能完成。沒有資金被鎖定以及沒有支付交易費用。你可以將交易移至失敗的交易。 portfolio.pending.failedTrade.maker.missingTakerFeeTx=掛單費交易未找到。\n\n如果沒有 tx,交易不能完成。沒有資金被鎖定以及沒有支付交易費用。你可以將交易移至失敗的交易。 -portfolio.pending.failedTrade.missingDepositTx=這個保證金交易(2 對 2 多重簽名交易)缺失\n\n沒有該 tx,交易不能完成。沒有資金被鎖定但是您的交易手續費仍然已支出。您可以發起一個請求去賠償改交易手續費在這裡:https://github.com/bisq-network/support/issues\n\n請隨意的將該交易移至失敗交易 -portfolio.pending.failedTrade.buyer.existingDepositTxButMissingDelayedPayoutTx=The delayed payout transaction is missing, but funds have been locked in the deposit transaction.\n\nPlease do NOT send the fiat or altcoin payment to the BTC seller, because without the delayed payout tx, arbitration cannot be opened. Instead, open a mediation ticket with Cmd/Ctrl+o. The mediator should suggest that both peers each get back the the full amount of their security deposits (with seller receiving full trade amount back as well). This way, there is no security risk, and only trade fees are lost. \n\nYou can request a reimbursement for lost trade fees here: [HYPERLINK:https://github.com/bisq-network/support/issues] -portfolio.pending.failedTrade.seller.existingDepositTxButMissingDelayedPayoutTx=The delayed payout transaction is missing but funds have been locked in the deposit transaction.\n\nIf the buyer is also missing the delayed payout transaction, they will be instructed to NOT send the payment and open a mediation ticket instead. You should also open a mediation ticket with Cmd/Ctrl+o. \n\nIf the buyer has not sent payment yet, the mediator should suggest that both peers each get back the full amount of their security deposits (with seller receiving full trade amount back as well). Otherwise the trade amount should go to the buyer. \n\nYou can request a reimbursement for lost trade fees here: [HYPERLINK:https://github.com/bisq-network/support/issues] -portfolio.pending.failedTrade.errorMsgSet=There was an error during trade protocol execution.\n\nError: {0}\n\nIt might be that this error is not critical, and the trade can be completed normally. If you are unsure, open a mediation ticket to get advice from Bisq mediators. \n\nIf the error was critical and the trade cannot be completed, you might have lost your trade fee. Request a reimbursement for lost trade fees here: [HYPERLINK:https://github.com/bisq-network/support/issues] -portfolio.pending.failedTrade.missingContract=The trade contract is not set.\n\nThe trade cannot be completed and you might have lost your trade fee. If so, you can request a reimbursement for lost trade fees here: [HYPERLINK:https://github.com/bisq-network/support/issues] -portfolio.pending.failedTrade.info.popup=The trade protocol encountered some problems.\n\n{0} -portfolio.pending.failedTrade.txChainInvalid.moveToFailed=The trade protocol encountered a serious problem.\n\n{0}\n\nDo you want to move the trade to failed trades?\n\nYou cannot open mediation or arbitration from the failed trades view, but you can move a failed trade back to the open trades screen any time. -portfolio.pending.failedTrade.txChainValid.moveToFailed=這個交易協議存在一些問題。\n\n{0}\n\n這個報價交易已經被髮布以及資金已被鎖定。只有在確定情況下將該交易移至失敗交易。這可能會阻止解決問題的可用選項。\n\n您確定想要將該交易移至失敗的交易嗎?\n\n您不能在失敗的交易中開啟一個調解或仲裁,但是你隨時可以將失敗的交易重新移至未完成交易。 +portfolio.pending.failedTrade.missingDepositTx=這個保證金交易(2 對 2 多重簽名交易)缺失\n\n沒有該 tx,交易不能完成。沒有資金被鎖定但是您的交易手續費仍然已支出。您可以發起一個請求去賠償改交易手續費在這裏:https://github.com/bisq-network/support/issues\n\n請隨意的將該交易移至失敗交易 +portfolio.pending.failedTrade.buyer.existingDepositTxButMissingDelayedPayoutTx=延遲支付交易缺失,但是資金仍然被鎖定在保證金交易中。\n\n請不要給比特幣賣家發送法幣或數字貨幣,因為沒有延遲交易 tx,不能開啟仲裁。使用 Cmd/Ctrl+o開啟調解協助。調解員應該建議交易雙方分別退回全部的保證金(賣方支付的交易金額也會全數返還)。這樣的話不會有任何的安全問題只會損失交易手續費。\n\n你可以在這裏為失敗的交易提出賠償要求:https://github.com/bisq-network/support/issues +portfolio.pending.failedTrade.seller.existingDepositTxButMissingDelayedPayoutTx=延遲支付交易確實但是資金仍然被鎖定在保證金交易中。\n\n如果賣家仍然缺失延遲支付交易,他會接到請勿付款的指示並開啟一個調節幫助。你也應該使用 Cmd/Ctrl+O 去打開一個調節協助\n\n如果買家還沒有發送付款,調解員應該會建議交易雙方分別退回全部的保證金(賣方支付的交易金額也會全數返還)。否則交易額應該判給買方。\n\n你可以在這裏為失敗的交易提出賠償要求:https://github.com/bisq-network/support/issues +portfolio.pending.failedTrade.errorMsgSet=在處理交易協議是發生了一個錯誤\n\n錯誤:{0}\n\n這應該不是致命錯誤,您可以正常的完成交易。如果你仍擔憂,打開一個調解協助並從 Bisq 調解員處得到建議。\n\n如果這個錯誤是致命的那麼這個交易就無法完成,你可能會損失交易費。可以在這裏為失敗的交易提出賠償要求:https://github.com/bisq-network/support/issues +portfolio.pending.failedTrade.missingContract=沒有設置交易合同。\n\n這個交易無法完成,你可能會損失交易手續費。可以在這裏為失敗的交易提出賠償要求:https://github.com/bisq-network/support/issues +portfolio.pending.failedTrade.info.popup=交易協議出現了問題。\n\n{0} +portfolio.pending.failedTrade.txChainInvalid.moveToFailed=交易協議出現了嚴重問題。\n\n{0}\n\n您確定想要將該交易移至失敗的交易嗎?\n\n您不能在失敗的交易中打開一個調解或仲裁,但是你隨時可以將失敗的交易重新移至未完成交易。 +portfolio.pending.failedTrade.txChainValid.moveToFailed=這個交易協議存在一些問題。\n\n{0}\n\n這個報價交易已經被髮布以及資金已被鎖定。只有在確定情況下將該交易移至失敗交易。這可能會阻止解決問題的可用選項。\n\n您確定想要將該交易移至失敗的交易嗎?\n\n您不能在失敗的交易中打開一個調解或仲裁,但是你隨時可以將失敗的交易重新移至未完成交易。 portfolio.pending.failedTrade.moveTradeToFailedIcon.tooltip=將交易移至失敗交易 -portfolio.pending.failedTrade.warningIcon.tooltip=點選開啟該交易的問題細節 +portfolio.pending.failedTrade.warningIcon.tooltip=點擊打開該交易的問題細節 portfolio.failed.revertToPending.popup=您想要將該交易移至未完成交易嗎 portfolio.failed.revertToPending=將交易移至未完成交易 @@ -838,7 +853,7 @@ funds.withdrawal.inputs=充值選擇 funds.withdrawal.useAllInputs=使用所有可用的充值地址 funds.withdrawal.useCustomInputs=使用自定義充值地址 funds.withdrawal.receiverAmount=接收者的數量 -funds.withdrawal.senderAmount=傳送者的數量 +funds.withdrawal.senderAmount=發送者的數量 funds.withdrawal.feeExcluded=不含挖礦費的金額 funds.withdrawal.feeIncluded=包含挖礦費的金額 funds.withdrawal.fromLabel=從源地址提現 @@ -850,12 +865,12 @@ funds.withdrawal.noFundsAvailable=沒有可用資金提現 funds.withdrawal.confirmWithdrawalRequest=確定提現請求 funds.withdrawal.withdrawMultipleAddresses=從多個地址提現({0}) funds.withdrawal.withdrawMultipleAddresses.tooltip=從多個地址提現:\n{0} -funds.withdrawal.notEnoughFunds=您錢包裡沒有足夠的資金。 +funds.withdrawal.notEnoughFunds=您錢包裏沒有足夠的資金。 funds.withdrawal.selectAddress=從列表中選一個源地址 -funds.withdrawal.setAmount=設定提現數量 +funds.withdrawal.setAmount=設置提現數量 funds.withdrawal.fillDestAddress=輸入您的目標地址 funds.withdrawal.warn.noSourceAddressSelected=您需要從上面列表中選一個源地址。 -funds.withdrawal.warn.amountExceeds=您的金額超過所選地址的可用金額。\n請考慮在上表中選擇多個地址或調整手續費設定,來支付手續費。 +funds.withdrawal.warn.amountExceeds=您的金額超過所選地址的可用金額。\n請考慮在上表中選擇多個地址或調整手續費設置,來支付手續費。 funds.reserved.noFunds=未完成報價中沒有已用資金 funds.reserved.reserved=報價 ID:{0} 接收在本地錢包中 @@ -863,7 +878,7 @@ funds.reserved.reserved=報價 ID:{0} 接收在本地錢包中 funds.locked.noFunds=交易中沒有凍結資金 funds.locked.locked=多重驗證凍結交易 ID:{0} -funds.tx.direction.sentTo=傳送至: +funds.tx.direction.sentTo=發送至: funds.tx.direction.receivedWith=接收到: funds.tx.direction.genesisTx=從初始 tx: funds.tx.txFeePaymentForBsqTx=BSQ tx 的礦工手續費支付 @@ -884,14 +899,13 @@ funds.tx.withdrawnFromBSQWallet=BTC 已從 BSQ 錢包中取出 funds.tx.memo=備註 funds.tx.noTxAvailable=沒有可用交易 funds.tx.revert=還原 -funds.tx.txSent=交易成功傳送到本地 Bisq 錢包中的新地址。 +funds.tx.txSent=交易成功發送到本地 Bisq 錢包中的新地址。 funds.tx.direction.self=內部錢包交易 -funds.tx.daoTxFee=DAO tx 的礦工手續費支付 +funds.tx.daoTxFee=BSQ tx 的礦工手續費支付 funds.tx.reimbursementRequestTxFee=退還申請 funds.tx.compensationRequestTxFee=報償申請 funds.tx.dustAttackTx=接受零頭 -funds.tx.dustAttackTx.popup=這筆交易是傳送一個非常小的比特幣金額到您的錢包,可能是區塊鏈分析公司嘗試監控您的交易。\n\n如果您在交易中使用該交易輸出,他們將瞭解到您很可能也是其他地址的所有者(資金歸集)。\n\n為了保護您的隱私,Bisq 錢包忽略了這種零頭的消費和餘額顯示。可以在設定中將輸出視為零頭時設定閾值量。 - +funds.tx.dustAttackTx.popup=這筆交易是發送一個非常小的比特幣金額到您的錢包,可能是區塊鏈分析公司嘗試監控您的交易。\n\n如果您在交易中使用該交易輸出,他們將瞭解到您很可能也是其他地址的所有者(資金歸集)。\n\n為了保護您的隱私,Bisq 錢包忽略了這種零頭的消費和餘額顯示。可以在設置中將輸出視為零頭時設置閾值量。 #################################################################### # Support @@ -901,68 +915,69 @@ support.tab.mediation.support=調解 support.tab.arbitration.support=仲裁 support.tab.legacyArbitration.support=歷史仲裁 support.tab.ArbitratorsSupportTickets={0} 的工單 -support.filter=查詢糾紛 -support.filter.prompt=輸入 交易 ID、日期、洋蔥地址或賬戶資訊 +support.filter=查找糾紛 +support.filter.prompt=輸入 交易 ID、日期、洋葱地址或賬户信息 support.sigCheck.button=確認結果 -support.sigCheck.popup.info=In case of a reimbursement request to the DAO you need to paste the summary message of the mediation and arbitration process in your reimbursement request on Github. To make this statement verifiable any user can check with this tool if the signature of the mediator or arbitrator matches the summary message. +support.sigCheck.popup.info=如果向在 DAO 發送賠償請求,您需要在 Github 上粘貼您的賠償請求中的調解和仲裁過程的摘要消息。要使此聲明可驗證,任何用户都可以使用此工具檢查調解或仲裁人員的簽名是否與摘要消息匹配。 support.sigCheck.popup.header=確認糾紛結果簽名 -support.sigCheck.popup.msg.label=總結訊息 -support.sigCheck.popup.msg.prompt=複製貼上糾紛總結訊息 +support.sigCheck.popup.msg.label=總結消息 +support.sigCheck.popup.msg.prompt=複製粘貼糾紛總結消息 support.sigCheck.popup.result=驗證結果 support.sigCheck.popup.success=簽名有效 support.sigCheck.popup.failed=簽名驗證失敗 -support.sigCheck.popup.invalidFormat=訊息並不是正確的格式。請複製貼上糾紛總結訊息。 +support.sigCheck.popup.invalidFormat=消息並不是正確的格式。請複製粘貼糾紛總結消息。 support.reOpenByTrader.prompt=您確定想要重新開啟糾紛? -support.reOpenButton.label=重新開啟 +support.reOpenButton.label=重新打開 support.sendNotificationButton.label=私人通知 -support.reportButton.label=報告 +support.reportButton.label=報吿 support.fullReportButton.label=所有糾紛 -support.noTickets=沒有建立的話題 -support.sendingMessage=傳送訊息... -support.receiverNotOnline=收件人未線上。訊息被儲存到他們的郵箱。 -support.sendMessageError=傳送訊息失敗。錯誤:{0} -support.wrongVersion=糾紛中的訂單建立於一箇舊版本的 Bisq。\n您不能在當前版本關閉這個糾紛。\n\n請您使用舊版本/協議版本: {0} -support.openFile=開啟附件檔案(檔案最大大小:{0} kb) -support.attachmentTooLarge=您的附件的總大小為 {0} kb,並超過最大值。 允許訊息大小為 {1} kB。 -support.maxSize=檔案允許的最大大小 {0} kB。 +support.noTickets=沒有創建的話題 +support.sendingMessage=發送消息... +support.receiverNotOnline=收件人未在線。消息被保存到他們的郵箱。 +support.sendMessageError=發送消息失敗。錯誤:{0} +support.wrongVersion=糾紛中的訂單創建於一箇舊版本的 Bisq。\n您不能在當前版本關閉這個糾紛。\n\n請您使用舊版本/協議版本: {0} +support.openFile=打開附件文件(文件最大大小:{0} kb) +support.attachmentTooLarge=您的附件的總大小為 {0} kb,並超過最大值。 允許消息大小為 {1} kB。 +support.maxSize=文件允許的最大大小 {0} kB。 support.attachment=附件 -support.tooManyAttachments=您不能在一個訊息裡傳送超過3個附件。 -support.save=儲存檔案到磁碟 -support.messages=訊息 -support.input.prompt=輸入訊息... -support.send=傳送 -support.addAttachments=新增附件 +support.tooManyAttachments=您不能在一個消息裏發送超過3個附件。 +support.save=保存文件到磁盤 +support.messages=消息 +support.input.prompt=輸入消息... +support.send=發送 +support.addAttachments=添加附件 support.closeTicket=關閉話題 support.attachments=附件: -support.savedInMailbox=訊息儲存在收件人的信箱中 -support.arrived=訊息抵達收件人 -support.acknowledged=收件人已確認接收訊息 -support.error=收件人無法處理訊息。錯誤:{0} +support.savedInMailbox=消息保存在收件人的信箱中 +support.arrived=消息抵達收件人 +support.acknowledged=收件人已確認接收消息 +support.error=收件人無法處理消息。錯誤:{0} support.buyerAddress=BTC 買家地址 support.sellerAddress=BTC 賣家地址 support.role=角色 +support.agent=Support agent support.state=狀態 support.closed=關閉 -support.open=開啟 +support.open=打開 support.buyerOfferer=BTC 買家/掛單者 support.sellerOfferer=BTC 賣家/掛單者 support.buyerTaker=BTC 買家/買單者 support.sellerTaker=BTC 賣家/買單者 -support.backgroundInfo=Bisq 不是一家公司,所以它處理糾紛的方式不同。\n\n交易雙方可以在應用程式中通過未完成交易頁面上的安全聊天進行通訊,以嘗試自行解決爭端。如果這還不夠,調解員可以介入幫助。調解員將對情況進行評估,並對交易資金的支出提出建議。如果兩個交易者都接受這個建議,那麼支付交易就完成了,交易也結束了。如果一方或雙方不同意調解員的建議,他們可以要求仲裁。仲裁員將重新評估情況,如果有必要,將親自向交易員付款,並要求 Bisq DAO 對這筆付款進行補償。 -support.initialInfo=請在下面的文字框中輸入您的問題描述。新增儘可能多的資訊,以加快解決糾紛的時間。\n\n以下是你應提供的資料核對表:\n\t●如果您是 BTC 買家:您是否使用法定貨幣或其他加密貨幣轉賬?如果是,您是否點選了應用程式中的“支付開始”按鈕?\n\t●如果您是 BTC 賣家:您是否收到法定貨幣或其他加密貨幣的付款了?如果是,你是否點選了應用程式中的“已收到付款”按鈕?\n\t●您使用的是哪個版本的 Bisq?\n\t●您使用的是哪種作業系統?\n\t●如果遇到操作執行失敗的問題,請考慮切換到新的資料目錄。\n\t有時資料目錄會損壞,並導致奇怪的錯誤。\n詳見:https://docs.bisq.network/backup-recovery.html#switch-to-a-new-data-directory\n\n請熟悉糾紛處理的基本規則:\n\t●您需要在2天內答覆 {0} 的請求。\n\t●調解員會在2天之內答覆,仲裁員會在5天之內答覆。\n\t●糾紛的最長期限為14天。\n\t●你需要與仲裁員合作,提供他們為你的案件所要求的資訊。\n\t●當您第一次啟動應用程式時,您接受了使用者協議中爭議文件中列出的規則。\n\n您可以通過 {2} 瞭解有關糾紛處理的更多資訊 -support.systemMsg=系統訊息:{0} -support.youOpenedTicket=您建立了幫助請求。\n\n{0}\n\nBisq 版本:{1} -support.youOpenedDispute=您建立了一個糾紛請求。\n\n{0}\n\nBisq 版本:{1} -support.youOpenedDisputeForMediation=您建立了一個調解請求。\n\n{0}\n\nBisq 版本:{1} +support.backgroundInfo=Bisq 不是一家公司,所以它處理糾紛的方式不同。\n\n交易雙方可以在應用程序中通過未完成交易頁面上的安全聊天進行通信,以嘗試自行解決爭端。如果這還不夠,調解員可以介入幫助。調解員將對情況進行評估,並對交易資金的支出提出建議。如果兩個交易者都接受這個建議,那麼支付交易就完成了,交易也結束了。如果一方或雙方不同意調解員的建議,他們可以要求仲裁。仲裁員將重新評估情況,如果有必要,將親自向交易員付款,並要求 Bisq DAO 對這筆付款進行補償。 +support.initialInfo=請在下面的文本框中輸入您的問題描述。添加儘可能多的信息,以加快解決糾紛的時間。\n\n以下是你應提供的資料核對表:\n\t●如果您是 BTC 買家:您是否使用法定貨幣或其他加密貨幣轉賬?如果是,您是否點擊了應用程序中的“支付開始”按鈕?\n\t●如果您是 BTC 賣家:您是否收到法定貨幣或其他加密貨幣的付款了?如果是,你是否點擊了應用程序中的“已收到付款”按鈕?\n\t●您使用的是哪個版本的 Bisq?\n\t●您使用的是哪種操作系統?\n\t●如果遇到操作執行失敗的問題,請考慮切換到新的數據目錄。\n\t有時數據目錄會損壞,並導致奇怪的錯誤。\n詳見:https://docs.bisq.network/backup-recovery.html#switch-to-a-new-data-directory\n\n請熟悉糾紛處理的基本規則:\n\t●您需要在2天內答覆 {0} 的請求。\n\t●調解員會在2天之內答覆,仲裁員會在5天之內答覆。\n\t●糾紛的最長期限為14天。\n\t●你需要與仲裁員合作,提供他們為你的案件所要求的信息。\n\t●當您第一次啟動應用程序時,您接受了用户協議中爭議文檔中列出的規則。\n\n您可以通過 {2} 瞭解有關糾紛處理的更多信息 +support.systemMsg=系統消息:{0} +support.youOpenedTicket=您創建了幫助請求。\n\n{0}\n\nBisq 版本:{1} +support.youOpenedDispute=您創建了一個糾紛請求。\n\n{0}\n\nBisq 版本:{1} +support.youOpenedDisputeForMediation=您創建了一個調解請求。\n\n{0}\n\nBisq 版本:{1} support.peerOpenedTicket=對方因技術問題請求獲取幫助。\n\n{0}\n\nBisq 版本:{1} -support.peerOpenedDispute=對方建立了一個糾紛請求。\n\n{0}\n\nBisq 版本:{1} -support.peerOpenedDisputeForMediation=對方建立了一個調解請求。\n\n{0}\n\nBisq 版本:{1} -support.mediatorsDisputeSummary=系統訊息:\n調解糾紛總結:\n{0} +support.peerOpenedDispute=對方創建了一個糾紛請求。\n\n{0}\n\nBisq 版本:{1} +support.peerOpenedDisputeForMediation=對方創建了一個調解請求。\n\n{0}\n\nBisq 版本:{1} +support.mediatorsDisputeSummary=系統消息:\n調解糾紛總結:\n{0} support.mediatorsAddress=仲裁員的節點地址:{0} -support.warning.disputesWithInvalidDonationAddress=延遲支付交易已經被用於一個不可用接受者地址。它與有效捐贈地址的任何 DAO 中引數值均不匹配。\n\n這可能是一個騙局。請將該事件通知開發者,在問題解決之前不要關閉該案件!\n\n糾紛所用的地址:{0}\n\n所有 DAO 引數中捐贈地址:{1}\n\n交易:{2}{3} +support.warning.disputesWithInvalidDonationAddress=延遲支付交易已經被用於一個不可用接受者地址。它與有效捐贈地址的任何 DAO 中參數值均不匹配。\n\n這可能是一個騙局。請將該事件通知開發者,在問題解決之前不要關閉該案件!\n\n糾紛所用的地址:{0}\n\n所有 DAO 參數中捐贈地址:{1}\n\n交易:{2}{3} support.warning.disputesWithInvalidDonationAddress.mediator=\n\n您確定一定要關閉糾紛嗎? support.warning.disputesWithInvalidDonationAddress.refundAgent=\n\n您不能進行支付。 @@ -971,26 +986,26 @@ support.warning.disputesWithInvalidDonationAddress.refundAgent=\n\n您不能進 # Settings #################################################################### settings.tab.preferences=偏好 -settings.tab.network=網路資訊 +settings.tab.network=網絡信息 settings.tab.about=關於我們 setting.preferences.general=通用偏好 setting.preferences.explorer=比特幣區塊瀏覽器 setting.preferences.explorer.bsq=Bisq 區塊瀏覽器 setting.preferences.deviation=與市場價格最大差價 -setting.preferences.bsqAverageTrimThreshold=Outlier threshold for BSQ rate +setting.preferences.bsqAverageTrimThreshold=BSQ 率已超過閾值 setting.preferences.avoidStandbyMode=避免待機模式 setting.preferences.autoConfirmXMR=XMR 自動確認 setting.preferences.autoConfirmEnabled=啟用 setting.preferences.autoConfirmRequiredConfirmations=已要求確認 setting.preferences.autoConfirmMaxTradeSize=最大交易量(BTC) -setting.preferences.autoConfirmServiceAddresses=Monero Explorer 連結(使用Tor,但本地主機,LAN IP地址和 *.local 主機名除外) +setting.preferences.autoConfirmServiceAddresses=Monero Explorer 鏈接(使用Tor,但本地主機,LAN IP地址和 *.local 主機名除外) setting.preferences.deviationToLarge=值不允許大於30% -setting.preferences.txFee=Withdrawal transaction fee (satoshis/vbyte) +setting.preferences.txFee=提現交易手續費(聰/字節) setting.preferences.useCustomValue=使用自定義值 -setting.preferences.txFeeMin=Transaction fee must be at least {0} satoshis/vbyte -setting.preferences.txFeeTooLarge=Your input is above any reasonable value (>5000 satoshis/vbyte). Transaction fee is usually in the range of 50-400 satoshis/vbyte. -setting.preferences.ignorePeers=忽略節點 [洋蔥地址:埠] +setting.preferences.txFeeMin=交易手續費必須至少為{0} 聰/字節 +setting.preferences.txFeeTooLarge=您輸入的數額超過可接受值(>5000 聰/字節)。交易手續費一般在 50-400 聰/字節、 +setting.preferences.ignorePeers=忽略節點 [洋葱地址:端口] setting.preferences.ignoreDustThreshold=最小無零頭輸出值 setting.preferences.currenciesInList=市場價的貨幣列表 setting.preferences.prefCurrency=首選貨幣 @@ -999,8 +1014,8 @@ setting.preferences.noFiat=沒有選定國家貨幣 setting.preferences.cannotRemovePrefCurrency=您不能刪除您選定的首選貨幣 setting.preferences.displayAltcoins=顯示數字貨幣 setting.preferences.noAltcoins=沒有選定數字貨幣 -setting.preferences.addFiat=新增法定貨幣 -setting.preferences.addAltcoin=新增數字貨幣 +setting.preferences.addFiat=添加法定貨幣 +setting.preferences.addAltcoin=添加數字貨幣 setting.preferences.displayOptions=顯示選項 setting.preferences.showOwnOffers=在報價列表中顯示我的報價 setting.preferences.useAnimations=使用動畫 @@ -1012,89 +1027,91 @@ settings.preferences.supportLanguageWarning=如有任何爭議,請注意調解 setting.preferences.daoOptions=DAO 選項 setting.preferences.dao.resyncFromGenesis.label=從初始 tx 重構 DAO 狀態 setting.preferences.dao.resyncFromResources.label=從指定資源重新構建 DAO 狀態 -setting.preferences.dao.resyncFromResources.popup=應用程式重新啟動後,Bisq 網路治理資料將從種子節點重新載入,而 BSQ 同步狀態將從創始交易中重新構建。 -setting.preferences.dao.resyncFromGenesis.popup=從創始交易中出現同步會消耗大量時間以及 CPU 資源。您確定要重新同步嗎?通常,從最新資原始檔進行重新同步就足夠了,而且速度更快。\n\n應用程式重新啟動後,Bisq 網路治理資料將從種子節點重新載入,而 BSQ 同步狀態將從初始交易中重新構建。 +setting.preferences.dao.resyncFromResources.popup=應用程序重新啟動後,Bisq 網絡治理數據將從種子節點重新加載,而 BSQ 同步狀態將從創始交易中重新構建。 +setting.preferences.dao.resyncFromGenesis.popup=從創始交易中出現同步會消耗大量時間以及 CPU 資源。您確定要重新同步嗎?通常,從最新資源文件進行重新同步就足夠了,而且速度更快。\n\n應用程序重新啟動後,Bisq 網絡治理數據將從種子節點重新加載,而 BSQ 同步狀態將從初始交易中重新構建。 setting.preferences.dao.resyncFromGenesis.resync=從創始區塊重新同步並關閉 -setting.preferences.dao.isDaoFullNode=以 DAO 全節點執行 Bisq -setting.preferences.dao.rpcUser=RPC 使用者名稱 +setting.preferences.dao.isDaoFullNode=以 DAO 全節點運行 Bisq +setting.preferences.dao.rpcUser=RPC 用户名 setting.preferences.dao.rpcPw=PRC 密碼 -setting.preferences.dao.blockNotifyPort=區塊通知埠 -setting.preferences.dao.fullNodeInfo=如果要將 Bisq 以 DAO 全節點執行,您需要在本地執行比特幣核心並啟用 RPC 。所有的需求都記錄在“ {0} ”中。 -setting.preferences.dao.fullNodeInfo.ok=開啟文件頁面 +setting.preferences.dao.blockNotifyPort=區塊通知端口 +setting.preferences.dao.fullNodeInfo=如果要將 Bisq 以 DAO 全節點運行,您需要在本地運行比特幣核心並啟用 RPC 。所有的需求都記錄在“ {0} ”中。 +setting.preferences.dao.fullNodeInfo.ok=打開文檔頁面 setting.preferences.dao.fullNodeInfo.cancel=不,我堅持使用輕節點模式 -settings.preferences.editCustomExplorer.headline=Explorer Settings -settings.preferences.editCustomExplorer.description=Choose a system defined explorer from the list on the left, and/or customize to suit your own preferences. -settings.preferences.editCustomExplorer.available=Available explorers -settings.preferences.editCustomExplorer.chosen=Chosen explorer settings +settings.preferences.editCustomExplorer.headline=瀏覽設置。 +settings.preferences.editCustomExplorer.description=從左側列表中選擇一個系統默認瀏覽器,或使用您偏好的自定義設置。 +settings.preferences.editCustomExplorer.available=可用瀏覽器 +settings.preferences.editCustomExplorer.chosen=已選擇的瀏覽器設置 settings.preferences.editCustomExplorer.name=名稱 -settings.preferences.editCustomExplorer.txUrl=Transaction URL -settings.preferences.editCustomExplorer.addressUrl=Address URL +settings.preferences.editCustomExplorer.txUrl=交易 URL +settings.preferences.editCustomExplorer.addressUrl=地址 URL -settings.net.btcHeader=比特幣網路 -settings.net.p2pHeader=Bisq 網路 +settings.net.btcHeader=比特幣網絡 +settings.net.p2pHeader=Bisq 網絡 settings.net.onionAddressLabel=我的匿名地址 settings.net.btcNodesLabel=使用自定義比特幣主節點 -settings.net.bitcoinPeersLabel=已連線節點 -settings.net.useTorForBtcJLabel=使用 Tor 連線比特幣網路 -settings.net.bitcoinNodesLabel=需要連線比特幣核心 +settings.net.bitcoinPeersLabel=已連接節點 +settings.net.useTorForBtcJLabel=使用 Tor 連接比特幣網絡 +settings.net.bitcoinNodesLabel=需要連接比特幣核心 settings.net.useProvidedNodesRadio=使用公共比特幣核心節點 -settings.net.usePublicNodesRadio=使用公共比特幣網路 +settings.net.usePublicNodesRadio=使用公共比特幣網絡 settings.net.useCustomNodesRadio=使用自定義比特幣主節點 -settings.net.warn.usePublicNodes=如果你使用公共比特幣網路,你就會面臨嚴重的隱私問題,這是由損壞的 bloom filter 設計和實現造成的,它適用於像 BitcoinJ 這樣的 SPV 錢包(在 Bisq 中使用)。您所連線的任何完整節點都可以發現您的所有錢包地址都屬於一個實體。\n\n詳情請瀏覽: https://bisq.network/blog/privacy-in-bitsquare 。\n\n您確定要使用公共節點嗎? +settings.net.warn.usePublicNodes=如果你使用公共比特幣網絡,你就會面臨嚴重的隱私問題,這是由損壞的 bloom filter 設計和實現造成的,它適用於像 BitcoinJ 這樣的 SPV 錢包(在 Bisq 中使用)。您所連接的任何完整節點都可以發現您的所有錢包地址都屬於一個實體。\n\n詳情請瀏覽: https://bisq.network/blog/privacy-in-bitsquare 。\n\n您確定要使用公共節點嗎? settings.net.warn.usePublicNodes.useProvided=不,使用給定的節點 -settings.net.warn.usePublicNodes.usePublic=使用公共網路 -settings.net.warn.useCustomNodes.B2XWarning=請確保您的比特幣節點是一個可信的比特幣核心節點!\n\n連線到不遵循比特幣核心共識規則的節點可能會損壞您的錢包,並在交易過程中造成問題。\n\n連線到違反共識規則的節點的使用者應對任何由此造成的損害負責。任何由此產生的糾紛都將有利於另一方。對於忽略此警告和保護機制的使用者,不提供任何技術支援! -settings.net.warn.invalidBtcConfig=由於您的配置無效,無法連線至比特幣網路。\n\n您的配置已經被重置為預設比特幣節點。你需要重啟 Bisq。 -settings.net.localhostBtcNodeInfo=背景資訊:Bisq 在啟動時會在本地查詢比特幣節點。如果有,Bisq 將只通過它與比特幣網路進行通訊。 -settings.net.p2PPeersLabel=已連線節點 +settings.net.warn.usePublicNodes.usePublic=使用公共網絡 +settings.net.warn.useCustomNodes.B2XWarning=請確保您的比特幣節點是一個可信的比特幣核心節點!\n\n連接到不遵循比特幣核心共識規則的節點可能會損壞您的錢包,並在交易過程中造成問題。\n\n連接到違反共識規則的節點的用户應對任何由此造成的損害負責。任何由此產生的糾紛都將有利於另一方。對於忽略此警吿和保護機制的用户,不提供任何技術支持! +settings.net.warn.invalidBtcConfig=由於您的配置無效,無法連接至比特幣網絡。\n\n您的配置已經被重置為默認比特幣節點。你需要重啟 Bisq。 +settings.net.localhostBtcNodeInfo=背景信息:Bisq 在啟動時會在本地查找比特幣節點。如果有,Bisq 將只通過它與比特幣網絡進行通信。 +settings.net.p2PPeersLabel=已連接節點 settings.net.onionAddressColumn=匿名地址 -settings.net.creationDateColumn=已建立連線 +settings.net.creationDateColumn=已建立連接 settings.net.connectionTypeColumn=入/出 -settings.net.sentDataLabel=統計資料已傳送 -settings.net.receivedDataLabel=統計資料已接收 +settings.net.sentDataLabel=統計數據已發送 +settings.net.receivedDataLabel=統計數據已接收 +settings.net.chainHeightLabel=最新 BTC 區塊高度 settings.net.roundTripTimeColumn=延遲 -settings.net.sentBytesColumn=傳送 +settings.net.sentBytesColumn=發送 settings.net.receivedBytesColumn=接收 -settings.net.peerTypeColumn=節點型別 -settings.net.openTorSettingsButton=開啟 Tor 設定 +settings.net.peerTypeColumn=節點類型 +settings.net.openTorSettingsButton=打開 Tor 設置 settings.net.versionColumn=版本 settings.net.subVersionColumn=子版本 settings.net.heightColumn=高度 -settings.net.needRestart=您需要重啟應用程式以同意這次變更。\n您需要現在重啟嗎? +settings.net.needRestart=您需要重啟應用程序以同意這次變更。\n您需要現在重啟嗎? settings.net.notKnownYet=至今未知... -settings.net.sentData=已傳送資料 {0},{1} 條訊息,{2} 條訊息/秒 -settings.net.receivedData=已接收資料 {0},{1} 條訊息,{2} 條訊息/秒 -settings.net.ips=新增逗號分隔的 IP 地址及埠,如使用8333埠可不填寫。 +settings.net.sentData=已發送數據 {0},{1} 條消息,{2} 條消息/秒 +settings.net.receivedData=已接收數據 {0},{1} 條消息,{2} 條消息/秒 +settings.net.chainHeight=Bisq :{0}|節點:{1} +settings.net.ips=添加逗號分隔的 IP 地址及端口,如使用8333端口可不填寫。 settings.net.seedNode=種子節點 settings.net.directPeer=節點(直連) settings.net.peer=節點 -settings.net.inbound=接收資料包 -settings.net.outbound=傳送資料包 +settings.net.inbound=接收數據包 +settings.net.outbound=發送數據包 settings.net.reSyncSPVChainLabel=重新同步 SPV 鏈 -settings.net.reSyncSPVChainButton=刪除 SPV 鏈檔案並重新同步 -settings.net.reSyncSPVSuccess=SPV 鏈檔案將在下一次啟動時被刪除。您現在需要重新啟動應用程式。\n\n重新啟動後,可能需要一段時間才能與網路重新同步,只有重新同步完成後才會看到所有的交易。\n\n根據交易的數量和錢包賬齡,重新同步可能會花費幾個小時,並消耗100%的 CPU。不要打斷這個過程,否則你會不斷地重複它。 -settings.net.reSyncSPVAfterRestart=SPV 鏈檔案已被刪除。請耐心等待,與網路重新同步可能需要一段時間。 -settings.net.reSyncSPVAfterRestartCompleted=重新同步剛剛完成,請重啟應用程式。 -settings.net.reSyncSPVFailed=無法刪除 SPV 鏈檔案。\n錯誤:{0} +settings.net.reSyncSPVChainButton=刪除 SPV 鏈文件並重新同步 +settings.net.reSyncSPVSuccess=Are you sure you want to do an SPV resync? If you proceed, the SPV chain file will be deleted on the next startup.\n\nAfter the restart it can take a while to resync with the network and you will only see all transactions once the resync is completed.\n\nDepending on the number of transactions and the age of your wallet the resync can take up to a few hours and consumes 100% of CPU. Do not interrupt the process otherwise you have to repeat it. +settings.net.reSyncSPVAfterRestart=SPV 鏈文件已被刪除。請耐心等待,與網絡重新同步可能需要一段時間。 +settings.net.reSyncSPVAfterRestartCompleted=重新同步剛剛完成,請重啟應用程序。 +settings.net.reSyncSPVFailed=無法刪除 SPV 鏈文件。\n錯誤:{0} setting.about.aboutBisq=關於 Bisq -setting.about.about=Bisq 是一款開源軟體,它通過分散的對等網路促進了比特幣與各國貨幣(以及其他加密貨幣)的交易,嚴格保護了使用者隱私的方式。請到我們專案的網站閱讀更多關於 Bisq 的資訊。 +setting.about.about=Bisq 是一款開源軟件,它通過分散的對等網絡促進了比特幣與各國貨幣(以及其他加密貨幣)的交易,嚴格保護了用户隱私的方式。請到我們項目的網站閲讀更多關於 Bisq 的信息。 setting.about.web=Bisq 網站 -setting.about.code=原始碼 +setting.about.code=源代碼 setting.about.agpl=AGPL 協議 -setting.about.support=支援 Bisq -setting.about.def=Bisq 不是一個公司,而是一個社群專案,開放參與。如果您想參與或支援 Bisq,請點選下面連線。 +setting.about.support=支持 Bisq +setting.about.def=Bisq 不是一個公司,而是一個社區項目,開放參與。如果您想參與或支持 Bisq,請點擊下面連接。 setting.about.contribute=貢獻 -setting.about.providers=資料提供商 -setting.about.apisWithFee=Bisq 使用 Bisq 價格指數來表示法幣與虛擬貨幣的市場價格,並使用 Bisq 記憶體池節點來估算採礦費。 +setting.about.providers=數據提供商 +setting.about.apisWithFee=Bisq 使用 Bisq 價格指數來表示法幣與虛擬貨幣的市場價格,並使用 Bisq 內存池節點來估算採礦費。 setting.about.apis=Bisq 使用 Bisq 價格指數來表示法幣與數字貨幣的市場價格。 setting.about.pricesProvided=交易所價格提供商 setting.about.feeEstimation.label=礦工手續費估算提供商 setting.about.versionDetails=版本詳情 -setting.about.version=應用程式版本 +setting.about.version=應用程序版本 setting.about.subsystems.label=子系統版本 -setting.about.subsystems.val=網路版本:{0};P2P 訊息版本:{1};本地資料庫版本:{2};交易協議版本:{3} +setting.about.subsystems.val=網絡版本:{0};P2P 消息版本:{1};本地數據庫版本:{2};交易協議版本:{3} setting.about.shortcuts=快捷鍵 setting.about.shortcuts.ctrlOrAltOrCmd=“Ctrl + {0}”或“alt + {0}”或“cmd + {0}” @@ -1105,48 +1122,48 @@ setting.about.shortcuts.menuNav.value=使用“Ctrl”或“Alt”或“cmd” + setting.about.shortcuts.close=關閉 Bisq setting.about.shortcuts.close.value=“Ctrl + {0}”或“cmd + {0}”或“Ctrl + {1}”或“cmd + {1}” -setting.about.shortcuts.closePopup=關閉彈窗以及對話方塊 +setting.about.shortcuts.closePopup=關閉彈窗以及對話框 setting.about.shortcuts.closePopup.value=‘釋放’ 鍵 -setting.about.shortcuts.chatSendMsg=傳送資訊到交易夥伴 +setting.about.shortcuts.chatSendMsg=發送信息到交易夥伴 setting.about.shortcuts.chatSendMsg.value=“Ctrl + ENTER”或“alt + ENTER”或“cmd + ENTER” -setting.about.shortcuts.openDispute=建立糾紛 -setting.about.shortcuts.openDispute.value=選擇未完成交易並點選:{0} +setting.about.shortcuts.openDispute=創建糾紛 +setting.about.shortcuts.openDispute.value=選擇未完成交易並點擊:{0} -setting.about.shortcuts.walletDetails=開啟錢包詳情視窗 +setting.about.shortcuts.walletDetails=打開錢包詳情窗口 -setting.about.shortcuts.openEmergencyBtcWalletTool=開啟應急 BTC 錢包工具 +setting.about.shortcuts.openEmergencyBtcWalletTool=打開應急 BTC 錢包工具 -setting.about.shortcuts.openEmergencyBsqWalletTool=開啟應急 BSQ 錢包工具 +setting.about.shortcuts.openEmergencyBsqWalletTool=打開應急 BSQ 錢包工具 setting.about.shortcuts.showTorLogs=在 DEBUG 與 WARN 之間切換 Tor 日誌等級 -setting.about.shortcuts.manualPayoutTxWindow=開啟視窗手動支付雙重驗證存款交易 +setting.about.shortcuts.manualPayoutTxWindow=打開窗口手動支付雙重驗證存款交易 -setting.about.shortcuts.reRepublishAllGovernanceData=重新推送 DAO 眾議廳資料(包括提案以及投票) +setting.about.shortcuts.reRepublishAllGovernanceData=重新推送 DAO 眾議廳數據(包括提案以及投票) -setting.about.shortcuts.removeStuckTrade=開啟彈窗並將異常交易移動至失敗交易頁(僅在你已經確認的情況下使用) +setting.about.shortcuts.removeStuckTrade=打開彈窗並將異常交易移動至失敗交易頁(僅在你已經確認的情況下使用) setting.about.shortcuts.removeStuckTrade.value=選擇未完成交易並按下:{0} setting.about.shortcuts.registerArbitrator=註冊仲裁員(僅限調解員/仲裁員) -setting.about.shortcuts.registerArbitrator.value=切換至賬戶頁面並按下:{0} +setting.about.shortcuts.registerArbitrator.value=切換至賬户頁面並按下:{0} setting.about.shortcuts.registerMediator=註冊調解員(僅限調解員/仲裁員) -setting.about.shortcuts.registerMediator.value=切換至賬戶頁面並按下:{0} +setting.about.shortcuts.registerMediator.value=切換至賬户頁面並按下:{0} -setting.about.shortcuts.openSignPaymentAccountsWindow=開啟賬齡驗證視窗(僅限仲裁員) +setting.about.shortcuts.openSignPaymentAccountsWindow=打開賬齡驗證窗口(僅限仲裁員) setting.about.shortcuts.openSignPaymentAccountsWindow.value=切換至仲裁頁面並按下:{0} -setting.about.shortcuts.sendAlertMsg=傳送警報或更新訊息(需要許可權) +setting.about.shortcuts.sendAlertMsg=發送警報或更新消息(需要權限) -setting.about.shortcuts.sendFilter=設定過濾器(需要許可權) +setting.about.shortcuts.sendFilter=設置過濾器(需要權限) -setting.about.shortcuts.sendPrivateNotification=傳送私人通知到對等點(需要許可權) -setting.about.shortcuts.sendPrivateNotification.value=點選交易夥伴頭像並按下:{0} 以顯示更多資訊 +setting.about.shortcuts.sendPrivateNotification=發送私人通知到對等點(需要權限) +setting.about.shortcuts.sendPrivateNotification.value=點擊交易夥伴頭像並按下:{0} 以顯示更多信息 setting.info.headline=新 XMR 自動確認功能 -setting.info.msg=當你完成 BTC/XMR 交易時,您可以使用自動確認功能來驗證是否向您的錢包中傳送了正確數量的 XMR,以便 Bisq 可以自動將交易標記為完成,從而使每個人都可以更快地進行交易。\n\n自動確認使用 XMR 傳送方提供的交易金鑰在至少 2 個 XMR 區塊瀏覽器節點上檢查 XMR 交易。在預設情況下,Bisq 使用由 Bisq 貢獻者執行的區塊瀏覽器節點,但是我們建議執行您自己的 XMR 區塊瀏覽器節點以最大程度地保護隱私和安全。\n\n您還可以在``設定''中將每筆交易的最大 BTC 數量設定為自動確認以及所需確認的數量。\n\n在 Bisq Wiki 上檢視更多詳細資訊(包括如何設定自己的區塊瀏覽器節點):https://bisq.wiki/Trading_Monero#Auto-confirming_trades +setting.info.msg=當你完成 BTC/XMR 交易時,您可以使用自動確認功能來驗證是否向您的錢包中發送了正確數量的 XMR,以便 Bisq 可以自動將交易標記為完成,從而使每個人都可以更快地進行交易。\n\n自動確認使用 XMR 發送方提供的交易密鑰在至少 2 個 XMR 區塊瀏覽器節點上檢查 XMR 交易。在默認情況下,Bisq 使用由 Bisq 貢獻者運行的區塊瀏覽器節點,但是我們建議運行您自己的 XMR 區塊瀏覽器節點以最大程度地保護隱私和安全。\n\n您還可以在``設置''中將每筆交易的最大 BTC 數量設置為自動確認以及所需確認的數量。\n\n在 Bisq Wiki 上查看更多詳細信息(包括如何設置自己的區塊瀏覽器節點):https://bisq.wiki/Trading_Monero#Auto-confirming_trades #################################################################### # Account #################################################################### @@ -1154,16 +1171,26 @@ setting.info.msg=當你完成 BTC/XMR 交易時,您可以使用自動確認功 account.tab.mediatorRegistration=調解員註冊 account.tab.refundAgentRegistration=退款助理註冊 account.tab.signing=驗證中 -account.info.headline=歡迎來到 Bisq 賬戶 -account.info.msg=在這裡你可以設定交易賬戶的法定貨幣及數字貨幣,選擇仲裁員和備份你的錢包及賬戶資料。\n\n當你開始執行 Bisq 就已經建立了一個空的比特幣錢包。\n\n我們建議你在充值之前寫下你比特幣錢包的還原金鑰(在左邊的列表)和考慮新增密碼。在“資金”選項中管理比特幣存入和提現。\n\n隱私 & 安全:\nBisq 是一個去中心化的交易所 – 意味著您的所有資料都儲存在您的電腦上,沒有伺服器,我們無法訪問您的個人資訊,您的資金,甚至您的 IP 地址。如銀行賬號、數字貨幣、比特幣地址等資料只分享給與您交易的人,以實現您發起的交易(如果有爭議,仲裁員將會看到您的交易資料)。 +account.info.headline=歡迎來到 Bisq 賬户 +account.info.msg=在這裏你可以設置交易賬户的法定貨幣及數字貨幣,選擇仲裁員和備份你的錢包及賬户數據。\n\n當你開始運行 Bisq 就已經創建了一個空的比特幣錢包。\n\n我們建議你在充值之前寫下你比特幣錢包的還原密鑰(在左邊的列表)和考慮添加密碼。在“資金”選項中管理比特幣存入和提現。\n\n隱私 & 安全:\nBisq 是一個去中心化的交易所 – 意味着您的所有數據都保存在您的電腦上,沒有服務器,我們無法訪問您的個人信息,您的資金,甚至您的 IP 地址。如銀行賬號、數字貨幣、比特幣地址等數據只分享給與您交易的人,以實現您發起的交易(如果有爭議,仲裁員將會看到您的交易數據)。 -account.menu.paymentAccount=法定貨幣賬戶 -account.menu.altCoinsAccountView=數字貨幣賬戶 +account.menu.paymentAccount=法定貨幣賬户 +account.menu.altCoinsAccountView=數字貨幣賬户 account.menu.password=錢包密碼 -account.menu.seedWords=錢包金鑰 +account.menu.seedWords=錢包密鑰 +account.menu.walletInfo=Wallet info account.menu.backup=備份 account.menu.notifications=通知 +account.menu.walletInfo.balance.headLine=Wallet balances +account.menu.walletInfo.balance.info=This shows the internal wallet balance including unconfirmed transactions.\nFor BTC, the internal wallet balance shown below should match the sum of the 'Available' and 'Reserved' balances shown in the top right of this window. +account.menu.walletInfo.xpub.headLine=Watch keys (xpub keys) +account.menu.walletInfo.walletSelector={0} {1} wallet +account.menu.walletInfo.path.headLine=HD keychain paths +account.menu.walletInfo.path.info=If you import seed words into another wallet (like Electrum), you'll need to define the path. This should only be done in emergency cases when you lose access to the Bisq wallet and data directory.\nKeep in mind that spending funds from a non-Bisq wallet can bungle the internal Bisq data structures associated with the wallet data, which can lead to failed trades.\n\nNEVER send BSQ from a non-Bisq wallet, as it will probably lead to an invalid BSQ transaction and losing your BSQ. + +account.menu.walletInfo.openDetails=Show raw wallet details and private keys + ## TODO should we rename the following to a gereric name? account.arbitratorRegistration.pubKey=公鑰 @@ -1171,75 +1198,75 @@ account.arbitratorRegistration.register=註冊 account.arbitratorRegistration.registration={0} 註冊 account.arbitratorRegistration.revoke=撤銷 account.arbitratorRegistration.info.msg=請注意,撤銷後需要保留15天,因為可能有交易正在以你作為 {0}。最大允許的交易期限為8天,糾紛過程最多可能需要7天。 -account.arbitratorRegistration.warn.min1Language=您需要設定至少1種語言。\n我們已經為您新增了預設語言。 -account.arbitratorRegistration.removedSuccess=您已從 Bisq 網路成功刪除仲裁員註冊資訊。 +account.arbitratorRegistration.warn.min1Language=您需要設置至少1種語言。\n我們已經為您添加了默認語言。 +account.arbitratorRegistration.removedSuccess=您已從 Bisq 網絡成功刪除仲裁員註冊信息。 account.arbitratorRegistration.removedFailed=無法刪除仲裁員。{0} -account.arbitratorRegistration.registerSuccess=您已從 Bisq 網路成功註冊您的仲裁員。 +account.arbitratorRegistration.registerSuccess=您已從 Bisq 網絡成功註冊您的仲裁員。 account.arbitratorRegistration.registerFailed=無法註冊仲裁員。{0} -account.altcoin.yourAltcoinAccounts=您的數字貨幣賬戶 -account.altcoin.popup.wallet.msg=請確保您按照 {1} 網頁上所述使用 {0} 錢包的要求。\n使用集中式交易所的錢包,您無法控制金鑰或使用不相容的錢包軟體,可能會導致交易資金的流失!\n調解員或仲裁員不是 {2} 專家,在這種情況下不能幫助。 +account.altcoin.yourAltcoinAccounts=您的數字貨幣賬户 +account.altcoin.popup.wallet.msg=請確保您按照 {1} 網頁上所述使用 {0} 錢包的要求。\n使用集中式交易所的錢包,您無法控制密鑰或使用不兼容的錢包軟件,可能會導致交易資金的流失!\n調解員或仲裁員不是 {2} 專家,在這種情況下不能幫助。 account.altcoin.popup.wallet.confirm=我瞭解並確定我知道我需要哪種錢包。 # suppress inspection "UnusedProperty" -account.altcoin.popup.upx.msg=在 Bisq 上交易 UPX 需要您瞭解並滿足以下要求:\n\n要傳送 UPX ,您需要使用官方的 UPXmA GUI 錢包或啟用 store-tx-info 標誌的 UPXmA CLI 錢包(在新版本中是預設的)。請確保您可以訪問Tx金鑰,因為在糾紛狀態時需要。\nmonero-wallet-cli(使用get_Tx_key命令)\nmonero-wallet-gui:在高階>證明/檢查頁面。\n\n在普通的區塊鏈瀏覽器中,這種交易是不可驗證的。\n\n如有糾紛,你須向仲裁員提供下列資料:\n \n- Tx私鑰\n- 交易雜湊\n- 接收者的公開地址\n\n如未能提供上述資料,或使用不相容的錢包,將會導致糾紛敗訴。如果發生糾紛,UPX 傳送方負責向仲裁員提供 UPX 轉賬的驗證。\n\n不需要支付 ID,只需要普通的公共地址。\n \n如果您對該流程不確定,請訪問 UPXmA Discord 頻道(https://discord.gg/vhdNSrV)或 Telegram 交流群(https://t.me/uplexaOfficial)瞭解更多資訊。\n\n +account.altcoin.popup.upx.msg=在 Bisq 上交易 UPX 需要您瞭解並滿足以下要求:\n\n要發送 UPX ,您需要使用官方的 UPXmA GUI 錢包或啟用 store-tx-info 標誌的 UPXmA CLI 錢包(在新版本中是默認的)。請確保您可以訪問Tx密鑰,因為在糾紛狀態時需要。\nmonero-wallet-cli(使用get_Tx_key命令)\nmonero-wallet-gui:在高級>證明/檢查頁面。\n\n在普通的區塊鏈瀏覽器中,這種交易是不可驗證的。\n\n如有糾紛,你須向仲裁員提供下列資料:\n \n- Tx私鑰\n- 交易哈希\n- 接收者的公開地址\n\n如未能提供上述資料,或使用不兼容的錢包,將會導致糾紛敗訴。如果發生糾紛,UPX 發送方負責向仲裁員提供 UPX 轉賬的驗證。\n\n不需要支付 ID,只需要普通的公共地址。\n \n如果您對該流程不確定,請訪問 UPXmA Discord 頻道(https://discord.gg/vhdNSrV)或 Telegram 交流羣(https://t.me/uplexaOfficial)瞭解更多信息。\n\n # suppress inspection "UnusedProperty" -account.altcoin.popup.arq.msg=在 Bisq 上交易 ARQ 需要您瞭解並滿足以下要求:\n\n要傳送 ARQ ,您需要使用官方的 ArQmA GUI 錢包或啟用 store-tx-info 標誌的 ArQmA CLI 錢包(在新版本中是預設的)。請確保您可以訪問Tx金鑰,因為在糾紛狀態時需要。\nmonero-wallet-cli(使用get_Tx_key命令)\nmonero-wallet-gui:在高階>證明/檢查頁面。\n\n在普通的區塊鏈瀏覽器中,這種交易是不可驗證的。\n\n如有糾紛,你須向調解員或仲裁員提供下列資料:\n\n- Tx私鑰\n- 交易雜湊\n- 接收者的公開地址\n\n如未能提供上述資料,或使用不相容的錢包,將會導致糾紛敗訴。如果發生糾紛,ARQ 傳送方負責向調解員或仲裁員提供 ARQ 轉賬的驗證。\n\n不需要交易 ID,只需要普通的公共地址。\n\n如果您對該流程不確定,請訪問 ArQmA Discord 頻道(https://discord.gg/s9BQpJT)或 ArQmA 論壇(https://labs.arqma.com)瞭解更多資訊。 +account.altcoin.popup.arq.msg=在 Bisq 上交易 ARQ 需要您瞭解並滿足以下要求:\n\n要發送 ARQ ,您需要使用官方的 ArQmA GUI 錢包或啟用 store-tx-info 標誌的 ArQmA CLI 錢包(在新版本中是默認的)。請確保您可以訪問Tx密鑰,因為在糾紛狀態時需要。\nmonero-wallet-cli(使用get_Tx_key命令)\nmonero-wallet-gui:在高級>證明/檢查頁面。\n\n在普通的區塊鏈瀏覽器中,這種交易是不可驗證的。\n\n如有糾紛,你須向調解員或仲裁員提供下列資料:\n\n- Tx私鑰\n- 交易哈希\n- 接收者的公開地址\n\n如未能提供上述資料,或使用不兼容的錢包,將會導致糾紛敗訴。如果發生糾紛,ARQ 發送方負責向調解員或仲裁員提供 ARQ 轉賬的驗證。\n\n不需要交易 ID,只需要普通的公共地址。\n\n如果您對該流程不確定,請訪問 ArQmA Discord 頻道(https://discord.gg/s9BQpJT)或 ArQmA 論壇(https://labs.arqma.com)瞭解更多信息。 # suppress inspection "UnusedProperty" -account.altcoin.popup.xmr.msg=在 Bisq 上交易 XMR 需要你理解並滿足以下要求。\n\n如果您出售 XMR,當您在糾紛中您必須要提供下列資訊給調解員或仲裁員:\n- 交易金鑰(Tx 公鑰,Tx金鑰,Tx私鑰)\n- 交易 ID(Tx ID 或 Tx 雜湊)\n- 交易目標地址(接收者地址)\n\n在 wiki 中檢視更多關於 Monero 錢包的資訊:\nhttps://bisq.wiki/Trading_Monero#Proving_payments\n\n如未能提供要求的交易資料將在糾紛中直接判負\n\n還要注意,Bisq 現在提供了自動確認 XMR 交易的功能,以使交易更快,但是您需要在設定中啟用它。\n\n有關自動確認功能的更多資訊,請參見 Wiki:\nhttps://bisq.wiki/Trading_Monero#Auto-confirming_trades +account.altcoin.popup.xmr.msg=在 Bisq 上交易 XMR 需要你理解並滿足以下要求。\n\n如果您出售 XMR,當您在糾紛中您必須要提供下列信息給調解員或仲裁員:\n- 交易密鑰(Tx 公鑰,Tx密鑰,Tx私鑰)\n- 交易 ID(Tx ID 或 Tx 哈希)\n- 交易目標地址(接收者地址)\n\n在 wiki 中查看更多關於 Monero 錢包的信息:\nhttps://bisq.wiki/Trading_Monero#Proving_payments\n\n如未能提供要求的交易數據將在糾紛中直接判負\n\n還要注意,Bisq 現在提供了自動確認 XMR 交易的功能,以使交易更快,但是您需要在設置中啟用它。\n\n有關自動確認功能的更多信息,請參見 Wiki:\nhttps://bisq.wiki/Trading_Monero#Auto-confirming_trades # suppress inspection "UnusedProperty" -account.altcoin.popup.msr.msg=區塊鏈瀏覽器在 Bisq 上交易 XMR 需要您瞭解並滿足以下要求:\n\n傳送MSR時,您需要使用官方的 Masari GUI 錢包、啟用store-tx-info標記的Masari CLI錢包(預設啟用)或Masari 網頁錢包(https://wallet.getmasari.org)。請確保您可以訪問的 tx 金鑰,因為如果發生糾紛這是需要的。\nmonero-wallet-cli(使用get_Tx_key命令)\nmonero-wallet-gui:在高階>證明/檢查頁面。\n\nMasari 網頁錢包(前往 帳戶->交易歷史和檢視您傳送的交易細節)\n\n驗證可以在錢包中完成。\nmonero-wallet-cli:使用命令(check_tx_key)。\nmonero-wallet-gui:在高階>證明/檢查頁面\n驗證可以在區塊瀏覽器中完成\n開啟區塊瀏覽器(https://explorer.getmasari.org),使用搜尋欄查詢您的事務雜湊。\n一旦找到交易,滾動到底部的“證明傳送”區域,並填寫所需的詳細資訊。\n如有糾紛,你須向調解員或仲裁員提供下列資料:\n- Tx私鑰\n- 交易雜湊\n- 接收者的公開地址\n\n不需要交易 ID,只需要正常的公共地址。\n如未能提供上述資料,或使用不相容的錢包,將會導致糾紛敗訴。如果發生糾紛,XMR 傳送方負責向調解員或仲裁員提供 XMR 轉賬的驗證。\n\n如果您對該流程不確定,請訪問官方的 Masari Discord(https://discord.gg/sMCwMqs)上尋求幫助。 +account.altcoin.popup.msr.msg=區塊鏈瀏覽器在 Bisq 上交易 XMR 需要您瞭解並滿足以下要求:\n\n發送MSR時,您需要使用官方的 Masari GUI 錢包、啟用store-tx-info標記的Masari CLI錢包(默認啟用)或Masari 網頁錢包(https://wallet.getmasari.org)。請確保您可以訪問的 tx 密鑰,因為如果發生糾紛這是需要的。\nmonero-wallet-cli(使用get_Tx_key命令)\nmonero-wallet-gui:在高級>證明/檢查頁面。\n\nMasari 網頁錢包(前往 帳户->交易歷史和查看您發送的交易細節)\n\n驗證可以在錢包中完成。\nmonero-wallet-cli:使用命令(check_tx_key)。\nmonero-wallet-gui:在高級>證明/檢查頁面\n驗證可以在區塊瀏覽器中完成\n打開區塊瀏覽器(https://explorer.getmasari.org),使用搜索欄查找您的事務哈希。\n一旦找到交易,滾動到底部的“證明發送”區域,並填寫所需的詳細信息。\n如有糾紛,你須向調解員或仲裁員提供下列資料:\n- Tx私鑰\n- 交易哈希\n- 接收者的公開地址\n\n不需要交易 ID,只需要正常的公共地址。\n如未能提供上述資料,或使用不兼容的錢包,將會導致糾紛敗訴。如果發生糾紛,XMR 發送方負責向調解員或仲裁員提供 XMR 轉賬的驗證。\n\n如果您對該流程不確定,請訪問官方的 Masari Discord(https://discord.gg/sMCwMqs)上尋求幫助。 # suppress inspection "UnusedProperty" -account.altcoin.popup.blur.msg=在 Bisq 上交易 BLUR 需要你瞭解並滿足以下要求:\n\n要傳送匿名資訊你必須使用匿名網路 CLI 或 GUI 錢包。\n如果您正在使用 CLI 錢包,在傳輸傳送後將顯示交易雜湊(tx ID)。您必須儲存此資訊。在傳送傳輸之後,您必須立即使用“get_tx_key”命令來檢索交易私鑰。如果未能執行此步驟,以後可能無法檢索金鑰。\n\n如果您使用 Blur Network GUI 錢包,可以在“歷史”選項卡中方便地找到交易私鑰和交易 ID。傳送後立即定位感興趣的交易。單擊包含交易的框的右下角的“?”符號。您必須儲存此資訊。\n\n如果仲裁是必要的,您必須向調解員或仲裁員提供以下資訊:1.)交易ID,2.)交易私鑰,3.)收件人地址。調解或仲裁程式將使用 BLUR 事務檢視器(https://blur.cash/#tx-viewer)驗證 BLUR 轉賬。\n\n未能向調解員或仲裁員提供必要的資訊將導致敗訴。在所有爭議的情況下,匿名傳送方承擔100%的責任來向調解員或仲裁員核實交易。\n\n如果你不瞭解這些要求,不要在 Bisq 上交易。首先,在 Blur Network Discord 中尋求幫助(https://discord.gg/dMWaqVW)。 +account.altcoin.popup.blur.msg=在 Bisq 上交易 BLUR 需要你瞭解並滿足以下要求:\n\n要發送匿名信息你必須使用匿名網絡 CLI 或 GUI 錢包。\n如果您正在使用 CLI 錢包,在傳輸發送後將顯示交易哈希(tx ID)。您必須保存此信息。在發送傳輸之後,您必須立即使用“get_tx_key”命令來檢索交易私鑰。如果未能執行此步驟,以後可能無法檢索密鑰。\n\n如果您使用 Blur Network GUI 錢包,可以在“歷史”選項卡中方便地找到交易私鑰和交易 ID。發送後立即定位感興趣的交易。單擊包含交易的框的右下角的“?”符號。您必須保存此信息。\n\n如果仲裁是必要的,您必須向調解員或仲裁員提供以下信息:1.)交易ID,2.)交易私鑰,3.)收件人地址。調解或仲裁程序將使用 BLUR 事務查看器(https://blur.cash/#tx-viewer)驗證 BLUR 轉賬。\n\n未能向調解員或仲裁員提供必要的信息將導致敗訴。在所有爭議的情況下,匿名發送方承擔100%的責任來向調解員或仲裁員核實交易。\n\n如果你不瞭解這些要求,不要在 Bisq 上交易。首先,在 Blur Network Discord 中尋求幫助(https://discord.gg/dMWaqVW)。 # suppress inspection "UnusedProperty" -account.altcoin.popup.solo.msg=在 Bisq 上交易 Solo 需要您瞭解並滿足以下要求:\n\n要傳送 Solo,您必須使用 Solo CLI 網路錢包版本 5.1.3 或更高。\n\n如果您使用的是CLI錢包,則在傳送交易之後,將顯示交易ID。您必須儲存此資訊。在傳送交易之後,您必須立即使用'get_tx_key'命令來檢索交易金鑰。如果未能執行此步驟,則以後可能無法檢索金鑰。\n\n如果仲裁是必要的,您必須向調解員或仲裁員提供以下資訊:1)交易 ID,、2)交易金鑰,3)收件人的地址。調解員或仲裁員將使用 Solo 區塊資源管理器(https://explorer.Solo.org)搜尋交易然後使用“傳送證明”功能(https://explorer.minesolo.com/)\n\n未能向調解員或仲裁員提供必要的資訊將導致敗訴。在所有發生爭議的情況下,在向調解員或仲裁員核實交易時,QWC 的傳送方承擔 100% 的責任。\n\n如果你不理解這些要求,不要在 Bisq 上交易。首先,在 Solo Discord 中尋求幫助(https://discord.minesolo.com/)。\n\n +account.altcoin.popup.solo.msg=在 Bisq 上交易 Solo 需要您瞭解並滿足以下要求:\n\n要發送 Solo,您必須使用 Solo CLI 網絡錢包版本 5.1.3 或更高。\n\n如果您使用的是CLI錢包,則在發送交易之後,將顯示交易ID。您必須保存此信息。在發送交易之後,您必須立即使用'get_tx_key'命令來檢索交易密鑰。如果未能執行此步驟,則以後可能無法檢索密鑰。\n\n如果仲裁是必要的,您必須向調解員或仲裁員提供以下信息:1)交易 ID,、2)交易密鑰,3)收件人的地址。調解員或仲裁員將使用 Solo 區塊資源管理器(https://explorer.Solo.org)搜索交易然後使用“發送證明”功能(https://explorer.minesolo.com/)\n\n未能向調解員或仲裁員提供必要的信息將導致敗訴。在所有發生爭議的情況下,在向調解員或仲裁員核實交易時,QWC 的發送方承擔 100% 的責任。\n\n如果你不理解這些要求,不要在 Bisq 上交易。首先,在 Solo Discord 中尋求幫助(https://discord.minesolo.com/)。\n\n # suppress inspection "UnusedProperty" -account.altcoin.popup.cash2.msg=在 Bisq 上交易 CASH2 需要您瞭解並滿足以下要求:\n\n要傳送 CASH2,您必須使用 CASH2 錢包版本 3 或更高。\n\n在傳送交易之後,將顯示交易ID。您必須儲存此資訊。在傳送交易之後,必須立即在 simplewallet 中使用命令“getTxKey”來檢索交易金鑰。\n\n如果仲裁是必要的,您必須向調解員或仲裁員提供以下資訊:1)交易 ID,2)交易金鑰,3)收件人的 CASH2 地址。調解員或仲裁員將使用 CASH2 區塊資源管理器(https://blocks.cash2.org)驗證 CASH2 轉賬。\n\n未能向調解員或仲裁員提供必要的資訊將導致敗訴。在所有發生爭議的情況下,在向調解員或仲裁員核實交易時,CASH2 的傳送方承擔 100% 的責任。\n\n如果你不理解這些要求,不要在 Bisq 上交易。首先,在 Cash2 Discord 中尋求幫助(https://discord.gg/FGfXAYN)。 +account.altcoin.popup.cash2.msg=在 Bisq 上交易 CASH2 需要您瞭解並滿足以下要求:\n\n要發送 CASH2,您必須使用 CASH2 錢包版本 3 或更高。\n\n在發送交易之後,將顯示交易ID。您必須保存此信息。在發送交易之後,必須立即在 simplewallet 中使用命令“getTxKey”來檢索交易密鑰。\n\n如果仲裁是必要的,您必須向調解員或仲裁員提供以下信息:1)交易 ID,2)交易密鑰,3)收件人的 CASH2 地址。調解員或仲裁員將使用 CASH2 區塊資源管理器(https://blocks.cash2.org)驗證 CASH2 轉賬。\n\n未能向調解員或仲裁員提供必要的信息將導致敗訴。在所有發生爭議的情況下,在向調解員或仲裁員核實交易時,CASH2 的發送方承擔 100% 的責任。\n\n如果你不理解這些要求,不要在 Bisq 上交易。首先,在 Cash2 Discord 中尋求幫助(https://discord.gg/FGfXAYN)。 # suppress inspection "UnusedProperty" -account.altcoin.popup.qwertycoin.msg=在 Bisq 上交易 Qwertycoin 需要您瞭解並滿足以下要求:\n\n要傳送 Qwertycoin,您必須使用 Qwertycoin 錢包版本 5.1.3 或更高。\n\n在傳送交易之後,將顯示交易ID。您必須儲存此資訊。在傳送交易之後,必須立即在 simplewallet 中使用命令“get_Tx_Key”來檢索交易金鑰。\n\n如果仲裁是必要的,您必須向調解員或仲裁員提供以下資訊::1)交易 ID,、2)交易金鑰,3)收件人的 QWC 地址。調解員或仲裁員將使用 QWC 區塊資源管理器(https://explorer.qwertycoin.org)驗證 QWC 轉賬。\n\n未能向調解員或仲裁員提供必要的資訊將導致敗訴。在所有發生爭議的情況下,在向調解員或仲裁員核實交易時,QWC 的傳送方承擔 100% 的責任。\n\n如果你不理解這些要求,不要在 Bisq 上交易。首先,在 QWC Discord 中尋求幫助(https://discord.gg/rUkfnpC)。 +account.altcoin.popup.qwertycoin.msg=在 Bisq 上交易 Qwertycoin 需要您瞭解並滿足以下要求:\n\n要發送 Qwertycoin,您必須使用 Qwertycoin 錢包版本 5.1.3 或更高。\n\n在發送交易之後,將顯示交易ID。您必須保存此信息。在發送交易之後,必須立即在 simplewallet 中使用命令“get_Tx_Key”來檢索交易密鑰。\n\n如果仲裁是必要的,您必須向調解員或仲裁員提供以下信息::1)交易 ID,、2)交易密鑰,3)收件人的 QWC 地址。調解員或仲裁員將使用 QWC 區塊資源管理器(https://explorer.qwertycoin.org)驗證 QWC 轉賬。\n\n未能向調解員或仲裁員提供必要的信息將導致敗訴。在所有發生爭議的情況下,在向調解員或仲裁員核實交易時,QWC 的發送方承擔 100% 的責任。\n\n如果你不理解這些要求,不要在 Bisq 上交易。首先,在 QWC Discord 中尋求幫助(https://discord.gg/rUkfnpC)。 # suppress inspection "UnusedProperty" -account.altcoin.popup.drgl.msg=在 Bisq 上交易 Dragonglass 需要您瞭解並滿足以下要求:\n\n由於 Dragonglass 提供了隱私保護,所以交易不能在公共區塊鏈上驗證。如果需要,您可以通過使用您的 TXN-Private-Key 來證明您的付款。\nTXN-Private 密匙是自動生成的一次性密匙,用於只能從 DRGL 錢包中訪問的每個交易。\n要麼通過 DRGL-wallet GUI(內部交易細節對話方塊),要麼通過 Dragonglass CLI simplewallet(使用命令“get_tx_key”)。\n\n兩者都需要 DRGL 版本的“Oathkeeper”或更高版本。\n\n如有爭議,你必須向調解員或仲裁員提供下列資料:\n\n- txn-Privite-ket\n- 交易雜湊 \n- 接收者的公開地址\n\n付款驗證可以使用上面的資料作為輸入(http://drgl.info/#check_txn)。\n\n如未能提供上述資料,或使用不相容的錢包,將會導致糾紛敗訴。Dragonglass 傳送方負責在發生爭議時向調解員或仲裁員提供 DRGL 轉賬的驗證。不需要使用付款 ID。\n\n如果您對這個過程的任何部分都不確定,請訪問(http://discord.drgl.info)上的 Dragonglass 尋求幫助。 +account.altcoin.popup.drgl.msg=在 Bisq 上交易 Dragonglass 需要您瞭解並滿足以下要求:\n\n由於 Dragonglass 提供了隱私保護,所以交易不能在公共區塊鏈上驗證。如果需要,您可以通過使用您的 TXN-Private-Key 來證明您的付款。\nTXN-Private 密匙是自動生成的一次性密匙,用於只能從 DRGL 錢包中訪問的每個交易。\n要麼通過 DRGL-wallet GUI(內部交易細節對話框),要麼通過 Dragonglass CLI simplewallet(使用命令“get_tx_key”)。\n\n兩者都需要 DRGL 版本的“Oathkeeper”或更高版本。\n\n如有爭議,你必須向調解員或仲裁員提供下列資料:\n\n- txn-Privite-ket\n- 交易哈希 \n- 接收者的公開地址\n\n付款驗證可以使用上面的數據作為輸入(http://drgl.info/#check_txn)。\n\n如未能提供上述資料,或使用不兼容的錢包,將會導致糾紛敗訴。Dragonglass 發送方負責在發生爭議時向調解員或仲裁員提供 DRGL 轉賬的驗證。不需要使用付款 ID。\n\n如果您對這個過程的任何部分都不確定,請訪問(http://discord.drgl.info)上的 Dragonglass 尋求幫助。 # suppress inspection "UnusedProperty" account.altcoin.popup.ZEC.msg=當使用 Zcash 時,您只能使用透明地址(以 t 開頭),而不能使用 z 地址(私有),因為調解員或仲裁員無法使用 z 地址驗證交易。 # suppress inspection "UnusedProperty" account.altcoin.popup.XZC.msg=在使用 Zcoin 時,您只能使用透明的(可跟蹤的)地址,而不能使用不可跟蹤的地址,因為調解員或仲裁員無法在區塊資源管理器中使用不可跟蹤的地址驗證交易。 # suppress inspection "UnusedProperty" -account.altcoin.popup.grin.msg=GRIN 需要傳送方和接收方之間的互動過程來建立交易。請確保遵循 GRIN 專案網頁中的說明,以可靠地傳送和接收 GRIN(接收方需要線上,或至少在一定時間內線上)。\n \nBisq 只支援 Grinbox(Wallet713)錢包 URL 格式。\n\nGRIN 傳送者需要提供他們已成功傳送 GRIN 的證明。如果錢包不能提供證明,一個潛在的糾紛將被解決,有利於露齒微笑的接受者。請確保您使用了最新的支援交易證明的 Grinbox 軟體,並且您瞭解傳輸和接收 GRIN 的過程以及如何建立證明。\n請參閱 https://github.com/vault713/wallet713/blob/master/docs/usage.md#transaction-proofs-grinbox-only,以獲得關於 Grinbox 證明工具的更多資訊。\n +account.altcoin.popup.grin.msg=GRIN 需要發送方和接收方之間的交互過程來創建交易。請確保遵循 GRIN 項目網頁中的説明,以可靠地發送和接收 GRIN(接收方需要在線,或至少在一定時間內在線)。\n \nBisq 只支持 Grinbox(Wallet713)錢包 URL 格式。\n\nGRIN 發送者需要提供他們已成功發送 GRIN 的證明。如果錢包不能提供證明,一個潛在的糾紛將被解決,有利於露齒微笑的接受者。請確保您使用了最新的支持交易證明的 Grinbox 軟件,並且您瞭解傳輸和接收 GRIN 的過程以及如何創建證明。\n請參閲 https://github.com/vault713/wallet713/blob/master/docs/usage.md#transaction-proofs-grinbox-only,以獲得關於 Grinbox 證明工具的更多信息。\n # suppress inspection "UnusedProperty" -account.altcoin.popup.beam.msg=BEAM 需要傳送方和接收方之間的互動過程來建立交易。\n\n\n確保遵循 BEAM 專案網頁的指示可靠地傳送和接收 BEAM(接收方需要線上,或者至少在一定的時間範圍內線上)。\n\nBEAM 傳送者需要提供他們成功傳送 BEAM 的證明。一定要使用錢包軟體,可以產生這樣的證明。如果錢包不能提供證據,一個潛在的糾紛將得到解決,有利於 BEAM 接收者。 +account.altcoin.popup.beam.msg=BEAM 需要發送方和接收方之間的交互過程來創建交易。\n\n\n確保遵循 BEAM 項目網頁的指示可靠地發送和接收 BEAM(接收方需要在線,或者至少在一定的時間範圍內在線)。\n\nBEAM 發送者需要提供他們成功發送 BEAM 的證明。一定要使用錢包軟件,可以產生這樣的證明。如果錢包不能提供證據,一個潛在的糾紛將得到解決,有利於 BEAM 接收者。 # suppress inspection "UnusedProperty" -account.altcoin.popup.pars.msg=在 Bisq 上交易 ParsiCoin 需要您瞭解並滿足以下要求:\n\n要傳送 PARS ,您必須使用官方 ParsiCoin Wallet 版本 3.0.0 或更高。\n\n您可以在 GUI 錢包(ParsiPay)的交易部分檢查您的交易雜湊和交易鍵,您需要右鍵單擊“交易”,然後單擊“顯示詳情”。\n\n如果仲裁是 100% 必要的,您必須向調解員或仲裁員提供以下內容:1)交易雜湊,2)交易金鑰,以及3)接收方的 PARS 地址。調解員或仲裁員將使用 ParsiCoin 區塊鏈瀏覽器 (http://explorer.parsicoin.net/#check_payment)驗證 PARS 傳輸。\n\n如果你不瞭解這些要求,不要在 Bisq 上交易。首先,在 ParsiCoin Discord 尋求幫助(https://discord.gg/c7qmFNh)。 +account.altcoin.popup.pars.msg=在 Bisq 上交易 ParsiCoin 需要您瞭解並滿足以下要求:\n\n要發送 PARS ,您必須使用官方 ParsiCoin Wallet 版本 3.0.0 或更高。\n\n您可以在 GUI 錢包(ParsiPay)的交易部分檢查您的交易哈希和交易鍵,您需要右鍵單擊“交易”,然後單擊“顯示詳情”。\n\n如果仲裁是 100% 必要的,您必須向調解員或仲裁員提供以下內容:1)交易哈希,2)交易密鑰,以及3)接收方的 PARS 地址。調解員或仲裁員將使用 ParsiCoin 區塊鏈瀏覽器 (http://explorer.parsicoin.net/#check_payment)驗證 PARS 傳輸。\n\n如果你不瞭解這些要求,不要在 Bisq 上交易。首先,在 ParsiCoin Discord 尋求幫助(https://discord.gg/c7qmFNh)。 # suppress inspection "UnusedProperty" -account.altcoin.popup.blk-burnt.msg=要交易燒燬的貨幣,你需要知道以下幾點:\n\n燒燬的貨幣是不能花的。要在 Bisq 上交易它們,輸出指令碼需要採用以下形式:OP_RETURN OP_PUSHDATA,後跟相關的資料位元組,這些位元組經過十六進位制編碼後構成地址。例如,地址為666f6f(在UTF-8中的"foo")的燒燬的貨幣將有以下指令碼:\n\nOP_RETURN OP_PUSHDATA 666f6f\n\n要建立燒燬的貨幣,您可以使用“燒燬”RPC命令,它在一些錢包可用。\n\n對於可能的情況,可以檢視 https://ibo.laboratorium.ee\n\n因為燒燬的貨幣是不能用的,所以不能重新出售。“出售”燒燬的貨幣意味著焚燒初始的貨幣(與目的地地址相關聯的資料)。\n\n如果發生爭議,BLK 賣方需要提供交易雜湊。 +account.altcoin.popup.blk-burnt.msg=要交易燒燬的貨幣,你需要知道以下幾點:\n\n燒燬的貨幣是不能花的。要在 Bisq 上交易它們,輸出腳本需要採用以下形式:OP_RETURN OP_PUSHDATA,後跟相關的數據字節,這些字節經過十六進制編碼後構成地址。例如,地址為666f6f(在UTF-8中的"foo")的燒燬的貨幣將有以下腳本:\n\nOP_RETURN OP_PUSHDATA 666f6f\n\n要創建燒燬的貨幣,您可以使用“燒燬”RPC命令,它在一些錢包可用。\n\n對於可能的情況,可以查看 https://ibo.laboratorium.ee\n\n因為燒燬的貨幣是不能用的,所以不能重新出售。“出售”燒燬的貨幣意味着焚燒初始的貨幣(與目的地地址相關聯的數據)。\n\n如果發生爭議,BLK 賣方需要提供交易哈希。 # suppress inspection "UnusedProperty" -account.altcoin.popup.liquidbitcoin.msg=在 Bisq 上交易 L-BTC 你必須理解下述條款:\n\n當你在 Bisq 上接受 L-BTC 交易時,你不能使用手機 Blockstream Green Wallet 或者是一個託管/交易錢包。你必須只接收 L-BTC 到 Liquid Elements Core 錢包,或另一個 L-BTC 錢包且允許你獲得匿名的 L-BTC 地址以及金鑰。\n\n在需要進行調解的情況下,或者如果發生了交易糾紛,您必須將接收 L-BTC地址的安全金鑰披露給 Bisq 調解員或退款代理,以便他們能夠在他們自己的 Elements Core 全節點上驗證您的匿名交易的細節。\n\n如果你不瞭解或瞭解這些要求,不要在 Bisq 上交易 L-BTC。 +account.altcoin.popup.liquidbitcoin.msg=在 Bisq 上交易 L-BTC 你必須理解下述條款:\n\n當你在 Bisq 上接受 L-BTC 交易時,你不能使用手機 Blockstream Green Wallet 或者是一個託管/交易錢包。你必須只接收 L-BTC 到 Liquid Elements Core 錢包,或另一個 L-BTC 錢包且允許你獲得匿名的 L-BTC 地址以及密鑰。\n\n在需要進行調解的情況下,或者如果發生了交易糾紛,您必須將接收 L-BTC地址的安全密鑰披露給 Bisq 調解員或退款代理,以便他們能夠在他們自己的 Elements Core 全節點上驗證您的匿名交易的細節。\n\n如果你不瞭解或瞭解這些要求,不要在 Bisq 上交易 L-BTC。 -account.fiat.yourFiatAccounts=您的法定貨幣賬戶 +account.fiat.yourFiatAccounts=您的法定貨幣賬户 account.backup.title=備份錢包 account.backup.location=備份路徑 account.backup.selectLocation=選擇備份路徑 account.backup.backupNow=立即備份(備份沒有被加密!) -account.backup.appDir=應用程式資料目錄 -account.backup.openDirectory=開啟目錄 -account.backup.openLogFile=開啟日誌檔案 -account.backup.success=備份成功儲存在:\n{0} -account.backup.directoryNotAccessible=您沒有訪問選擇的目錄的許可權。 {0} +account.backup.appDir=應用程序數據目錄 +account.backup.openDirectory=打開目錄 +account.backup.openLogFile=打開日誌文件 +account.backup.success=備份成功保存在:\n{0} +account.backup.directoryNotAccessible=您沒有訪問選擇的目錄的權限。 {0} account.password.removePw.button=移除密碼 account.password.removePw.headline=移除錢包的密碼保護 -account.password.setPw.button=設定密碼 -account.password.setPw.headline=設定錢包的密碼保護 -account.password.info=使用密碼保護,您需要在將比特幣從錢包中取出時輸入密碼,或者要從還原金鑰和應用程式啟動時檢視或恢復錢包時輸入密碼。 +account.password.setPw.button=設置密碼 +account.password.setPw.headline=設置錢包的密碼保護 +account.password.info=使用密碼保護,您需要在將比特幣從錢包中取出時輸入密碼,或者要從還原密鑰和應用程序啟動時查看或恢復錢包時輸入密碼。 -account.seed.backup.title=備份您的錢包還原金鑰 -account.seed.info=請寫下錢包還原金鑰和時間!\n您可以通過還原金鑰和時間在任何時候恢復您的錢包。\n還原金鑰用於 BTC 和 BSQ 錢包。\n\n您應該在一張紙上寫下還原金鑰並且不要儲存它們在您的電腦上。\n請注意還原金鑰並不能代替備份。\n您需要備份完整的應用程式目錄在”賬戶/備份“介面去恢復有效的應用程式狀態和資料。 -account.seed.backup.warning=請注意種子詞不能替代備份。您需要為整個應用目錄(在“賬戶/備份”選項卡中)以恢復應用狀態以及資料。\n匯入種子詞僅在緊急情況時才推薦使用。 如果沒有正確備份資料庫檔案和金鑰,該應用程式將無法執行!\n\n在 Bisq wiki 中檢視更多資訊: https://bisq.wiki/Backing_up_application_data -account.seed.warn.noPw.msg=您還沒有設定一個可以保護還原金鑰顯示的錢包密碼。\n\n要顯示還原金鑰嗎? +account.seed.backup.title=備份您的錢包還原密鑰 +account.seed.info=請寫下錢包還原密鑰和時間!\n您可以通過還原密鑰和時間在任何時候恢復您的錢包。\n還原密鑰用於 BTC 和 BSQ 錢包。\n\n您應該在一張紙上寫下還原密鑰並且不要保存它們在您的電腦上。\n請注意還原密鑰並不能代替備份。\n您需要備份完整的應用程序目錄在”賬户/備份“界面去恢復有效的應用程序狀態和數據。 +account.seed.backup.warning=請注意種子詞不能替代備份。您需要為整個應用目錄(在“賬户/備份”選項卡中)以恢復應用狀態以及數據。\n導入種子詞僅在緊急情況時才推薦使用。 如果沒有正確備份數據庫文件和密鑰,該應用程序將無法運行!\n\n在 Bisq wiki 中查看更多信息: https://bisq.wiki/Backing_up_application_data +account.seed.warn.noPw.msg=您還沒有設置一個可以保護還原密鑰顯示的錢包密碼。\n\n要顯示還原密鑰嗎? account.seed.warn.noPw.yes=是的,不要再問我 -account.seed.enterPw=輸入密碼檢視還原金鑰 -account.seed.restore.info=請在應用還原金鑰還原之前進行備份。請注意,錢包還原僅用於緊急情況,可能會導致內部錢包資料庫出現問題。\n這不是應用備份的方法!請使用應用程式資料目錄中的備份來恢復以前的應用程式狀態。\n恢復後,應用程式將自動關閉。重新啟動應用程式後,它將重新與比特幣網路同步。這可能需要一段時間,並且會消耗大量CPU,特別是在錢包較舊且有很多交易的情況下。請避免中斷該程序,否則可能需要再次刪除 SPV 鏈檔案或重複還原過程。 +account.seed.enterPw=輸入密碼查看還原密鑰 +account.seed.restore.info=請在應用還原密鑰還原之前進行備份。請注意,錢包還原僅用於緊急情況,可能會導致內部錢包數據庫出現問題。\n這不是應用備份的方法!請使用應用程序數據目錄中的備份來恢復以前的應用程序狀態。\n恢復後,應用程序將自動關閉。重新啟動應用程序後,它將重新與比特幣網絡同步。這可能需要一段時間,並且會消耗大量CPU,特別是在錢包較舊且有很多交易的情況下。請避免中斷該進程,否則可能需要再次刪除 SPV 鏈文件或重複還原過程。 account.seed.restore.ok=好的,立即執行回覆並且關閉 Bisq @@ -1249,55 +1276,55 @@ account.seed.restore.ok=好的,立即執行回覆並且關閉 Bisq account.notifications.setup.title=安裝 account.notifications.download.label=下載手機應用 -account.notifications.waitingForWebCam=等待網路攝像頭... +account.notifications.waitingForWebCam=等待網絡攝像頭... account.notifications.webCamWindow.headline=用手機掃描二維碼 -account.notifications.webcam.label=使用網路攝像頭 +account.notifications.webcam.label=使用網絡攝像頭 account.notifications.webcam.button=掃描二維碼 -account.notifications.noWebcam.button=我沒有網路攝像頭 +account.notifications.noWebcam.button=我沒有網絡攝像頭 account.notifications.erase.label=在手機上清除通知 account.notifications.erase.title=清除通知 account.notifications.email.label=驗證碼 account.notifications.email.prompt=輸入您通過電子郵件收到的驗證碼 -account.notifications.settings.title=設定 +account.notifications.settings.title=設置 account.notifications.useSound.label=在手機上播放提示聲音 -account.notifications.trade.label=接收交易資訊 +account.notifications.trade.label=接收交易信息 account.notifications.market.label=接收報價提醒 account.notifications.price.label=接收價格提醒 account.notifications.priceAlert.title=價格提醒 account.notifications.priceAlert.high.label=提醒條件:當 BTC 價格高於 account.notifications.priceAlert.low.label=提醒條件:當 BTC 價格低於 -account.notifications.priceAlert.setButton=設定價格提醒 +account.notifications.priceAlert.setButton=設置價格提醒 account.notifications.priceAlert.removeButton=取消價格提醒 account.notifications.trade.message.title=交易狀態已變更 -account.notifications.trade.message.msg.conf=ID 為 {0} 的交易的存款交易已被確認。請開啟您的 Bisq 應用程式並開始付款。 +account.notifications.trade.message.msg.conf=ID 為 {0} 的交易的存款交易已被確認。請打開您的 Bisq 應用程序並開始付款。 account.notifications.trade.message.msg.started=BTC 買家已經開始支付 ID 為 {0} 的交易。 account.notifications.trade.message.msg.completed=ID 為 {0} 的交易已完成。 account.notifications.offer.message.title=您的報價已被接受 account.notifications.offer.message.msg=您的 ID 為 {0} 的報價已被接受 -account.notifications.dispute.message.title=新的糾紛訊息 -account.notifications.dispute.message.msg=您收到了一個 ID 為 {0} 的交易糾紛訊息 +account.notifications.dispute.message.title=新的糾紛消息 +account.notifications.dispute.message.msg=您收到了一個 ID 為 {0} 的交易糾紛消息 account.notifications.marketAlert.title=報價提醒 -account.notifications.marketAlert.selectPaymentAccount=提供匹配的付款帳戶 -account.notifications.marketAlert.offerType.label=我感興趣的報價型別 +account.notifications.marketAlert.selectPaymentAccount=提供匹配的付款帳户 +account.notifications.marketAlert.offerType.label=我感興趣的報價類型 account.notifications.marketAlert.offerType.buy=買入報價(我想要出售 BTC ) account.notifications.marketAlert.offerType.sell=賣出報價(我想要購買 BTC ) account.notifications.marketAlert.trigger=報價距離(%) -account.notifications.marketAlert.trigger.info=設定價格區間後,只有當滿足(或超過)您的需求的報價釋出時,您才會收到提醒。您想賣 BTC ,但你只能以當前市價的 2% 溢價出售。將此欄位設定為 2% 將確保您只收到高於當前市場價格 2%(或更多)的報價的提醒。 +account.notifications.marketAlert.trigger.info=設置價格區間後,只有當滿足(或超過)您的需求的報價發佈時,您才會收到提醒。您想賣 BTC ,但你只能以當前市價的 2% 溢價出售。將此字段設置為 2% 將確保您只收到高於當前市場價格 2%(或更多)的報價的提醒。 account.notifications.marketAlert.trigger.prompt=與市場價格的百分比距離(例如 2.50%, -0.50% 等) -account.notifications.marketAlert.addButton=新增報價提醒 +account.notifications.marketAlert.addButton=添加報價提醒 account.notifications.marketAlert.manageAlertsButton=管理報價提醒 account.notifications.marketAlert.manageAlerts.title=管理報價提醒 -account.notifications.marketAlert.manageAlerts.header.paymentAccount=支付賬戶 +account.notifications.marketAlert.manageAlerts.header.paymentAccount=支付賬户 account.notifications.marketAlert.manageAlerts.header.trigger=觸發價格 -account.notifications.marketAlert.manageAlerts.header.offerType=報價型別 +account.notifications.marketAlert.manageAlerts.header.offerType=報價類型 account.notifications.marketAlert.message.title=報價提醒 account.notifications.marketAlert.message.msg.below=低於 account.notifications.marketAlert.message.msg.above=高於 -account.notifications.marketAlert.message.msg=價格為 {2}({3} {4}市場價)和支付方式為 {5} 的報價 {0} {1} 已釋出到 Bisq 報價列表。\n報價ID: {6}。 +account.notifications.marketAlert.message.msg=價格為 {2}({3} {4}市場價)和支付方式為 {5} 的報價 {0} {1} 已發佈到 Bisq 報價列表。\n報價ID: {6}。 account.notifications.priceAlert.message.title=價格提醒 {0} account.notifications.priceAlert.message.msg=您的價格提醒已被觸發。當前 {0} 的價格為 {1} {2} -account.notifications.noWebCamFound.warning=未找到網路攝像頭。\n\n請使用電子郵件選項將程式碼和加密金鑰從您的手機傳送到 Bisq 應用程式。 +account.notifications.noWebCamFound.warning=未找到網絡攝像頭。\n\n請使用電子郵件選項將代碼和加密密鑰從您的手機發送到 Bisq 應用程序。 account.notifications.priceAlert.warning.highPriceTooLow=較高的價格必須大於較低的價格。 account.notifications.priceAlert.warning.lowerPriceTooHigh=較低的價格必須低於較高的價格。 @@ -1308,12 +1335,12 @@ account.notifications.priceAlert.warning.lowerPriceTooHigh=較低的價格必須 # DAO #################################################################### -dao.tab.factsAndFigures=確切訊息 +dao.tab.factsAndFigures=確切消息 dao.tab.bsqWallet=BSQ 錢包 dao.tab.proposals=管理 dao.tab.bonding=關係 dao.tab.proofOfBurn=資產清單掛牌費/燒燬證明 -dao.tab.monitor=網路監視器 +dao.tab.monitor=網絡監視器 dao.tab.news=新聞 dao.paidWithBsq=已用 BSQ 支付 @@ -1326,8 +1353,8 @@ dao.lockedInBonds=凍結餘額 dao.availableNonBsqBalance=可用的非 BSQ 餘額(BTC) dao.reputationBalance=聲望值(不會花費) -dao.tx.published.success=你的交易已經成功釋出 -dao.proposal.menuItem.make=建立要求 +dao.tx.published.success=你的交易已經成功發佈 +dao.proposal.menuItem.make=創建要求 dao.proposal.menuItem.browse=瀏覽開啟的報償申請 dao.proposal.menuItem.vote=為報償申請投票 dao.proposal.menuItem.result=投票結果 @@ -1343,8 +1370,8 @@ dao.cycle.voteResult=投票結果 dao.cycle.phaseDuration=區塊 {0} (≈{1});區塊 {2} - {3})(≈{4} - ≈{5}) dao.cycle.phaseDurationWithoutBlocks=區塊 {0} - {1} (≈{2} - ≈{3} ) -dao.voteReveal.txPublished.headLine=投票公示交易釋出 -dao.voteReveal.txPublished=你的交易 ID 為 {0} 投票公示交易已經成功釋出。\n\n如果您已經參與了 DAO 投票,那麼這將由軟體自動完成。 +dao.voteReveal.txPublished.headLine=投票公示交易發佈 +dao.voteReveal.txPublished=你的交易 ID 為 {0} 投票公示交易已經成功發佈。\n\n如果您已經參與了 DAO 投票,那麼這將由軟件自動完成。 dao.results.cycles.header=週期 dao.results.cycles.table.header.cycle=週期 @@ -1355,7 +1382,7 @@ dao.results.cycles.table.header.issuance=發行 dao.results.results.table.item.cycle=週期 {0} 開始於:{1} dao.results.proposals.header=選定週期的請求 -dao.results.proposals.table.header.nameLink=名稱/連結 +dao.results.proposals.table.header.nameLink=名稱/鏈接 dao.results.proposals.table.header.details=詳情 dao.results.proposals.table.header.myVote=我的投票 dao.results.proposals.table.header.result=投票結果 @@ -1409,13 +1436,13 @@ dao.param.QUORUM_COMP_REQUEST=BSQ 要求的報償申請的仲裁人數 # suppress inspection "UnusedProperty" dao.param.QUORUM_REIMBURSEMENT=BSQ 要求的退還申請的仲裁人數 # suppress inspection "UnusedProperty" -dao.param.QUORUM_CHANGE_PARAM=BSQ 要求的改變引數的仲裁人數 +dao.param.QUORUM_CHANGE_PARAM=BSQ 要求的改變參數的仲裁人數 # suppress inspection "UnusedProperty" dao.param.QUORUM_REMOVE_ASSET=BSQ 要求的移除資產要求的人數 # suppress inspection "UnusedProperty" dao.param.QUORUM_CONFISCATION=BSQ 要求的沒收申請的仲裁人數 # suppress inspection "UnusedProperty" -dao.param.QUORUM_ROLE=BSQ 要求的繫結角色的仲裁人數 +dao.param.QUORUM_ROLE=BSQ 要求的綁定角色的仲裁人數 # suppress inspection "UnusedProperty" dao.param.THRESHOLD_GENERIC=普通提案的要求百分比 @@ -1424,7 +1451,7 @@ dao.param.THRESHOLD_COMP_REQUEST=報償申請的要求百分比 # suppress inspection "UnusedProperty" dao.param.THRESHOLD_REIMBURSEMENT=退還申請的要求百分比 # suppress inspection "UnusedProperty" -dao.param.THRESHOLD_CHANGE_PARAM=改變引數的要求百分比 +dao.param.THRESHOLD_CHANGE_PARAM=改變參數的要求百分比 # suppress inspection "UnusedProperty" dao.param.THRESHOLD_REMOVE_ASSET=移除資產的要求百分比 # suppress inspection "UnusedProperty" @@ -1457,7 +1484,7 @@ dao.param.currentValue=當前值:{0} dao.param.currentAndPastValue=當前餘額:{0}(提案時的餘額:{1}) dao.param.blocks={0} 區塊 -dao.results.invalidVotes=在那個投票週期中,我們有無效的投票。如果投票沒有在 Bisq 網路中很好地分佈,就會發生這種情況。\n{0} +dao.results.invalidVotes=在那個投票週期中,我們有無效的投票。如果投票沒有在 Bisq 網絡中很好地分佈,就會發生這種情況。\n{0} # suppress inspection "UnusedProperty" dao.phase.PHASE_UNDEFINED=未定義 @@ -1495,12 +1522,12 @@ dao.bond.reputation.table.header=我的名譽擔保 dao.bond.reputation.amount=鎖定的 BSQ 數量 dao.bond.reputation.time=在區塊中的解鎖時間 dao.bond.reputation.salt=鹽 -dao.bond.reputation.hash=雜湊 +dao.bond.reputation.hash=哈希 dao.bond.reputation.lockupButton=鎖定 dao.bond.reputation.lockup.headline=確認鎖定交易 -dao.bond.reputation.lockup.details=Lockup amount: {0}\nUnlock time: {1} block(s) (≈{2})\n\nMining fee: {3} ({4} Satoshis/vbyte)\nTransaction vsize: {5} Kb\n\nAre you sure you want to proceed? +dao.bond.reputation.lockup.details=鎖定數量:{0}\n解鎖時間:{1} 區塊(≈{2})\n\n礦工手續費:{3}({4} 聰/字節)\n交易大小:{5} 字節\n\n你確定想要繼續? dao.bond.reputation.unlock.headline=確認解鎖交易 -dao.bond.reputation.unlock.details=Unlock amount: {0}\nUnlock time: {1} block(s) (≈{2})\n\nMining fee: {3} ({4} Satoshis/vbyte)\nTransaction vsize: {5} Kb\n\nAre you sure you want to proceed? +dao.bond.reputation.unlock.details=解鎖金額:{0}\n解鎖時間:{1} 區塊(≈{2})\n\n挖礦手續費:{3}({4} 聰/Byte)\n交易大小:{5} Kb\n\n你想繼續這個操作嗎? dao.bond.allBonds.header=所有擔保 @@ -1511,16 +1538,16 @@ dao.bond.details.header=交易方詳情 dao.bond.details.role=角色 dao.bond.details.requiredBond=需要的 BSQ 擔保 dao.bond.details.unlockTime=在區塊中的解鎖時間 -dao.bond.details.link=連結到交易方描述 +dao.bond.details.link=鏈接到交易方描述 dao.bond.details.isSingleton=是否可由多個交易方擔任 dao.bond.details.blocks={0} 區塊 dao.bond.table.column.name=名稱 -dao.bond.table.column.link=繫結 -dao.bond.table.column.bondType=連線型別 +dao.bond.table.column.link=綁定 +dao.bond.table.column.bondType=連接類型 dao.bond.table.column.details=詳情 dao.bond.table.column.lockupTxId=鎖定 Tx ID -dao.bond.table.column.bondState=連線狀態 +dao.bond.table.column.bondState=連接狀態 dao.bond.table.column.lockTime=解鎖時間 dao.bond.table.column.lockupDate=鎖定日期 @@ -1635,14 +1662,14 @@ dao.proofOfBurn.burn=燒燬 dao.proofOfBurn.allTxs=所有燒燬證明交易 dao.proofOfBurn.myItems=我的燒燬證明交易 dao.proofOfBurn.date=日期 -dao.proofOfBurn.hash=雜湊 +dao.proofOfBurn.hash=哈希 dao.proofOfBurn.txs=交易記錄 dao.proofOfBurn.pubKey=公鑰 -dao.proofOfBurn.signature.window.title=使用燒燬證明交易中的金鑰驗證訊息 -dao.proofOfBurn.verify.window.title=使用燒燬證明交易中的金鑰確認訊息 -dao.proofOfBurn.copySig=將驗證複製到剪貼簿 +dao.proofOfBurn.signature.window.title=使用燒燬證明交易中的密鑰驗證消息 +dao.proofOfBurn.verify.window.title=使用燒燬證明交易中的密鑰確認消息 +dao.proofOfBurn.copySig=將驗證複製到剪貼板 dao.proofOfBurn.sign=驗證 -dao.proofOfBurn.message=訊息 +dao.proofOfBurn.message=消息 dao.proofOfBurn.sig=驗證 dao.proofOfBurn.verify=確認 dao.proofOfBurn.verificationResult.ok=確認成功 @@ -1685,7 +1712,7 @@ dao.proposal.type.BONDED_ROLE=擔保角色的提案 # suppress inspection "UnusedProperty" dao.proposal.type.REMOVE_ASSET=移除資產提案 # suppress inspection "UnusedProperty" -dao.proposal.type.CHANGE_PARAM=修改引數的提議 +dao.proposal.type.CHANGE_PARAM=修改參數的提議 # suppress inspection "UnusedProperty" dao.proposal.type.GENERIC=一般提議 # suppress inspection "UnusedProperty" @@ -1702,7 +1729,7 @@ dao.proposal.type.short.BONDED_ROLE=擔保角色 # suppress inspection "UnusedProperty" dao.proposal.type.short.REMOVE_ASSET=移除一個數字貨幣 # suppress inspection "UnusedProperty" -dao.proposal.type.short.CHANGE_PARAM=修改引數 +dao.proposal.type.short.CHANGE_PARAM=修改參數 # suppress inspection "UnusedProperty" dao.proposal.type.short.GENERIC=一般提議 # suppress inspection "UnusedProperty" @@ -1722,32 +1749,32 @@ dao.proposal.myVote.merit=所得的 BSQ 的投票權重 dao.proposal.myVote.stake=Stake 的投票權重 dao.proposal.myVote.revealTxId=投票公示的交易 ID dao.proposal.myVote.stake.prompt=在投票中最大可用份額:{0} -dao.proposal.votes.header=設定投票的份額,併發布您的投票 -dao.proposal.myVote.button=釋出投票 -dao.proposal.myVote.setStake.description=在對所有提案進行投票後,您必須鎖定BSQ來設定投票的份額。您鎖定的 BSQ 越多,你的投票權重就越大。\n\n投票會鎖定 BSQ 將在投票顯示階段再次解鎖。 -dao.proposal.create.selectProposalType=選擇提案型別 +dao.proposal.votes.header=設置投票的份額,併發布您的投票 +dao.proposal.myVote.button=發佈投票 +dao.proposal.myVote.setStake.description=在對所有提案進行投票後,您必須鎖定BSQ來設置投票的份額。您鎖定的 BSQ 越多,你的投票權重就越大。\n\n投票會鎖定 BSQ 將在投票顯示階段再次解鎖。 +dao.proposal.create.selectProposalType=選擇提案類型 dao.proposal.create.phase.inactive=請等到下一個提案階段 -dao.proposal.create.proposalType=提議型別 -dao.proposal.create.new=建立新的賠償要求 -dao.proposal.create.button=建立賠償要求 -dao.proposal.create.publish=釋出提案 -dao.proposal.create.publishing=正在釋出提案中... +dao.proposal.create.proposalType=提議類型 +dao.proposal.create.new=創建新的賠償要求 +dao.proposal.create.button=創建賠償要求 +dao.proposal.create.publish=發佈提案 +dao.proposal.create.publishing=正在發佈提案中... dao.proposal=提案 -dao.proposal.display.type=提議型別 -dao.proposal.display.name=確切的 GitHub 的使用者名稱 -dao.proposal.display.link=詳情的連結 -dao.proposal.display.link.prompt=提案的連結 +dao.proposal.display.type=提議類型 +dao.proposal.display.name=確切的 GitHub 的用户名 +dao.proposal.display.link=詳情的鏈接 +dao.proposal.display.link.prompt=提案的鏈接 dao.proposal.display.requestedBsq=申請的 BSQ 數量 dao.proposal.display.txId=提案交易 ID dao.proposal.display.proposalFee=提案手續費 dao.proposal.display.myVote=我的投票 dao.proposal.display.voteResult=投票結果總結 -dao.proposal.display.bondedRoleComboBox.label=擔保角色型別 +dao.proposal.display.bondedRoleComboBox.label=擔保角色類型 dao.proposal.display.requiredBondForRole.label=角色需要的擔保 dao.proposal.display.option=選項 -dao.proposal.table.header.proposalType=提議型別 -dao.proposal.table.header.link=繫結 +dao.proposal.table.header.proposalType=提議類型 +dao.proposal.table.header.link=綁定 dao.proposal.table.header.myVote=我的投票 # suppress inspection "UnusedProperty" dao.proposal.table.header.remove=移除 @@ -1765,41 +1792,41 @@ dao.proposal.voteResult.success=已接受 dao.proposal.voteResult.failed=已拒絕 dao.proposal.voteResult.summary=結果:{0};閾值:{1}(要求> {2});仲裁人數:{3}(要求> {4}) -dao.proposal.display.paramComboBox.label=選擇需要改變的引數 -dao.proposal.display.paramValue=引數值 +dao.proposal.display.paramComboBox.label=選擇需要改變的參數 +dao.proposal.display.paramValue=參數值 dao.proposal.display.confiscateBondComboBox.label=選擇擔保 dao.proposal.display.assetComboBox.label=需要移除的資產 dao.blindVote=匿名投票 -dao.blindVote.startPublishing=釋出匿名投票交易中 -dao.blindVote.success=我們的匿名投票交易已經成功釋出。\n\n請注意,您必須線上在投票公示階段,以便您的 Bisq 應用程式可以釋出投票公示交易。沒有投票公示交易,您的投票將無效! +dao.blindVote.startPublishing=發佈匿名投票交易中 +dao.blindVote.success=我們的匿名投票交易已經成功發佈。\n\n請注意,您必須在線在投票公示階段,以便您的 Bisq 應用程序可以發佈投票公示交易。沒有投票公示交易,您的投票將無效! -dao.wallet.menuItem.send=傳送 +dao.wallet.menuItem.send=發送 dao.wallet.menuItem.receive=接收 dao.wallet.menuItem.transactions=交易記錄 dao.wallet.dashboard.myBalance=我的錢包餘額 dao.wallet.receive.fundYourWallet=你的 BSQ 接收地址 -dao.wallet.receive.bsqAddress=BSQ 錢包地址(重新整理未使用地址) +dao.wallet.receive.bsqAddress=BSQ 錢包地址(刷新未使用地址) dao.wallet.send.sendFunds=提現 -dao.wallet.send.sendBtcFunds=傳送非 BSQ 資金(BTC) +dao.wallet.send.sendBtcFunds=發送非 BSQ 資金(BTC) dao.wallet.send.amount=BSQ 數量 dao.wallet.send.btcAmount=BTC 數量(無 BSQ 資金) -dao.wallet.send.setAmount=設定提現數量(最小量 {0}) +dao.wallet.send.setAmount=設置提現數量(最小量 {0}) dao.wallet.send.receiverAddress=接收者的 BSQ 地址 dao.wallet.send.receiverBtcAddress=接收者的 BTC 地址 dao.wallet.send.setDestinationAddress=輸入您的目標地址 -dao.wallet.send.send=傳送 BSQ 資金 -dao.wallet.send.sendBtc=傳送 BTC 資金 +dao.wallet.send.send=發送 BSQ 資金 +dao.wallet.send.sendBtc=發送 BTC 資金 dao.wallet.send.sendFunds.headline=確定提現申請 -dao.wallet.send.sendFunds.details=Sending: {0}\nTo receiving address: {1}.\nRequired transaction fee is: {2} ({3} satoshis/vbyte)\nTransaction vsize: {4} vKb\n\nThe recipient will receive: {5}\n\nAre you sure you want to withdraw that amount? +dao.wallet.send.sendFunds.details=發送:{0}\n來自:{1}\n要求的礦工手續費:{2}({3}比特/節)\n交易大小:{4}字節\n\n接收方會收到:{5}\n\n您確定您想要提現這些數量嗎? dao.wallet.chainHeightSynced=最新確認區塊:{0} dao.wallet.chainHeightSyncing=等待區塊... 已確認{0}/{1}區塊 -dao.wallet.tx.type=型別 +dao.wallet.tx.type=類型 # suppress inspection "UnusedProperty" dao.tx.type.enum.UNDEFINED=未定義 @@ -1816,7 +1843,7 @@ dao.tx.type.enum.TRANSFER_BSQ=劃轉 BSQ # suppress inspection "UnusedProperty" dao.tx.type.enum.received.TRANSFER_BSQ=接收 BSQ # suppress inspection "UnusedProperty" -dao.tx.type.enum.sent.TRANSFER_BSQ=傳送 BSQ +dao.tx.type.enum.sent.TRANSFER_BSQ=發送 BSQ # suppress inspection "UnusedProperty" dao.tx.type.enum.PAY_TRADE_FEE=付交易費記錄 # suppress inspection "UnusedProperty" @@ -1845,39 +1872,39 @@ dao.tx.issuanceFromCompReq=報償申請/發放 dao.tx.issuanceFromCompReq.tooltip=導致新 BSQ 發行的報償請求。\n發行日期:{0} dao.tx.issuanceFromReimbursement=退還申請/發放 dao.tx.issuanceFromReimbursement.tooltip=導致新 BSQ 發放的退還申請。\n發放日期: {0} -dao.proposal.create.missingBsqFunds=您沒有足夠的 BSQ 資金來建立提案。如果您有一個未經確認的 BSQ 交易,您需要等待一個區塊鏈確認,因為 BSQ 只有在包含在一個區塊中時才會被驗證。\n缺失:{0} +dao.proposal.create.missingBsqFunds=您沒有足夠的 BSQ 資金來創建提案。如果您有一個未經確認的 BSQ 交易,您需要等待一個區塊鏈確認,因為 BSQ 只有在包含在一個區塊中時才會被驗證。\n缺失:{0} -dao.proposal.create.missingBsqFundsForBond=你沒有足夠的 BSQ 資金來承擔這個角色。您仍然可以釋出這個提案,但如果它被接受,您將需要這個角色所需的全部 BSQ 金額。\n缺少:{0} +dao.proposal.create.missingBsqFundsForBond=你沒有足夠的 BSQ 資金來承擔這個角色。您仍然可以發佈這個提案,但如果它被接受,您將需要這個角色所需的全部 BSQ 金額。\n缺少:{0} dao.proposal.create.missingMinerFeeFunds=您沒有足夠的BTC資金來支付該提案交易。所有的 BSQ交易需要用 BTC 支付挖礦手續費。\n缺少:{0} dao.proposal.create.missingIssuanceFunds=您沒有足夠的BTC資金來支付該提案交易。所有的 BSQ交易需要用 BTC 支付挖礦手續費以及發起交易也需要用 BTC 支付所需的 BSQ 數量({0} 聰/BSQ)\n缺少:{1} dao.feeTx.confirm=確認 {0} 交易 -dao.feeTx.confirm.details={0} fee: {1}\nMining fee: {2} ({3} Satoshis/vbyte)\nTransaction vsize: {4} vKb\n\nAre you sure you want to publish the {5} transaction? +dao.feeTx.confirm.details={0}手續費:{1}\n礦工手續費:{2}({3} 聰/byte)\n交易大小:{4} Kb\n\n您確定您要發送這個 {5} 交易嗎? -dao.feeTx.issuanceProposal.confirm.details={0} fee: {1}\nBTC needed for BSQ issuance: {2} ({3} Satoshis/BSQ)\nMining fee: {4} ({5} Satoshis/vbyte)\nTransaction vsize: {6} vKb\n\nIf your request is approved, you will receive the amount you requested net of the 2 BSQ proposal fee.\n\nAre you sure you want to publish the {7} transaction? +dao.feeTx.issuanceProposal.confirm.details={0}手續費:{1}\n為 BSQ 提案所需要的BTC:{2}({3}聰 / BSQ)\n挖礦手續費:{4}({5}聰 /字節)\n交易大小:{6}Kb\n\n如果你的要求被批准,你將收到你要求數量的 2 個 BSQ 提議的費用。\n\n你確定你想要發佈{7}交易? dao.news.bisqDAO.title=Bisq DAO dao.news.bisqDAO.description=正如 Bisq交易是分散的,並且不受審查,它的治理模型也是如此—— Bisq DAO 和 BSQ 是使其成為可能的工具。 -dao.news.bisqDAO.readMoreLink=瞭解有關 Bisq DAO 的更多資訊 +dao.news.bisqDAO.readMoreLink=瞭解有關 Bisq DAO 的更多信息 dao.news.pastContribution.title=過去有所貢獻?申請 BSQ dao.news.pastContribution.description=如果您對 Bisq 有貢獻,請使用下面的 BSQ 地址,並申請參與 BSQ 初始分發。 dao.news.pastContribution.yourAddress=你的 BSQ 錢包地址 dao.news.pastContribution.requestNow=現在申請 -dao.news.DAOOnTestnet.title=在我們的測試網路上執行 BISQ DAO -dao.news.DAOOnTestnet.description=核心網路 Bisq DAO 還沒有啟動,但是您可以通過在我們的測試網路上執行它來了解 Bisq DAO 。 -dao.news.DAOOnTestnet.firstSection.title=1.切換至 DAO 測試網路模式 -dao.news.DAOOnTestnet.firstSection.content=從設定頁面切換到 DAO 測試網路。 +dao.news.DAOOnTestnet.title=在我們的測試網絡上運行 BISQ DAO +dao.news.DAOOnTestnet.description=核心網絡 Bisq DAO 還沒有啟動,但是您可以通過在我們的測試網絡上運行它來了解 Bisq DAO 。 +dao.news.DAOOnTestnet.firstSection.title=1.切換至 DAO 測試網絡模式 +dao.news.DAOOnTestnet.firstSection.content=從設置頁面切換到 DAO 測試網絡。 dao.news.DAOOnTestnet.secondSection.title=2.獲得一些 BSQ dao.news.DAOOnTestnet.secondSection.content=在 Slack 上申請 BSQ 或在 Bisq 上購買 BSQ 。 dao.news.DAOOnTestnet.thirdSection.title=3.參與投票週期 dao.news.DAOOnTestnet.thirdSection.content=就修改 Bisq 的各個方面提出建議並進行表決。 dao.news.DAOOnTestnet.fourthSection.title=4.探索 BSQ 區塊鏈瀏覽器 dao.news.DAOOnTestnet.fourthSection.content=由於 BSQ 只是比特幣,你可以看到 BSQ 交易在我們的比特幣區塊瀏覽器。 -dao.news.DAOOnTestnet.readMoreLink=閱讀完整的文件 +dao.news.DAOOnTestnet.readMoreLink=閲讀完整的文檔 dao.monitor.daoState=DAO 狀態 dao.monitor.proposals=提案狀態 @@ -1886,41 +1913,41 @@ dao.monitor.blindVotes=匿名投票狀態 dao.monitor.table.peers=節點 dao.monitor.table.conflicts=矛盾 dao.monitor.state=狀態 -dao.monitor.requestAlHashes=要求所有雜湊 +dao.monitor.requestAlHashes=要求所有哈希 dao.monitor.resync=重新同步 DAO 狀態 dao.monitor.table.header.cycleBlockHeight=週期/區塊高度 dao.monitor.table.cycleBlockHeight=週期 {0} /區塊 {1} dao.monitor.table.seedPeers=種子節點:{0} dao.monitor.daoState.headline=DAO 狀態 -dao.monitor.daoState.table.headline=DAO 狀態的雜湊鏈 +dao.monitor.daoState.table.headline=DAO 狀態的哈希鏈 dao.monitor.daoState.table.blockHeight=區塊高度 -dao.monitor.daoState.table.hash=DAO 狀態的雜湊 -dao.monitor.daoState.table.prev=以前的雜湊 -dao.monitor.daoState.conflictTable.headline=來自不同實體的 DAO 狀態雜湊 +dao.monitor.daoState.table.hash=DAO 狀態的哈希 +dao.monitor.daoState.table.prev=以前的哈希 +dao.monitor.daoState.conflictTable.headline=來自不同實體的 DAO 狀態哈希 dao.monitor.daoState.utxoConflicts=UTXO 衝突 dao.monitor.daoState.utxoConflicts.blockHeight=區塊高度:{0} dao.monitor.daoState.utxoConflicts.sumUtxo=所有 UTXO 的總和:{0} BSQ dao.monitor.daoState.utxoConflicts.sumBsq=所有 BSQ 的總和:{0} BSQ -dao.monitor.daoState.checkpoint.popup=DAO 狀態與網路不同步。重啟之後,DAO 狀態將重新同步。 +dao.monitor.daoState.checkpoint.popup=DAO 狀態與網絡不同步。重啟之後,DAO 狀態將重新同步。 dao.monitor.proposal.headline=提案狀態 -dao.monitor.proposal.table.headline=提案狀態的雜湊鏈 -dao.monitor.proposal.conflictTable.headline=來自不同實體的提案狀態雜湊 +dao.monitor.proposal.table.headline=提案狀態的哈希鏈 +dao.monitor.proposal.conflictTable.headline=來自不同實體的提案狀態哈希 -dao.monitor.proposal.table.hash=提案狀態的雜湊 -dao.monitor.proposal.table.prev=以前的雜湊 +dao.monitor.proposal.table.hash=提案狀態的哈希 +dao.monitor.proposal.table.prev=以前的哈希 dao.monitor.proposal.table.numProposals=提案編號 -dao.monitor.isInConflictWithSeedNode=您的本地資料與至少一個種子節點不一致。請重新同步 DAO 狀態。 -dao.monitor.isInConflictWithNonSeedNode=您的一個對等節點與網路不一致,但您的節點與種子節點同步。 -dao.monitor.daoStateInSync=您的本地節點與網路一致 +dao.monitor.isInConflictWithSeedNode=您的本地數據與至少一個種子節點不一致。請重新同步 DAO 狀態。 +dao.monitor.isInConflictWithNonSeedNode=您的一個對等節點與網絡不一致,但您的節點與種子節點同步。 +dao.monitor.daoStateInSync=您的本地節點與網絡一致 dao.monitor.blindVote.headline=匿名投票狀態 -dao.monitor.blindVote.table.headline=匿名投票狀態的雜湊鏈 -dao.monitor.blindVote.conflictTable.headline=來自不同實體的匿名投票狀態雜湊 -dao.monitor.blindVote.table.hash=匿名投票狀態的雜湊 -dao.monitor.blindVote.table.prev=以前的雜湊 +dao.monitor.blindVote.table.headline=匿名投票狀態的哈希鏈 +dao.monitor.blindVote.conflictTable.headline=來自不同實體的匿名投票狀態哈希 +dao.monitor.blindVote.table.hash=匿名投票狀態的哈希 +dao.monitor.blindVote.table.prev=以前的哈希 dao.monitor.blindVote.table.numBlindVotes=匿名投票編號 dao.factsAndFigures.menuItem.supply=BSQ 供給 @@ -1930,7 +1957,7 @@ dao.factsAndFigures.dashboard.avgPrice90=90天平均 BSQ/BTC 交易價格 dao.factsAndFigures.dashboard.avgPrice30=30天平均 BSQ/BTC 交易價格 dao.factsAndFigures.dashboard.avgUSDPrice90=90 天成交量加權平均 USD/BSQ 交易價格 dao.factsAndFigures.dashboard.avgUSDPrice30=30 天成交量加權平均 USD/BSQ 交易價格 -dao.factsAndFigures.dashboard.marketCap=市值(基於市場價) +dao.factsAndFigures.dashboard.marketCap=市值(基於 30天平均 USD/BSQ 價格) dao.factsAndFigures.dashboard.availableAmount=總共可用的 BSQ dao.factsAndFigures.supply.issuedVsBurnt=已發放的 BSQ 已銷燬的 BSQ @@ -1944,7 +1971,7 @@ dao.factsAndFigures.supply.burnt=BSQ 燒燬總量 dao.factsAndFigures.supply.burntMovingAverage=15天動態平均線 dao.factsAndFigures.supply.burntZoomToInliers=放大至 inliers -dao.factsAndFigures.supply.locked=BSQ 全域性鎖定狀態 +dao.factsAndFigures.supply.locked=BSQ 全局鎖定狀態 dao.factsAndFigures.supply.totalLockedUpAmount=擔保的鎖定 dao.factsAndFigures.supply.totalUnlockingAmount=正在從擔保解鎖 BSQ dao.factsAndFigures.supply.totalUnlockedAmount=已從擔保解鎖 BSQ @@ -1971,40 +1998,40 @@ dao.factsAndFigures.transactions.irregularTx=所有不正常的交易記錄: contractWindow.title=糾紛詳情 contractWindow.dates=報價時間/交易時間 contractWindow.btcAddresses=BTC 買家/BTC 賣家的比特幣地址 -contractWindow.onions=BTC 買家/BTC 賣家的網路地址 +contractWindow.onions=BTC 買家/BTC 賣家的網絡地址 contractWindow.accountAge=BTC 買家/BTC 賣家的賬齡 contractWindow.numDisputes=BTC 買家/BTC 賣家的糾紛編號 -contractWindow.contractHash=合同雜湊 +contractWindow.contractHash=合同哈希 displayAlertMessageWindow.headline=重要資料! displayAlertMessageWindow.update.headline=重要更新資料! displayAlertMessageWindow.update.download=下載: -displayUpdateDownloadWindow.downloadedFiles=下載完成的檔案: +displayUpdateDownloadWindow.downloadedFiles=下載完成的文件: displayUpdateDownloadWindow.downloadingFile=正在下載:{0} displayUpdateDownloadWindow.verifiedSigs=驗證驗證: -displayUpdateDownloadWindow.status.downloading=下載檔案... +displayUpdateDownloadWindow.status.downloading=下載文件... displayUpdateDownloadWindow.status.verifying=驗證驗證中... -displayUpdateDownloadWindow.button.label=下載安裝程式並驗證驗證 +displayUpdateDownloadWindow.button.label=下載安裝程序並驗證驗證 displayUpdateDownloadWindow.button.downloadLater=稍後下載 displayUpdateDownloadWindow.button.ignoreDownload=忽略這個版本 displayUpdateDownloadWindow.headline=Bisq 有新的更新! displayUpdateDownloadWindow.download.failed.headline=下載失敗 displayUpdateDownloadWindow.download.failed=下載失敗。\n請到 https://bisq.io/downloads 下載並驗證。 -displayUpdateDownloadWindow.installer.failed=無法確定正確的安裝程式。請通過 https://bisq.network/downloads 手動下載和驗證。 +displayUpdateDownloadWindow.installer.failed=無法確定正確的安裝程序。請通過 https://bisq.network/downloads 手動下載和驗證。 displayUpdateDownloadWindow.verify.failed=驗證失敗。\n請到 https://bisq.io/downloads 手動下載和驗證。 -displayUpdateDownloadWindow.success=新版本成功下載並驗證驗證 。\n\n請開啟下載目錄,關閉應用程式並安裝最新版本。 -displayUpdateDownloadWindow.download.openDir=開啟下載目錄 +displayUpdateDownloadWindow.success=新版本成功下載並驗證驗證 。\n\n請打開下載目錄,關閉應用程序並安裝最新版本。 +displayUpdateDownloadWindow.download.openDir=打開下載目錄 disputeSummaryWindow.title=概要 -disputeSummaryWindow.openDate=工單建立時間 +disputeSummaryWindow.openDate=工單創建時間 disputeSummaryWindow.role=交易者的角色 disputeSummaryWindow.payout=交易金額支付 disputeSummaryWindow.payout.getsTradeAmount=BTC {0} 獲得交易金額支付 -disputeSummaryWindow.payout.getsAll=BTC {0} 獲取全部 +disputeSummaryWindow.payout.getsAll=最大 BTC 支付數 {0} disputeSummaryWindow.payout.custom=自定義支付 disputeSummaryWindow.payoutAmount.buyer=買家支付金額 disputeSummaryWindow.payoutAmount.seller=賣家支付金額 -disputeSummaryWindow.payoutAmount.invert=使用失敗者作為釋出者 +disputeSummaryWindow.payoutAmount.invert=使用失敗者作為發佈者 disputeSummaryWindow.reason=糾紛的原因 # dynamic values are not recognized by IntelliJ @@ -2027,14 +2054,14 @@ disputeSummaryWindow.reason.OPTION_TRADE=可選交易 # suppress inspection "UnusedProperty" disputeSummaryWindow.reason.SELLER_NOT_RESPONDING=賣家未迴應 # suppress inspection "UnusedProperty" -disputeSummaryWindow.reason.WRONG_SENDER_ACCOUNT=錯誤的傳送者賬號 +disputeSummaryWindow.reason.WRONG_SENDER_ACCOUNT=錯誤的發送者賬號 # suppress inspection "UnusedProperty" disputeSummaryWindow.reason.PEER_WAS_LATE=交易夥伴已超時 # suppress inspection "UnusedProperty" disputeSummaryWindow.reason.TRADE_ALREADY_SETTLED=交易已穩定 -disputeSummaryWindow.summaryNotes=總結說明 -disputeSummaryWindow.addSummaryNotes=新增總結說明 +disputeSummaryWindow.summaryNotes=總結説明 +disputeSummaryWindow.addSummaryNotes=添加總結説明 disputeSummaryWindow.close.button=關閉話題 # Do no change any line break or order of tokens as the structure is used for signature verification @@ -2044,60 +2071,60 @@ disputeSummaryWindow.close.msg=工單已關閉{0}\n{1} 節點地址:{12}\n\n # Do no change any line break or order of tokens as the structure is used for signature verification disputeSummaryWindow.close.msgWithSig={0}{1}{2}{3} -disputeSummaryWindow.close.nextStepsForMediation=\n\n下一個步驟:\n開啟未完成交易,接受或拒絕建議的調解員的建議 +disputeSummaryWindow.close.nextStepsForMediation=\n\n下一個步驟:\n打開未完成交易,接受或拒絕建議的調解員的建議 disputeSummaryWindow.close.nextStepsForRefundAgentArbitration=\n\n下一個步驟:\n不需要您採取進一步的行動。如果仲裁員做出了對你有利的裁決,你將在 資金/交易 頁中看到“仲裁退款”交易 -disputeSummaryWindow.close.closePeer=你也需要關閉交易物件的話題! -disputeSummaryWindow.close.txDetails.headline=釋出交易退款 +disputeSummaryWindow.close.closePeer=你也需要關閉交易對象的話題! +disputeSummaryWindow.close.txDetails.headline=發佈交易退款 # suppress inspection "TrailingSpacesInProperty" disputeSummaryWindow.close.txDetails.buyer=買方收到{0}在地址:{1} # suppress inspection "TrailingSpacesInProperty" disputeSummaryWindow.close.txDetails.seller=賣方收到{0}在地址:{1} -disputeSummaryWindow.close.txDetails=Spending: {0}\n{1}{2}Transaction fee: {3} ({4} satoshis/vbyte)\nTransaction vsize: {5} vKb\n\nAre you sure you want to publish this transaction? +disputeSummaryWindow.close.txDetails=費用:{0}\n{1}{2}交易費:{3}({4}satoshis/byte)\n事務大小:{5} Kb\n\n您確定要發佈此交易嗎? disputeSummaryWindow.close.noPayout.headline=未支付關閉 disputeSummaryWindow.close.noPayout.text=你想要在未作支付的情況下關閉嗎? emptyWalletWindow.headline={0} 錢包急救工具 -emptyWalletWindow.info=請在緊急情況下使用,如果您無法從 UI 中訪問您的資金。\n\n請注意,使用此工具時,所有未結報價將自動關閉。\n\n在使用此工具之前,請備份您的資料目錄。您可以在“帳戶/備份”中執行此操作。\n\n請報告我們您的問題,並在 Github 或 Bisq 論壇上提交錯誤報告,以便我們可以調查導致問題的原因。 +emptyWalletWindow.info=請在緊急情況下使用,如果您無法從 UI 中訪問您的資金。\n\n請注意,使用此工具時,所有未結報價將自動關閉。\n\n在使用此工具之前,請備份您的數據目錄。您可以在“帳户/備份”中執行此操作。\n\n請報吿我們您的問題,並在 Github 或 Bisq 論壇上提交錯誤報吿,以便我們可以調查導致問題的原因。 emptyWalletWindow.balance=您的可用錢包餘額 emptyWalletWindow.bsq.btcBalance=非 BSQ 聰餘額 emptyWalletWindow.address=輸入您的目標地址 -emptyWalletWindow.button=傳送全部資金 -emptyWalletWindow.openOffers.warn=您有已釋出的報價,如果您清空錢包將被刪除。\n你確定要清空你的錢包嗎? +emptyWalletWindow.button=發送全部資金 +emptyWalletWindow.openOffers.warn=您有已發佈的報價,如果您清空錢包將被刪除。\n你確定要清空你的錢包嗎? emptyWalletWindow.openOffers.yes=是的,我確定 emptyWalletWindow.sent.success=您的錢包的餘額已成功轉移。 -enterPrivKeyWindow.headline=輸入金鑰進行註冊 +enterPrivKeyWindow.headline=輸入密鑰進行註冊 filterWindow.headline=編輯篩選列表 filterWindow.offers=篩選報價(用逗號“,”隔開) filterWindow.onions=篩選匿名地址(用逗號“,”隔開) -filterWindow.accounts=篩選交易賬戶資料:\n格式:逗號分割的 [付款方式ID|資料欄位|值] -filterWindow.bannedCurrencies=篩選貨幣程式碼(用逗號“,”隔開) +filterWindow.accounts=篩選交易賬户數據:\n格式:逗號分割的 [付款方式ID|數據字段|值] +filterWindow.bannedCurrencies=篩選貨幣代碼(用逗號“,”隔開) filterWindow.bannedPaymentMethods=篩選支付方式 ID(用逗號“,”隔開) -filterWindow.bannedAccountWitnessSignerPubKeys=已過濾的帳戶證人簽名者公鑰(逗號分隔十六進位制公鑰) -filterWindow.bannedPrivilegedDevPubKeys=已過濾的特權開發者公鑰(逗號分隔十六進位制公鑰) -filterWindow.arbitrators=篩選後的仲裁人(用逗號“,”隔開的洋蔥地址) -filterWindow.mediators=篩選後的調解員(用逗號“,”隔開的洋蔥地址) -filterWindow.refundAgents=篩選後的退款助理(用逗號“,”隔開的洋蔥地址) -filterWindow.seedNode=篩選後的種子節點(用逗號“,”隔開的洋蔥地址) -filterWindow.priceRelayNode=篩選後的價格中繼節點(用逗號“,”隔開的洋蔥地址) -filterWindow.btcNode=篩選後的比特幣節點(用逗號“,”隔開的地址+埠) -filterWindow.preventPublicBtcNetwork=禁止使用公共比特幣網路 +filterWindow.bannedAccountWitnessSignerPubKeys=已過濾的帳户證人簽名者公鑰(逗號分隔十六進制公鑰) +filterWindow.bannedPrivilegedDevPubKeys=已過濾的特權開發者公鑰(逗號分隔十六進制公鑰) +filterWindow.arbitrators=篩選後的仲裁人(用逗號“,”隔開的洋葱地址) +filterWindow.mediators=篩選後的調解員(用逗號“,”隔開的洋葱地址) +filterWindow.refundAgents=篩選後的退款助理(用逗號“,”隔開的洋葱地址) +filterWindow.seedNode=篩選後的種子節點(用逗號“,”隔開的洋葱地址) +filterWindow.priceRelayNode=篩選後的價格中繼節點(用逗號“,”隔開的洋葱地址) +filterWindow.btcNode=篩選後的比特幣節點(用逗號“,”隔開的地址+端口) +filterWindow.preventPublicBtcNetwork=禁止使用公共比特幣網絡 filterWindow.disableDao=禁用 DAO filterWindow.disableAutoConf=禁用自動確認 -filterWindow.autoConfExplorers=Filtered auto-confirm explorers (comma sep. addresses) +filterWindow.autoConfExplorers=已過濾自動確認瀏覽器(逗號分隔地址) filterWindow.disableDaoBelowVersion=DAO 最低所需要的版本 filterWindow.disableTradeBelowVersion=交易最低所需要的版本 -filterWindow.add=新增篩選 +filterWindow.add=添加篩選 filterWindow.remove=移除篩選 filterWindow.btcFeeReceiverAddresses=比特幣手續費接收地址 offerDetailsWindow.minBtcAmount=最小 BTC 數量 offerDetailsWindow.min=(最小 {0}) offerDetailsWindow.distance=(與市場價格的差距:{0}) -offerDetailsWindow.myTradingAccount=我的交易賬戶 +offerDetailsWindow.myTradingAccount=我的交易賬户 offerDetailsWindow.offererBankId=(賣家的銀行 ID/BIC/SWIFT) offerDetailsWindow.offerersBankName=(賣家的銀行名稱): offerDetailsWindow.bankId=銀行 ID(例如 BIC 或者 SWIFT ): @@ -2105,9 +2132,9 @@ offerDetailsWindow.countryBank=賣家銀行所在國家或地區 offerDetailsWindow.commitment=承諾 offerDetailsWindow.agree=我同意 offerDetailsWindow.tac=條款和條件 -offerDetailsWindow.confirm.maker=確定:釋出報價 {0} 比特幣 +offerDetailsWindow.confirm.maker=確定:發佈報價 {0} 比特幣 offerDetailsWindow.confirm.taker=確定:下單買入 {0} 比特幣 -offerDetailsWindow.creationDate=建立時間 +offerDetailsWindow.creationDate=創建時間 offerDetailsWindow.makersOnion=賣家的匿名地址 qRCodeWindow.headline=二維碼 @@ -2115,33 +2142,33 @@ qRCodeWindow.msg=請使用二維碼從外部錢包充值至 Bisq 錢包 qRCodeWindow.request=付款請求:\n{0} selectDepositTxWindow.headline=選擇糾紛的存款交易 -selectDepositTxWindow.msg=存款交易未儲存在交易中。\n請從您的錢包中選擇一個現有的多重驗證交易,這是在失敗的交易中使用的存款交易。\n\n您可以通過開啟交易詳細資訊視窗(點選列表中的交易 ID)並按照交易費用支付交易輸出到您看到多重驗證存款交易的下一個交易(地址從3開始),找到正確的交易。 該交易 ID 應在此處列出的列表中顯示。 一旦您找到正確的交易,請在此處選擇該交易並繼續\n\n抱歉給您帶來不便,但是錯誤的情況應該非常罕見,將來我們會嘗試找到更好的解決方法。 +selectDepositTxWindow.msg=存款交易未存儲在交易中。\n請從您的錢包中選擇一個現有的多重驗證交易,這是在失敗的交易中使用的存款交易。\n\n您可以通過打開交易詳細信息窗口(點擊列表中的交易 ID)並按照交易費用支付交易輸出到您看到多重驗證存款交易的下一個交易(地址從3開始),找到正確的交易。 該交易 ID 應在此處列出的列表中顯示。 一旦您找到正確的交易,請在此處選擇該交易並繼續\n\n抱歉給您帶來不便,但是錯誤的情況應該非常罕見,將來我們會嘗試找到更好的解決方法。 selectDepositTxWindow.select=選擇存款交易 -sendAlertMessageWindow.headline=傳送全球通知 -sendAlertMessageWindow.alertMsg=提醒訊息 -sendAlertMessageWindow.enterMsg=輸入訊息: +sendAlertMessageWindow.headline=發送全球通知 +sendAlertMessageWindow.alertMsg=提醒消息 +sendAlertMessageWindow.enterMsg=輸入消息: sendAlertMessageWindow.isUpdate=是更新通知 sendAlertMessageWindow.version=新版本號 -sendAlertMessageWindow.send=傳送通知 +sendAlertMessageWindow.send=發送通知 sendAlertMessageWindow.remove=移除通知 -sendPrivateNotificationWindow.headline=傳送私信 +sendPrivateNotificationWindow.headline=發送私信 sendPrivateNotificationWindow.privateNotification=私人通知 sendPrivateNotificationWindow.enterNotification=輸入通知 -sendPrivateNotificationWindow.send=傳送私人通知 +sendPrivateNotificationWindow.send=發送私人通知 -showWalletDataWindow.walletData=錢包資料 +showWalletDataWindow.walletData=錢包數據 showWalletDataWindow.includePrivKeys=包含私鑰 -setXMRTxKeyWindow.headline=證明已傳送 XMR -setXMRTxKeyWindow.note=在下面新增 tx 資訊可以更快的自動確認交易。更多資訊::https://bisq.wiki/Trading_Monero +setXMRTxKeyWindow.headline=證明已發送 XMR +setXMRTxKeyWindow.note=在下面添加 tx 信息可以更快的自動確認交易。更多信息::https://bisq.wiki/Trading_Monero setXMRTxKeyWindow.txHash=交易 ID (可選) -setXMRTxKeyWindow.txKey=交易金鑰 (可選) +setXMRTxKeyWindow.txKey=交易密鑰 (可選) # We do not translate the tac because of the legal nature. We would need translations checked by lawyers # in each language which is too expensive atm. -tacWindow.headline=使用者協議 +tacWindow.headline=用户協議 tacWindow.agree=我同意 tacWindow.disagree=我不同意並退出 tacWindow.arbitrationSystem=糾紛解決方案 @@ -2151,38 +2178,41 @@ tradeDetailsWindow.disputedPayoutTxId=糾紛支付交易 ID: tradeDetailsWindow.tradeDate=交易時間 tradeDetailsWindow.txFee=礦工手續費 tradeDetailsWindow.tradingPeersOnion=交易夥伴匿名地址 -tradeDetailsWindow.tradingPeersPubKeyHash=交易夥伴公鑰雜湊值 +tradeDetailsWindow.tradingPeersPubKeyHash=交易夥伴公鑰哈希值 tradeDetailsWindow.tradeState=交易狀態 tradeDetailsWindow.agentAddresses=仲裁員/調解員 +tradeDetailsWindow.detailData=Detail data walletPasswordWindow.headline=輸入密碼解鎖 -torNetworkSettingWindow.header=Tor 網路設定 +torNetworkSettingWindow.header=Tor 網絡設置 torNetworkSettingWindow.noBridges=不使用網橋 -torNetworkSettingWindow.providedBridges=連線到提供的網橋 +torNetworkSettingWindow.providedBridges=連接到提供的網橋 torNetworkSettingWindow.customBridges=輸入自定義網橋 -torNetworkSettingWindow.transportType=傳輸型別 +torNetworkSettingWindow.transportType=傳輸類型 torNetworkSettingWindow.obfs3=obfs3 torNetworkSettingWindow.obfs4=obfs4(推薦) torNetworkSettingWindow.meekAmazon=meek-amazon torNetworkSettingWindow.meekAzure=meek-azure torNetworkSettingWindow.enterBridge=輸入一個或多個網橋中繼節點(每行一個) -torNetworkSettingWindow.enterBridgePrompt=輸入地址:埠 +torNetworkSettingWindow.enterBridgePrompt=輸入地址:端口 torNetworkSettingWindow.restartInfo=您需要重新啟動以應用更改 -torNetworkSettingWindow.openTorWebPage=開啟 Tor Project 網頁 -torNetworkSettingWindow.deleteFiles.header=連線問題? -torNetworkSettingWindow.deleteFiles.info=如果您在啟動時有重複的連線問題,刪除過期的 Tor 檔案可能會有所幫助。如果要嘗試修復,請單擊下面的按鈕,然後重新啟動。 -torNetworkSettingWindow.deleteFiles.button=刪除過期的 Tor 檔案並關閉 -torNetworkSettingWindow.deleteFiles.progress=關閉正在執行中的 Tor -torNetworkSettingWindow.deleteFiles.success=過期的 Tor 檔案被成功刪除。請重新啟動。 -torNetworkSettingWindow.bridges.header=Tor 網路被遮蔽? -torNetworkSettingWindow.bridges.info=如果 Tor 被您的 Internet 提供商或您的國家或地區遮蔽,您可以嘗試使用 Tor 網橋。\n \n訪問 Tor 網頁:https://bridges.torproject.org/bridges,瞭解關於網橋和可插拔傳輸的更多資訊。 +torNetworkSettingWindow.openTorWebPage=打開 Tor Project 網頁 +torNetworkSettingWindow.deleteFiles.header=連接問題? +torNetworkSettingWindow.deleteFiles.info=如果您在啟動時有重複的連接問題,刪除過期的 Tor 文件可能會有所幫助。如果要嘗試修復,請單擊下面的按鈕,然後重新啟動。 +torNetworkSettingWindow.deleteFiles.button=刪除過期的 Tor 文件並關閉 +torNetworkSettingWindow.deleteFiles.progress=關閉正在運行中的 Tor +torNetworkSettingWindow.deleteFiles.success=過期的 Tor 文件被成功刪除。請重新啟動。 +torNetworkSettingWindow.bridges.header=Tor 網絡被屏蔽? +torNetworkSettingWindow.bridges.info=如果 Tor 被您的 Internet 提供商或您的國家或地區屏蔽,您可以嘗試使用 Tor 網橋。\n \n訪問 Tor 網頁:https://bridges.torproject.org/bridges,瞭解關於網橋和可插拔傳輸的更多信息。 feeOptionWindow.headline=選擇貨幣支付交易手續費 feeOptionWindow.info=您可以選擇用 BSQ 或 BTC 支付交易費用。如果您選擇 BSQ ,您會感謝這些交易手續費折扣。 feeOptionWindow.optionsLabel=選擇貨幣支付交易手續費 feeOptionWindow.useBTC=使用 BTC feeOptionWindow.fee={0}(≈ {1}) +feeOptionWindow.btcFeeWithFiatAndPercentage={0} (≈ {1} / {2}) +feeOptionWindow.btcFeeWithPercentage={0} ({1}) #################################################################### @@ -2196,122 +2226,121 @@ popup.headline.backgroundInfo=背景資料 popup.headline.feedback=完成 popup.headline.confirmation=確定 popup.headline.information=資料 -popup.headline.warning=警告 +popup.headline.warning=警吿 popup.headline.error=錯誤 popup.doNotShowAgain=不要再顯示 -popup.reportError.log=開啟日誌檔案 -popup.reportError.gitHub=報告至 Github issue tracker -popup.reportError={0}\n\n為了幫助我們改進軟體,請在 https://github.com/bisq-network/bisq/issues 上開啟一個新問題來報告這個 bug 。\n\n當您單擊下面任意一個按鈕時,上面的錯誤訊息將被複制到剪貼簿。\n\n如果您通過按下“開啟日誌檔案”,儲存一份副本,並將其附加到 bug 報告中,如果包含 bisq.log 檔案,那麼除錯就會變得更容易。 +popup.reportError.log=打開日誌文件 +popup.reportError.gitHub=報吿至 Github issue tracker +popup.reportError={0}\n\n為了幫助我們改進軟件,請在 https://github.com/bisq-network/bisq/issues 上打開一個新問題來報吿這個 bug 。\n\n當您單擊下面任意一個按鈕時,上面的錯誤消息將被複制到剪貼板。\n\n如果您通過按下“打開日誌文件”,保存一份副本,並將其附加到 bug 報吿中,如果包含 bisq.log 文件,那麼調試就會變得更容易。 -popup.error.tryRestart=請嘗試重啟您的應用程式或者檢查您的網路連線。 +popup.error.tryRestart=請嘗試重啟您的應用程序或者檢查您的網絡連接。 popup.error.takeOfferRequestFailed=當有人試圖接受你的報價時發生了一個錯誤:\n{0} -error.spvFileCorrupted=讀取 SPV 鏈檔案時發生錯誤。\n可能是 SPV 鏈檔案被破壞了。\n\n錯誤訊息:{0}\n\n要刪除它並開始重新同步嗎? -error.deleteAddressEntryListFailed=無法刪除 AddressEntryList 檔案。\n \n錯誤:{0} -error.closedTradeWithUnconfirmedDepositTx=交易 ID 為 {0} 的已關閉交易的保證金交易仍未確認。\n \n請在“設定/網路資訊”進行 SPV 重新同步,以檢視交易是否有效。 -error.closedTradeWithNoDepositTx=交易 ID 為 {0} 的保證金交易已被確認。\n\n請重新啟動應用程式來清理已關閉的交易列表。 +error.spvFileCorrupted=讀取 SPV 鏈文件時發生錯誤。\n可能是 SPV 鏈文件被破壞了。\n\n錯誤消息:{0}\n\n要刪除它並開始重新同步嗎? +error.deleteAddressEntryListFailed=無法刪除 AddressEntryList 文件。\n \n錯誤:{0} +error.closedTradeWithUnconfirmedDepositTx=交易 ID 為 {0} 的已關閉交易的保證金交易仍未確認。\n \n請在“設置/網絡信息”進行 SPV 重新同步,以查看交易是否有效。 +error.closedTradeWithNoDepositTx=交易 ID 為 {0} 的保證金交易已被確認。\n\n請重新啟動應用程序來清理已關閉的交易列表。 popup.warning.walletNotInitialized=錢包至今未初始化 -popup.warning.osxKeyLoggerWarning=由於 MacOS 10.14 及更高版本中的安全措施更加嚴格,因此啟動 Java 應用程式(Bisq 使用Java)會在 MacOS 中引發彈出警告(``Bisq 希望從任何應用程式接收擊鍵'').\n\n為了避免該問題,請開啟“ MacOS 設定”,然後轉到“安全和隱私”->“隱私”->“輸入監視”,然後從右側列表中刪除“ Bisq”。\n\n一旦解決了技術限制(所需的 Java 版本的 Java 打包程式尚未交付),Bisq將升級到新的 Java 版本,以避免該問題。 -popup.warning.wrongVersion=您這臺電腦上可能有錯誤的 Bisq 版本。\n您的電腦的架構是:{0}\n您安裝的 Bisq 二進位制檔案是:{1}\n請關閉並重新安裝正確的版本({2})。 -popup.warning.incompatibleDB=我們檢測到不相容的資料庫檔案!\n\n那些資料庫檔案與我們當前的程式碼庫不相容:\n{0}\n\n我們對損壞的檔案進行了備份,並將預設值應用於新的資料庫版本。\n\n備份位於:\n{1}/db/backup_of_corrupted_data。\n\n請檢查您是否安裝了最新版本的 Bisq\n您可以下載:\nhttps://bisq.network/downloads\n\n請重新啟動應用程式。 -popup.warning.startupFailed.twoInstances=Bisq 已經在執行。 您不能執行兩個 Bisq 例項。 -popup.warning.tradePeriod.halfReached=您與 ID {0} 的交易已達到最長交易期的一半,且仍未完成。\n\n交易期結束於 {1}\n\n請檢視“業務/未完成交易”的交易狀態,以獲取更多資訊。 -popup.warning.tradePeriod.ended=您與 ID {0} 的已達到最長交易期,且未完成。\n\n交易期結束於 {1}\n\n請檢視“業務/未完成交易”的交易狀態,以從調解員獲取更多資訊。 -popup.warning.noTradingAccountSetup.headline=您還沒有設定交易賬戶 -popup.warning.noTradingAccountSetup.msg=您需要設定法定貨幣或數字貨幣賬戶才能建立報價。\n您要設定帳戶嗎? +popup.warning.osxKeyLoggerWarning=由於 MacOS 10.14 及更高版本中的安全措施更加嚴格,因此啟動 Java 應用程序(Bisq 使用Java)會在 MacOS 中引發彈出警吿(``Bisq 希望從任何應用程序接收擊鍵'').\n\n為了避免該問題,請打開“ MacOS 設置”,然後轉到“安全和隱私”->“隱私”->“輸入監視”,然後從右側列表中刪除“ Bisq”。\n\n一旦解決了技術限制(所需的 Java 版本的 Java 打包程序尚未交付),Bisq將升級到新的 Java 版本,以避免該問題。 +popup.warning.wrongVersion=您這台電腦上可能有錯誤的 Bisq 版本。\n您的電腦的架構是:{0}\n您安裝的 Bisq 二進制文件是:{1}\n請關閉並重新安裝正確的版本({2})。 +popup.warning.incompatibleDB=我們檢測到不兼容的數據庫文件!\n\n那些數據庫文件與我們當前的代碼庫不兼容:\n{0}\n\n我們對損壞的文件進行了備份,並將默認值應用於新的數據庫版本。\n\n備份位於:\n{1}/db/backup_of_corrupted_data。\n\n請檢查您是否安裝了最新版本的 Bisq\n您可以下載:\nhttps://bisq.network/downloads\n\n請重新啟動應用程序。 +popup.warning.startupFailed.twoInstances=Bisq 已經在運行。 您不能運行兩個 Bisq 實例。 +popup.warning.tradePeriod.halfReached=您與 ID {0} 的交易已達到最長交易期的一半,且仍未完成。\n\n交易期結束於 {1}\n\n請查看“業務/未完成交易”的交易狀態,以獲取更多信息。 +popup.warning.tradePeriod.ended=您與 ID {0} 的已達到最長交易期,且未完成。\n\n交易期結束於 {1}\n\n請查看“業務/未完成交易”的交易狀態,以從調解員獲取更多信息。 +popup.warning.noTradingAccountSetup.headline=您還沒有設置交易賬户 +popup.warning.noTradingAccountSetup.msg=您需要設置法定貨幣或數字貨幣賬户才能創建報價。\n您要設置帳户嗎? popup.warning.noArbitratorsAvailable=沒有仲裁員可用。 popup.warning.noMediatorsAvailable=沒有調解員可用。 -popup.warning.notFullyConnected=您需要等到您完全連線到網路\n在啟動時可能需要2分鐘。 -popup.warning.notSufficientConnectionsToBtcNetwork=你需要等待至少有{0}個與比特幣網路的連線點。 +popup.warning.notFullyConnected=您需要等到您完全連接到網絡\n在啟動時可能需要2分鐘。 +popup.warning.notSufficientConnectionsToBtcNetwork=你需要等待至少有{0}個與比特幣網絡的連接點。 popup.warning.downloadNotComplete=您需要等待,直到丟失的比特幣區塊被下載完畢。 +popup.warning.chainNotSynced=Bisq 錢包區塊鏈高度沒有正確地同步。如果最近才打開應用,請等待一個新發布的比特幣區塊。\n\n你可以檢查區塊鏈高度在設置/網絡信息。如果經過了一個區塊但問題還是沒有解決,你應該及時的完成 SPV 鏈重新同步。https://bisq.wiki/Resyncing_SPV_file popup.warning.removeOffer=您確定要移除該報價嗎?\n如果您刪除該報價,{0} 的掛單費將會丟失。 -popup.warning.tooLargePercentageValue=您不能設定100%或更大的百分比。 +popup.warning.tooLargePercentageValue=您不能設置100%或更大的百分比。 popup.warning.examplePercentageValue=請輸入百分比數字,如 5.4% 是“5.4” popup.warning.noPriceFeedAvailable=該貨幣沒有可用的價格。 你不能使用基於百分比的價格。\n請選擇固定價格。 -popup.warning.sendMsgFailed=向您的交易物件傳送訊息失敗。\n請重試,如果繼續失敗報告錯誤。 +popup.warning.sendMsgFailed=向您的交易對象發送消息失敗。\n請重試,如果繼續失敗報吿錯誤。 popup.warning.insufficientBtcFundsForBsqTx=你沒有足夠的 BTC 資金支付這筆交易的挖礦手續費。\n請充值您的 BTC 錢包。\n缺少的資金:{0} -popup.warning.bsqChangeBelowDustException=該交易產生的 BSQ 變化輸出低於零頭限制(5.46 BSQ),將被比特幣網路拒絕。\n\n您需要傳送更高的金額以避免更改輸出(例如,通過在您的傳送金額中新增零頭),或者向您的錢包中新增更多的 BSQ 資金,以避免生成零頭輸出。\n\n零頭輸出為 {0}。 -popup.warning.btcChangeBelowDustException=該交易建立的更改輸出低於零頭限制(546 聰),將被比特幣網路拒絕。\n\n您需要將零頭新增到傳送量中,以避免生成零頭輸出。\n\n零頭輸出為{0}。 +popup.warning.bsqChangeBelowDustException=該交易產生的 BSQ 變化輸出低於零頭限制(5.46 BSQ),將被比特幣網絡拒絕。\n\n您需要發送更高的金額以避免更改輸出(例如,通過在您的發送金額中添加零頭),或者向您的錢包中添加更多的 BSQ 資金,以避免生成零頭輸出。\n\n零頭輸出為 {0}。 +popup.warning.btcChangeBelowDustException=該交易創建的更改輸出低於零頭限制(546 聰),將被比特幣網絡拒絕。\n\n您需要將零頭添加到發送量中,以避免生成零頭輸出。\n\n零頭輸出為{0}。 popup.warning.insufficientBsqFundsForBtcFeePayment=您需要更多的 BSQ 去完成這筆交易 - 錢包中最後剩餘 5.46 BSQ 將無法用於支付交易手續費因為 BTC 協議中的零頭限制。\n\n你可以購買更多的 BSQ 或用 BTC支付交易手續費\n\n缺少 BSQ 資金:{0} popup.warning.noBsqFundsForBtcFeePayment=您的 BSQ 錢包沒有足夠的資金支付 BSQ 的交易費用。 -popup.warning.messageTooLong=您的資訊超過最大允許的大小。請將其分成多個部分傳送,或將其上傳到 https://pastebin.com 之類的伺服器。 -popup.warning.lockedUpFunds=你已經從一個失敗的交易中凍結了資金。\n凍結餘額:{0}\n存款tx地址:{1}\n交易單號:{2}\n\n請通過選擇待處理交易介面中的交易並點選“alt + o”或“option+ o”開啟幫助話題。 +popup.warning.messageTooLong=您的信息超過最大允許的大小。請將其分成多個部分發送,或將其上傳到 https://pastebin.com 之類的服務器。 +popup.warning.lockedUpFunds=你已經從一個失敗的交易中凍結了資金。\n凍結餘額:{0}\n存款tx地址:{1}\n交易單號:{2}\n\n請通過選擇待處理交易界面中的交易並點擊“alt + o”或“option+ o”打開幫助話題。 # suppress inspection "UnusedProperty" popup.warning.nodeBanned=其中一個 {0} 節點已被禁用 # suppress inspection "UnusedProperty" popup.warning.priceRelay=價格傳遞 popup.warning.seed=種子 -popup.warning.mandatoryUpdate.trading=請更新到最新的 Bisq 版本。強制更新禁止了舊版本進行交易。更多資訊請訪問 Bisq 論壇。 -popup.warning.mandatoryUpdate.dao=請更新到最新的 Bisq 版本。強制更新禁止了舊版本舊版本的 Bisq DAO 和 BSQ 。更多資訊請訪問 Bisq 論壇。 -popup.warning.disable.dao=Bisq DAO 和 BSQ 被臨時禁用的。更多資訊請訪問 Bisq 論壇。 +popup.warning.mandatoryUpdate.trading=請更新到最新的 Bisq 版本。強制更新禁止了舊版本進行交易。更多信息請訪問 Bisq 論壇。 +popup.warning.mandatoryUpdate.dao=請更新到最新的 Bisq 版本。強制更新禁止了舊版本舊版本的 Bisq DAO 和 BSQ 。更多信息請訪問 Bisq 論壇。 +popup.warning.disable.dao=Bisq DAO 和 BSQ 被臨時禁用的。更多信息請訪問 Bisq 論壇。 popup.warning.burnBTC=這筆交易是無法實現,因為 {0} 的挖礦手續費用會超過 {1} 的轉賬金額。請等到挖礦手續費再次降低或您積累了更多的 BTC 來轉賬。 -popup.warning.openOffer.makerFeeTxRejected=交易 ID 為 {0} 的掛單費交易被比特幣網路拒絕。\n交易 ID = {1}\n交易已被移至失敗交易。\n請到“設定/網路資訊”進行 SPV 重新同步。\n如需更多幫助,請聯絡 Bisq Keybase 團隊的 Support 頻道 +popup.warning.openOffer.makerFeeTxRejected=交易 ID 為 {0} 的掛單費交易被比特幣網絡拒絕。\n交易 ID = {1}\n交易已被移至失敗交易。\n請到“設置/網絡信息”進行 SPV 重新同步。\n如需更多幫助,請聯繫 Bisq Keybase 團隊的 Support 頻道 popup.warning.trade.txRejected.tradeFee=交易手續費 popup.warning.trade.txRejected.deposit=押金 -popup.warning.trade.txRejected=使用 ID {1} 進行交易的 {0} 交易被比特幣網路拒絕。\n交易 ID = {2}}\n交易已被移至失敗交易。\n請到“設定/網路資訊”進行 SPV 重新同步。\n如需更多幫助,請聯絡 Bisq Keybase 團隊的 Support 頻道 +popup.warning.trade.txRejected=The {0} transaction for trade with ID {1} was rejected by the Bitcoin network.\nTransaction ID={2}\nThe trade has been moved to failed trades.\nPlease go to \"Settings/Network info\" and do a SPV resync.\nFor further help please contact the Bisq support channel at the Bisq Keybase team. -popup.warning.openOfferWithInvalidMakerFeeTx=交易 ID 為 {0} 的掛單費交易無效。\n交易 ID = {1}。\n請到“設定/網路資訊”進行 SPV 重新同步。\n如需更多幫助,請聯絡 Bisq Keybase 團隊的 Support 頻道 +popup.warning.openOfferWithInvalidMakerFeeTx=交易 ID 為 {0} 的掛單費交易無效。\n交易 ID = {1}。\n請到“設置/網絡信息”進行 SPV 重新同步。\n如需更多幫助,請聯繫 Bisq Keybase 團隊的 Support 頻道 -popup.info.securityDepositInfo=為了確保雙方都遵守交易協議,雙方都需要支付保證金。\n\n這筆存款一直儲存在您的交易錢包裡,直到您的交易成功完成,然後再退還給您。\n\n請注意:如果您正在建立一個新的報價,Bisq 需要執行另一個交易員接受它。為了讓您的報價線上,保持 Bisq 執行,並確保這臺計算機也線上(即,確保它沒有切換到待機模式…顯示器可以待機)。 +popup.info.securityDepositInfo=為了確保雙方都遵守交易協議,雙方都需要支付保證金。\n\n這筆存款一直保存在您的交易錢包裏,直到您的交易成功完成,然後再退還給您。\n\n請注意:如果您正在創建一個新的報價,Bisq 需要運行另一個交易員接受它。為了讓您的報價在線,保持 Bisq 運行,並確保這台計算機也在線(即,確保它沒有切換到待機模式…顯示器可以待機)。 popup.info.cashDepositInfo=請確保您在您的地區有一個銀行分行,以便能夠進行現金存款。\n賣方銀行的銀行 ID(BIC/SWIFT)為:{0}。 popup.info.cashDepositInfo.confirm=我確認我可以支付保證金 -popup.info.shutDownWithOpenOffers=Bisq 正在被關閉,但仍有公開的報價。\n\n當 Bisq 關閉時,這些提供將不能在 P2P 網路上使用,但是它們將在您下次啟動 Bisq 時重新發布到 P2P 網路上。\n\n為了讓您的報價線上,保持 Bisq 執行,並確保這臺計算機也線上(即,確保它不會進入待機模式…顯示器待機不是問題)。 -popup.info.qubesOSSetupInfo=It appears you are running Bisq on Qubes OS. \n\nPlease make sure your Bisq qube is setup according to our Setup Guide at [HYPERLINK:https://bisq.wiki/Running_Bisq_on_Qubes]. +popup.info.shutDownWithOpenOffers=Bisq 正在被關閉,但仍有公開的報價。\n\n當 Bisq 關閉時,這些提供將不能在 P2P 網絡上使用,但是它們將在您下次啟動 Bisq 時重新發布到 P2P 網絡上。\n\n為了讓您的報價在線,保持 Bisq 運行,並確保這台計算機也在線(即,確保它不會進入待機模式…顯示器待機不是問題)。 +popup.info.qubesOSSetupInfo=你似乎好像在 Qubes OS 上運行 Bisq。\n\n請確保您的 Bisq qube 是參考設置指南的説明設置的 https://bisq.wiki/Running_Bisq_on_Qubes +popup.warn.downGradePrevention=不支持從 {0} 版本降級到 {1} 版本。請使用最新的 Bisq 版本。 +popup.warn.daoRequiresRestart=There was a problem with synchronizing the DAO state. You have to restart the application to fix the issue. popup.privateNotification.headline=重要私人通知! popup.securityRecommendation.headline=重要安全建議 -popup.securityRecommendation.msg=如果您還沒有啟用,我們想提醒您考慮為您的錢包使用密碼保護。\n\n強烈建議你寫下錢包還原金鑰。 那些還原金鑰就是恢復你的比特幣錢包的主密碼。\n在“錢包金鑰”部分,您可以找到更多資訊\n\n此外,您應該在“備份”介面備份完整的應用程式資料資料夾。 +popup.securityRecommendation.msg=如果您還沒有啟用,我們想提醒您考慮為您的錢包使用密碼保護。\n\n強烈建議你寫下錢包還原密鑰。 那些還原密鑰就是恢復你的比特幣錢包的主密碼。\n在“錢包密鑰”部分,您可以找到更多信息\n\n此外,您應該在“備份”界面備份完整的應用程序數據文件夾。 -popup.bitcoinLocalhostNode.msg=Bisq 檢測到一個本地執行的比特幣核心節點(在本地主機)。\n在啟動 Bisq 之前,請確保此節點已完全同步,並且沒有在刪除模式下執行。 -popup.bitcoinLocalhostNode.additionalRequirements=\n\n對於配置完整的節點,要求該節點禁用 pruning 並啟用 bloom filters。 +popup.bitcoinLocalhostNode.msg=Bisq detected a Bitcoin Core node running on this machine (at localhost).\n\nPlease ensure:\n- the node is fully synced before starting Bisq\n- pruning is disabled ('prune=0' in bitcoin.conf)\n- bloom filters are enabled ('peerbloomfilters=1' in bitcoin.conf) popup.shutDownInProgress.headline=正在關閉 popup.shutDownInProgress.msg=關閉應用可能會花一點時間。\n請不要打斷關閉過程。 popup.attention.forTradeWithId=交易 ID {0} 需要注意 -popup.info.multiplePaymentAccounts.headline=多個支付賬戶可用 -popup.info.multiplePaymentAccounts.msg=您有多個支付帳戶在這個報價中可用。請確你做了正確的選擇。 +popup.info.multiplePaymentAccounts.headline=多個支付賬户可用 +popup.info.multiplePaymentAccounts.msg=您有多個支付帳户在這個報價中可用。請確你做了正確的選擇。 -popup.accountSigning.selectAccounts.headline=選擇付款賬戶 -popup.accountSigning.selectAccounts.description=根據付款方式和時間點,所有與支付給買方的付款發生的爭議有關的付款帳戶將被選擇讓您驗證。 +popup.accountSigning.selectAccounts.headline=選擇付款賬户 +popup.accountSigning.selectAccounts.description=根據付款方式和時間點,所有與支付給買方的付款發生的爭議有關的付款帳户將被選擇讓您驗證。 popup.accountSigning.selectAccounts.signAll=驗證所有付款方式 -popup.accountSigning.selectAccounts.datePicker=選擇要驗證的帳戶的時間點 +popup.accountSigning.selectAccounts.datePicker=選擇要驗證的帳户的時間點 -popup.accountSigning.confirmSelectedAccounts.headline=確認選定的付款帳戶 -popup.accountSigning.confirmSelectedAccounts.description=根據您的輸入,將選擇 {0} 支付帳戶。 -popup.accountSigning.confirmSelectedAccounts.button=確認付款賬戶 -popup.accountSigning.signAccounts.headline=確認驗證付款賬戶 -popup.accountSigning.signAccounts.description=根據您的選擇,{0} 付款帳戶將被驗證。 -popup.accountSigning.signAccounts.button=驗證付款賬戶 -popup.accountSigning.signAccounts.ECKey=輸入仲裁員金鑰 +popup.accountSigning.confirmSelectedAccounts.headline=確認選定的付款帳户 +popup.accountSigning.confirmSelectedAccounts.description=根據您的輸入,將選擇 {0} 支付帳户。 +popup.accountSigning.confirmSelectedAccounts.button=確認付款賬户 +popup.accountSigning.signAccounts.headline=確認驗證付款賬户 +popup.accountSigning.signAccounts.description=根據您的選擇,{0} 付款帳户將被驗證。 +popup.accountSigning.signAccounts.button=驗證付款賬户 +popup.accountSigning.signAccounts.ECKey=輸入仲裁員密鑰 popup.accountSigning.signAccounts.ECKey.error=不正確的仲裁員 ECKey popup.accountSigning.success.headline=恭喜 -popup.accountSigning.success.description=所有 {0} 支付賬戶已成功驗證! -popup.accountSigning.generalInformation=您將在帳戶頁面找到所有賬戶的驗證狀態。\n\n更多資訊,請訪問https://docs.bisq.network/payment-methods#account-signing. -popup.accountSigning.signedByArbitrator=您的一個付款帳戶已被認證以及被仲裁員驗證。交易成功後,使用此帳戶將自動驗證您的交易夥伴的帳戶。\n\n{0} -popup.accountSigning.signedByPeer=您的一個付款帳戶已經被交易夥伴驗證和驗證。您的初始交易限額將被取消,您將能夠在{0}天后驗證其他帳戶。 -popup.accountSigning.peerLimitLifted=您其中一個帳戶的初始限額已被取消。\n\n{0} -popup.accountSigning.peerSigner=您的一個帳戶已足夠成熟,可以驗證其他付款帳戶,您的一個帳戶的初始限額已被取消。\n\n{0} +popup.accountSigning.success.description=所有 {0} 支付賬户已成功驗證! +popup.accountSigning.generalInformation=您將在帳户頁面找到所有賬户的驗證狀態。\n\n更多信息,請訪問https://docs.bisq.network/payment-methods#account-signing. +popup.accountSigning.signedByArbitrator=您的一個付款帳户已被認證以及被仲裁員驗證。交易成功後,使用此帳户將自動驗證您的交易夥伴的帳户。\n\n{0} +popup.accountSigning.signedByPeer=您的一個付款帳户已經被交易夥伴驗證和驗證。您的初始交易限額將被取消,您將能夠在{0}天后驗證其他帳户。 +popup.accountSigning.peerLimitLifted=您其中一個帳户的初始限額已被取消。\n\n{0} +popup.accountSigning.peerSigner=您的一個帳户已足夠成熟,可以驗證其他付款帳户,您的一個帳户的初始限額已被取消。\n\n{0} -popup.accountSigning.singleAccountSelect.headline=選擇賬齡證據 -popup.accountSigning.singleAccountSelect.description=尋找賬齡證據 -popup.accountSigning.singleAccountSelect.datePicker=選擇要驗證的帳戶的時間點 +popup.accountSigning.singleAccountSelect.headline=Import unsigned account age witness popup.accountSigning.confirmSingleAccount.headline=確認所選賬齡證據 -popup.accountSigning.confirmSingleAccount.selectedHash=已選擇證據雜湊值 +popup.accountSigning.confirmSingleAccount.selectedHash=已選擇證據哈希值 popup.accountSigning.confirmSingleAccount.button=驗證賬齡證據 popup.accountSigning.successSingleAccount.description=證據 {0} 已被驗證 popup.accountSigning.successSingleAccount.success.headline=成功 -popup.accountSigning.successSingleAccount.signError=未能成功驗證證據,{0} popup.accountSigning.unsignedPubKeys.headline=未驗證公鑰 popup.accountSigning.unsignedPubKeys.sign=驗證公鑰 @@ -2330,11 +2359,11 @@ notification.trade.accepted=您 BTC {0} 的報價被接受。 notification.trade.confirmed=您的交易至少有一個區塊鏈確認。\n您現在可以開始付款。 notification.trade.paymentStarted=BTC 買家已經開始付款。 notification.trade.selectTrade=選擇交易 -notification.trade.peerOpenedDispute=您的交易物件建立了一個 {0}。 +notification.trade.peerOpenedDispute=您的交易對象創建了一個 {0}。 notification.trade.disputeClosed=這個 {0} 被關閉。 notification.walletUpdate.headline=交易錢包更新 notification.walletUpdate.msg=您的交易錢包充值成功。\n金額:{0} -notification.takeOffer.walletUpdate.msg=您的交易錢包已經從早期的下單嘗試中得到足夠的資金支援。\n金額:{0} +notification.takeOffer.walletUpdate.msg=您的交易錢包已經從早期的下單嘗試中得到足夠的資金支持。\n金額:{0} notification.tradeCompleted.headline=交易完成 notification.tradeCompleted.msg=您現在可以提現您的資金到您的外部比特幣錢包或者劃轉它到 Bisq 錢包。 @@ -2343,32 +2372,32 @@ notification.tradeCompleted.msg=您現在可以提現您的資金到您的外部 # System Tray #################################################################### -systemTray.show=顯示應用程式視窗 -systemTray.hide=隱藏應用程式視窗 -systemTray.info=關於 Bisq 資訊 +systemTray.show=顯示應用程序窗口 +systemTray.hide=隱藏應用程序窗口 +systemTray.info=關於 Bisq 信息 systemTray.exit=退出 -systemTray.tooltip=Bisq:去中心化比特幣交易網路 +systemTray.tooltip=Bisq:去中心化比特幣交易網絡 #################################################################### # GUI Util #################################################################### -guiUtil.miningFeeInfo=Please be sure that the mining fee used by your external wallet is at least {0} satoshis/vbyte. Otherwise the trade transactions may not be confirmed in time and the trade will end up in a dispute. +guiUtil.miningFeeInfo=請確保您的外部錢包使用的礦工手續費費用足夠高至少為 {0} 聰/字節,以便礦工接受資金交易。\n否則交易所交易無法確認,交易最終將會出現糾紛。 -guiUtil.accountExport.savedToPath=交易賬戶儲存在路徑:\n{0} -guiUtil.accountExport.noAccountSetup=您沒有交易賬戶設定匯出。 +guiUtil.accountExport.savedToPath=交易賬户保存在路徑:\n{0} +guiUtil.accountExport.noAccountSetup=您沒有交易賬户設置導出。 guiUtil.accountExport.selectPath=選擇路徑 {0} # suppress inspection "TrailingSpacesInProperty" -guiUtil.accountExport.tradingAccount=交易賬戶 ID {0}\n +guiUtil.accountExport.tradingAccount=交易賬户 ID {0}\n # suppress inspection "TrailingSpacesInProperty" -guiUtil.accountImport.noImport=我們沒有匯入 ID {0} 的交易賬戶,因為它已經存在。\n -guiUtil.accountExport.exportFailed=匯出 .CSV 失敗,因為發生了錯誤。\n錯誤 = {0} -guiUtil.accountExport.selectExportPath=選擇匯出路徑 -guiUtil.accountImport.imported=交易賬戶匯入路徑:\n{0}\n\n匯入賬戶:\n{1} -guiUtil.accountImport.noAccountsFound=在路徑 {0} 找不到匯出的交易賬戶。\n檔名為 {1}。 -guiUtil.openWebBrowser.warning=您將在系統網路瀏覽器中開啟一個網頁。\n你現在要開啟網頁嗎?\n\n如果您沒有使用“Tor 瀏覽器”作為預設的系統網路瀏覽器,則將以預設連線到網頁。\n\n網址:“{0}” -guiUtil.openWebBrowser.doOpen=開啟網頁並且不要再詢問我 +guiUtil.accountImport.noImport=我們沒有導入 ID {0} 的交易賬户,因為它已經存在。\n +guiUtil.accountExport.exportFailed=導出 .CSV 失敗,因為發生了錯誤。\n錯誤 = {0} +guiUtil.accountExport.selectExportPath=選擇導出路徑 +guiUtil.accountImport.imported=交易賬户導入路徑:\n{0}\n\n導入賬户:\n{1} +guiUtil.accountImport.noAccountsFound=在路徑 {0} 找不到導出的交易賬户。\n文件名為 {1}。 +guiUtil.openWebBrowser.warning=您將在系統網絡瀏覽器中打開一個網頁。\n你現在要打開網頁嗎?\n\n如果您沒有使用“Tor 瀏覽器”作為默認的系統網絡瀏覽器,則將以默認連接到網頁。\n\n網址:“{0}” +guiUtil.openWebBrowser.doOpen=打開網頁並且不要再詢問我 guiUtil.openWebBrowser.copyUrl=複製 URL 並取消 guiUtil.ofTradeAmount=的交易數量 guiUtil.requiredMinimum=(最低需求量) @@ -2382,44 +2411,44 @@ list.currency.showAll=顯示全部 list.currency.editList=編輯幣種列表 table.placeholder.noItems=最近沒有可用的 {0} -table.placeholder.noData=最近沒有可用資料 -table.placeholder.processingData=處理資料… +table.placeholder.noData=最近沒有可用數據 +table.placeholder.processingData=處理數據… peerInfoIcon.tooltip.tradePeer=交易夥伴 peerInfoIcon.tooltip.maker=製造者 peerInfoIcon.tooltip.trade.traded={0} 匿名地址:{1}\n您已經與他交易過 {2} 次了\n{3} peerInfoIcon.tooltip.trade.notTraded={0} 匿名地址:{1}\n你還沒有與他交易過。\n{2} -peerInfoIcon.tooltip.age=支付賬戶在 {0} 前建立。 -peerInfoIcon.tooltip.unknownAge=支付賬戶賬齡未知。 +peerInfoIcon.tooltip.age=支付賬户在 {0} 前創建。 +peerInfoIcon.tooltip.unknownAge=支付賬户賬齡未知。 -tooltip.openPopupForDetails=開啟彈出視窗的詳細資訊 -tooltip.invalidTradeState.warning=這個交易處於不可用狀態。開啟詳情視窗以發現更多細節。 -tooltip.openBlockchainForAddress=使用外部區塊鏈瀏覽器開啟地址:{0} -tooltip.openBlockchainForTx=使用外部區塊鏈瀏覽器開啟交易:{0} +tooltip.openPopupForDetails=打開彈出窗口的詳細信息 +tooltip.invalidTradeState.warning=這個交易處於不可用狀態。打開詳情窗口以發現更多細節。 +tooltip.openBlockchainForAddress=使用外部區塊鏈瀏覽器打開地址:{0} +tooltip.openBlockchainForTx=使用外部區塊鏈瀏覽器打開交易:{0} confidence.unknown=未知交易狀態 -confidence.seen=被 {0} 人檢視 / 0 確定 +confidence.seen=被 {0} 人查看 / 0 確定 confidence.confirmed=在 {0} 區塊中確認 confidence.invalid=交易無效 -peerInfo.title=物件資料 +peerInfo.title=對象資料 peerInfo.nrOfTrades=已完成交易數量 peerInfo.notTradedYet=你還沒有與他交易過。 -peerInfo.setTag=設定該物件的標籤 -peerInfo.age.noRisk=支付賬戶賬齡 +peerInfo.setTag=設置該對象的標籤 +peerInfo.age.noRisk=支付賬户賬齡 peerInfo.age.chargeBackRisk=自驗證 peerInfo.unknownAge=賬齡未知 -addressTextField.openWallet=開啟您的預設比特幣錢包 -addressTextField.copyToClipboard=複製地址到剪貼簿 -addressTextField.addressCopiedToClipboard=地址已被複制到剪貼簿 -addressTextField.openWallet.failed=開啟預設的比特幣錢包應用程式失敗了。或許您沒有安裝? +addressTextField.openWallet=打開您的默認比特幣錢包 +addressTextField.copyToClipboard=複製地址到剪貼板 +addressTextField.addressCopiedToClipboard=地址已被複制到剪貼板 +addressTextField.openWallet.failed=打開默認的比特幣錢包應用程序失敗了。或許您沒有安裝? peerInfoIcon.tooltip={0}\n標識:{1} -txIdTextField.copyIcon.tooltip=複製交易 ID 到剪貼簿 -txIdTextField.blockExplorerIcon.tooltip=使用外部區塊鏈瀏覽器開啟這個交易 ID +txIdTextField.copyIcon.tooltip=複製交易 ID 到剪貼板 +txIdTextField.blockExplorerIcon.tooltip=使用外部區塊鏈瀏覽器打開這個交易 ID txIdTextField.missingTx.warning.tooltip=所需的交易缺失 @@ -2427,14 +2456,14 @@ txIdTextField.missingTx.warning.tooltip=所需的交易缺失 # Navigation #################################################################### -navigation.account=“賬戶” -navigation.account.walletSeed=“賬戶/錢包金鑰” +navigation.account=“賬户” +navigation.account.walletSeed=“賬户/錢包密鑰” navigation.funds.availableForWithdrawal=“資金/提現” navigation.portfolio.myOpenOffers=“資料/未完成報價” navigation.portfolio.pending=“業務/未完成交易” navigation.portfolio.closedTrades=“資料/歷史” navigation.funds.depositFunds=“資金/收到資金” -navigation.settings.preferences=“設定/偏好” +navigation.settings.preferences=“設置/偏好” # suppress inspection "UnusedProperty" navigation.funds.transactions=“資金/交易記錄” navigation.support=“幫助” @@ -2447,11 +2476,11 @@ navigation.dao.wallet.receive=“DAO/BSQ 錢包/接收” formatter.formatVolumeLabel={0} 數量 {1} formatter.makerTaker=賣家 {0} {1} / 買家 {2} {3} -formatter.youAreAsMaker=您是 {0} {1} 賣家 / 買家是 {2} {3} -formatter.youAreAsTaker=您是 {0} {1} 買家 / 賣家是 {2} {3} +formatter.youAreAsMaker=You are: {1} {0} (maker) / Taker is: {3} {2} +formatter.youAreAsTaker=You are: {1} {0} (taker) / Maker is: {3} {2} formatter.youAre=您是 {0} {1} ({2} {3}) -formatter.youAreCreatingAnOffer.fiat=您建立新的報價 {0} {1} -formatter.youAreCreatingAnOffer.altcoin=您正建立報價 {0} {1}({2} {3}) +formatter.youAreCreatingAnOffer.fiat=您創建新的報價 {0} {1} +formatter.youAreCreatingAnOffer.altcoin=您正創建報價 {0} {1}({2} {3}) formatter.asMaker={0} {1} 是賣家 formatter.asTaker={0} {1} 是買家 @@ -2463,15 +2492,15 @@ formatter.asTaker={0} {1} 是買家 # we use enum values here # dynamic values are not recognized by IntelliJ # suppress inspection "UnusedProperty" -BTC_MAINNET=比特幣主幹網路 +BTC_MAINNET=比特幣主幹網絡 # suppress inspection "UnusedProperty" -BTC_TESTNET=比特幣測試網路 +BTC_TESTNET=比特幣測試網絡 # suppress inspection "UnusedProperty" BTC_REGTEST=比特幣迴歸測試 # suppress inspection "UnusedProperty" -BTC_DAO_TESTNET=比特幣 DAO 測試網路(棄用) +BTC_DAO_TESTNET=比特幣 DAO 測試網絡(棄用) # suppress inspection "UnusedProperty" -BTC_DAO_BETANET=Bisq DAO 測試網路(比特幣主要網路) +BTC_DAO_BETANET=Bisq DAO 測試網絡(比特幣主要網絡) # suppress inspection "UnusedProperty" BTC_DAO_REGTEST=比特幣 DAO 迴歸測試 @@ -2493,30 +2522,30 @@ time.seconds=秒 password.enterPassword=輸入密碼 password.confirmPassword=確認密碼 -password.tooLong=你輸入的密碼太長,不要超過 500 個字元。 -password.deriveKey=從密碼中提取金鑰 +password.tooLong=你輸入的密碼太長,不要超過 500 個字符。 +password.deriveKey=從密碼中提取密鑰 password.walletDecrypted=錢包成功解密並移除密碼保護 password.wrongPw=你輸入了錯誤的密碼。\n\n請再次嘗試輸入密碼,仔細檢查拼寫錯誤。 password.walletEncrypted=錢包成功加密並開啟密碼保護。 -password.walletEncryptionFailed=Wallet password could not be set. You may have imported seed words which do not match the wallet database. Please contact the developers on Keybase ([HYPERLINK:https://keybase.io/team/bisq]). +password.walletEncryptionFailed=無法設置錢包密碼。您可能導入了與錢包數據庫不匹配的還原密鑰。請在 Keybase 上聯繫開發者(https://keybase.io/team/bisq]) password.passwordsDoNotMatch=這2個密碼您輸入的不相同 password.forgotPassword=忘記密碼? -password.backupReminder=Please note that when setting a wallet password all automatically created backups from the unencrypted wallet will be deleted.\n\nIt is highly recommended that you make a backup of the application directory and write down your seed words before setting a password! -password.backupWasDone=I have already made a backup +password.backupReminder=請注意,設置錢包密碼時,所有未加密的錢包的自動創建的備份將被刪除。\n\n強烈建議您備份應用程序的目錄,並在設置密碼之前記下您的還原密鑰! +password.backupWasDone=我已備份 -seed.seedWords=錢包金鑰 -seed.enterSeedWords=輸入錢包金鑰 +seed.seedWords=錢包密鑰 +seed.enterSeedWords=輸入錢包密鑰 seed.date=錢包時間 -seed.restore.title=使用還原金鑰恢復錢包 +seed.restore.title=使用還原密鑰恢復錢包 seed.restore=恢復錢包 -seed.creationDate=建立時間 -seed.warn.walletNotEmpty.msg=Your Bitcoin wallet is not empty.\n\nYou must empty this wallet before attempting to restore an older one, as mixing wallets together can lead to invalidated backups.\n\nPlease finalize your trades, close all your open offers and go to the Funds section to withdraw your bitcoin.\nIn case you cannot access your bitcoin you can use the emergency tool to empty the wallet.\nTo open the emergency tool press \"Alt+e\" or \"Cmd/Ctrl+e\". +seed.creationDate=創建時間 +seed.warn.walletNotEmpty.msg=你的比特幣錢包不是空的。\n\n在嘗試恢復較舊的錢包之前,您必須清空此錢包,因為將錢包混在一起會導致無效的備份。\n\n請完成您的交易,關閉所有您的未完成報價,並轉到資金界面撤回您的比特幣。\n如果您無法訪問您的比特幣,您可以使用緊急工具清空錢包。\n要打開該應急工具,請按“alt + e”或“Cmd/Ctrl + e” 。 seed.warn.walletNotEmpty.restore=無論如何我要恢復 seed.warn.walletNotEmpty.emptyWallet=我先清空我的錢包 -seed.warn.notEncryptedAnymore=你的錢包被加密了。\n\n恢復後,錢包將不再加密,您必須設定新的密碼。\n\n你要繼續嗎? -seed.warn.walletDateEmpty=由於您尚未指定錢包日期,因此 Bisq 將必須掃描 2013.10.09(BIP39創始日期)之後的區塊鏈。\n\nBIP39 錢包於 Bisq 於 2017.06.28 首次釋出(版本 v0.5)。因此,您可以使用該日期來節省時間。\n\n理想情況下,您應指定建立錢包種子的日期。\n\n\n您確定要繼續而不指定錢包日期嗎? -seed.restore.success=新的還原金鑰成功地恢復了錢包。\n\n您需要關閉並重新啟動應用程式。 -seed.restore.error=使用還原金鑰恢復錢包時出現錯誤。{0} +seed.warn.notEncryptedAnymore=你的錢包被加密了。\n\n恢復後,錢包將不再加密,您必須設置新的密碼。\n\n你要繼續嗎? +seed.warn.walletDateEmpty=由於您尚未指定錢包日期,因此 Bisq 將必須掃描 2013.10.09(BIP39創始日期)之後的區塊鏈。\n\nBIP39 錢包於 Bisq 於 2017.06.28 首次發佈(版本 v0.5)。因此,您可以使用該日期來節省時間。\n\n理想情況下,您應指定創建錢包種子的日期。\n\n\n您確定要繼續而不指定錢包日期嗎? +seed.restore.success=新的還原密鑰成功地恢復了錢包。\n\n您需要關閉並重新啟動應用程序。 +seed.restore.error=使用還原密鑰恢復錢包時出現錯誤。{0} seed.restore.openOffers.warn=您有公開報價,如果您從種子詞恢復,則這些報價將被刪除。\n您確定要繼續嗎? @@ -2524,46 +2553,47 @@ seed.restore.openOffers.warn=您有公開報價,如果您從種子詞恢復, # Payment methods #################################################################### -payment.account=賬戶 -payment.account.no=賬戶編號 -payment.account.name=賬戶名稱 -payment.account.userName=使用者暱稱 +payment.account=賬户 +payment.account.no=賬户編號 +payment.account.name=賬户名稱 +payment.account.userName=用户暱稱 payment.account.phoneNr=電話號碼 -payment.account.owner=賬戶擁有者姓名: +payment.account.owner=賬户擁有者姓名: payment.account.fullName=全稱(名,中間名,姓) payment.account.state=州/省/地區 payment.account.city=城市 payment.bank.country=銀行所在國家或地區 -payment.account.name.email=賬戶擁有者姓名/電子郵箱 -payment.account.name.emailAndHolderId=賬戶擁有者姓名/電子郵箱 / {0} +payment.account.name.email=賬户擁有者姓名/電子郵箱 +payment.account.name.emailAndHolderId=賬户擁有者姓名/電子郵箱 / {0} payment.bank.name=銀行名稱 -payment.select.account=選擇賬戶型別 +payment.select.account=選擇賬户類型 payment.select.region=選擇地區 payment.select.country=選擇國家或地區 payment.select.bank.country=選擇銀行所在國家或地區 -payment.foreign.currency=你確定想選擇一個與此國家或地區預設幣種不同的貨幣? -payment.restore.default=不,恢復預設值 +payment.foreign.currency=你確定想選擇一個與此國家或地區默認幣種不同的貨幣? +payment.restore.default=不,恢復默認值 payment.email=電子郵箱 payment.country=國家或地區 payment.extras=額外要求 payment.email.mobile=電子郵箱或手機號碼 payment.altcoin.address=數字貨幣地址 payment.altcoin.tradeInstantCheckbox=使用數字貨幣進行即時交易( 1 小時內) -payment.altcoin.tradeInstant.popup=對於即時交易,要求交易雙方都線上,能夠在不到1小時內完成交易。\n \n如果你已經有未完成的報價以及你不能即時完成,請在資料頁面禁用這些報價。 +payment.altcoin.tradeInstant.popup=對於即時交易,要求交易雙方都在線,能夠在不到1小時內完成交易。\n \n如果你已經有未完成的報價以及你不能即時完成,請在資料頁面禁用這些報價。 payment.altcoin=數字貨幣 -payment.select.altcoin=Select or search Altcoin +payment.select.altcoin=選擇或搜索數字貨幣 payment.secret=密保問題 payment.answer=答案 payment.wallet=錢包 ID -payment.uphold.accountId=使用者名稱或電子郵箱或電話號碼 +payment.uphold.accountId=用户名或電子郵箱或電話號碼 payment.moneyBeam.accountId=電子郵箱或者電話號碼 -payment.venmo.venmoUserName=Venmo 使用者名稱: +payment.venmo.venmoUserName=Venmo 用户名: payment.popmoney.accountId=電子郵箱或者電話號碼 -payment.promptPay.promptPayId=公民身份證/稅號或電話號碼 -payment.supportedCurrencies=支援的貨幣 +payment.promptPay.promptPayId=公民身份證/税號或電話號碼 +payment.supportedCurrencies=支持的貨幣 +payment.supportedCurrenciesForReceiver=Currencies for receiving funds payment.limitations=限制條件 -payment.salt=帳戶年齡驗證鹽值 -payment.error.noHexSalt=The salt needs to be in HEX format.\nIt is only recommended to edit the salt field if you want to transfer the salt from an old account to keep your account age. The account age is verified by using the account salt and the identifying account data (e.g. IBAN). +payment.salt=帳户年齡驗證鹽值 +payment.error.noHexSalt=鹽值需要十六進制的。\n如果您想要從舊帳户轉移鹽值以保留帳齡,只建議編輯鹽值字段。帳齡通過帳户鹽值和識別帳户數據(例如 IBAN )來驗證。 payment.accept.euro=接受來自這些歐元國家的交易 payment.accept.nonEuro=接受來自這些非歐元國家的交易 payment.accepted.countries=接受的國家 @@ -2571,7 +2601,7 @@ payment.accepted.banks=接受的銀行(ID) payment.mobile=手機號碼 payment.postal.address=郵寄地址 payment.national.account.id.AR=CBU 號碼 -shared.accountSigningState=賬戶驗證狀態 +shared.accountSigningState=賬户驗證狀態 #new payment.altcoin.address.dyn={0} 地址 @@ -2584,58 +2614,59 @@ payment.maxPeriodAndLimit=最大交易時間:{0}/ 最大買入:{1}/ 最大 payment.maxPeriodAndLimitCrypto=最大交易期限:{0}/最大交易限額:{1} payment.currencyWithSymbol=貨幣:{0} payment.nameOfAcceptedBank=接受的銀行名稱 -payment.addAcceptedBank=新增接受的銀行 +payment.addAcceptedBank=添加接受的銀行 payment.clearAcceptedBanks=清除接受的銀行 payment.bank.nameOptional=銀行名稱(可選) -payment.bankCode=銀行程式碼 +payment.bankCode=銀行代碼 payment.bankId=銀行 ID (BIC/SWIFT): payment.bankIdOptional=銀行 ID(BIC/SWIFT)(可選) payment.branchNr=分行編碼 payment.branchNrOptional=分行編碼(可選) payment.accountNrLabel=賬號(IBAN) -payment.accountType=賬戶型別 +payment.accountType=賬户類型 payment.checking=檢查 -payment.savings=儲存 +payment.savings=保存 payment.personalId=個人 ID -payment.clearXchange.info=Zelle是一項轉賬服務,轉賬到其他銀行做的很好。\n\n1.檢查此頁面以檢視您的銀行是否(以及如何)與 Zelle 合作:\nhttps://www.zellepay.com/get-started\n\n2.特別注意您的轉賬限額-匯款限額因銀行而異,銀行通常分別指定每日,每週和每月的限額。\n\n3.如果您的銀行不能使用 Zelle,您仍然可以通過 Zelle 移動應用程式使用它,但是您的轉賬限額會低得多。\n\n4.您的 Bisq 帳戶上指定的名稱必須與 Zelle/銀行帳戶上的名稱匹配。 \n\n如果您無法按照貿易合同中的規定完成 Zelle 交易,則可能會損失部分(或全部)保證金。\n\n由於 Zelle 的拒付風險較高,因此建議賣家通過電子郵件或 SMS 與未簽名的買家聯絡,以確認買家確實擁有 Bisq 中指定的 Zelle 帳戶。 -payment.fasterPayments.newRequirements.info=有些銀行已經開始核實快捷支付收款人的全名。您當前的快捷支付帳戶沒有填寫全名。\n\n請考慮在 Bisq 中重新建立您的快捷支付帳戶,為將來的 {0} 買家提供一個完整的姓名。\n\n重新建立帳戶時,請確保將銀行區號、帳戶編號和帳齡驗證鹽值從舊帳戶複製到新帳戶。這將確保您現有的帳齡和簽名狀態得到保留。 -payment.moneyGram.info=When using MoneyGram the BTC buyer has to send the Authorisation number and a photo of the receipt by email to the BTC seller. The receipt must clearly show the seller's full name, country, state and the amount. The seller's email will be displayed to the buyer during the trade process. -payment.westernUnion.info=When using Western Union the BTC buyer has to send the MTCN (tracking number) and a photo of the receipt by email to the BTC seller. The receipt must clearly show the seller's full name, city, country and the amount. The seller's email will be displayed to the buyer during the trade process. -payment.halCash.info=使用 HalCash 時,BTC 買方需要通過手機簡訊向 BTC 賣方傳送 HalCash 程式碼。\n\n請確保不要超過銀行允許您用半現金匯款的最高金額。每次取款的最低金額是 10 歐元,最高金額是 10 歐元。金額是 600 歐元。對於重複取款,每天每個接收者 3000 歐元,每月每個接收者 6000 歐元。請與您的銀行核對這些限額,以確保它們使用與此處所述相同的限額。\n\n提現金額必須是 10 歐元的倍數,因為您不能從 ATM 機提取其他金額。 建立報價和下單螢幕中的 UI 將調整 BTC 金額,使 EUR 金額正確。你不能使用基於市場的價格,因為歐元的數量會隨著價格的變化而變化。\n +payment.clearXchange.info=Zelle是一項轉賬服務,轉賬到其他銀行做的很好。\n\n1.檢查此頁面以查看您的銀行是否(以及如何)與 Zelle 合作:\nhttps://www.zellepay.com/get-started\n\n2.特別注意您的轉賬限額-匯款限額因銀行而異,銀行通常分別指定每日,每週和每月的限額。\n\n3.如果您的銀行不能使用 Zelle,您仍然可以通過 Zelle 移動應用程序使用它,但是您的轉賬限額會低得多。\n\n4.您的 Bisq 帳户上指定的名稱必須與 Zelle/銀行帳户上的名稱匹配。 \n\n如果您無法按照貿易合同中的規定完成 Zelle 交易,則可能會損失部分(或全部)保證金。\n\n由於 Zelle 的拒付風險較高,因此建議賣家通過電子郵件或 SMS 與未簽名的買家聯繫,以確認買家確實擁有 Bisq 中指定的 Zelle 帳户。 +payment.fasterPayments.newRequirements.info=有些銀行已經開始核實快捷支付收款人的全名。您當前的快捷支付帳户沒有填寫全名。\n\n請考慮在 Bisq 中重新創建您的快捷支付帳户,為將來的 {0} 買家提供一個完整的姓名。\n\n重新創建帳户時,請確保將銀行區號、帳户編號和帳齡驗證鹽值從舊帳户複製到新帳户。這將確保您現有的帳齡和簽名狀態得到保留。 +payment.moneyGram.info=使用 MoneyGram 時,BTC 買方必須將授權號碼和收據的照片通過電子郵件發送給 BTC 賣方。收據必須清楚地顯示賣方的全名、國家或地區、州和金額。買方將在交易過程中顯示賣方的電子郵件。 +payment.westernUnion.info=使用 Western Union 時,BTC 買方必須通過電子郵件將 MTCN(運單號)和收據照片發送給 BTC 賣方。收據上必須清楚地顯示賣方的全名、城市、國家或地區和金額。買方將在交易過程中顯示賣方的電子郵件。 +payment.halCash.info=使用 HalCash 時,BTC 買方需要通過手機短信向 BTC 賣方發送 HalCash 代碼。\n\n請確保不要超過銀行允許您用半現金匯款的最高金額。每次取款的最低金額是 10 歐元,最高金額是 10 歐元。金額是 600 歐元。對於重複取款,每天每個接收者 3000 歐元,每月每個接收者 6000 歐元。請與您的銀行核對這些限額,以確保它們使用與此處所述相同的限額。\n\n提現金額必須是 10 歐元的倍數,因為您不能從 ATM 機提取其他金額。 創建報價和下單屏幕中的 UI 將調整 BTC 金額,使 EUR 金額正確。你不能使用基於市場的價格,因為歐元的數量會隨着價格的變化而變化。\n # suppress inspection "UnusedMessageFormatParameter" -payment.limits.info=Please be aware that all bank transfers carry a certain amount of chargeback risk. To mitigate this risk, Bisq sets per-trade limits based on the estimated level of chargeback risk for the payment method used.\n\nFor this payment method, your per-trade limit for buying and selling is {2}.\n\nThis limit only applies to the size of a single trade—you can place as many trades as you like.\n\nSee more details on the wiki [HYPERLINK:https://bisq.wiki/Account_limits]. +payment.limits.info=請注意,所有銀行轉賬都有一定的退款風險。為了降低這一風險,Bisq 基於使用的付款方式的退款風險。\n\n對於付款方式,您的每筆交易的出售和購買的限額為{2}\n\n限制只應用在單筆交易,你可以儘可能多的進行交易。\n\n在 Bisq Wiki 查看更多信息[HYPERLINK:https://bisq.wiki/Account_limits]。 # suppress inspection "UnusedProperty" -payment.limits.info.withSigning=To limit chargeback risk, Bisq sets per-trade limits for this payment account type based on the following 2 factors:\n\n1. General chargeback risk for the payment method\n2. Account signing status\n\nThis payment account is not yet signed, so it is limited to buying {0} per trade. After signing, buy limits will increase as follows:\n\n● Before signing, and for 30 days after signing, your per-trade buy limit will be {0}\n● 30 days after signing, your per-trade buy limit will be {1}\n● 60 days after signing, your per-trade buy limit will be {2}\n\nSell limits are not affected by account signing. You can sell {2} in a single trade immediately.\n\nThese limits only apply to the size of a single trade—you can place as many trades as you like. \n\nSee more details on the wiki [HYPERLINK:https://bisq.wiki/Account_limits]. +payment.limits.info.withSigning=為了降低這一風險,Bisq 基於兩個因素對該付款方式每筆交易設置了限制:\n\n1. 使用的付款方法的預估退款風險水平\n2. 您的付款方式的賬齡\n\n這個付款賬户還沒有被驗證,所以他每個交易最多購買{0}。在驗證之後,購買限制會以以下規則逐漸增加:\n\n●簽署前,以及簽署後30天內,您的每筆最大交易將限制為{0}\n●簽署後30天,每筆最大交易將限制為{1}\n●簽署後60天,每筆最大交易將限制為{2}\n\n出售限制不會被賬户驗證狀態限制,你可以理科進行單筆為{2}的交易\n\n限制只應用在單筆交易,你可以儘可能多的進行交易。\n\n在 Bisq Wiki 上查看更多:\nhttps://bisq.wiki/Account_limits -payment.cashDeposit.info=請確認您的銀行允許您將現金存款匯入他人賬戶。例如,美國銀行和富國銀行不再允許此類存款。 +payment.cashDeposit.info=請確認您的銀行允許您將現金存款匯入他人賬户。例如,美國銀行和富國銀行不再允許此類存款。 -payment.revolut.info=Revolut 要求使用“使用者名稱”作為帳戶 ID,而不是像以往的電話號碼或電子郵件。 -payment.account.revolut.addUserNameInfo={0}\nYour existing Revolut account ({1}) does not have a ''User name''.\nPlease enter your Revolut ''User name'' to update your account data.\nThis will not affect your account age signing status. -payment.revolut.addUserNameInfo.headLine=更新 Revolut 賬戶 +payment.revolut.info=Revolut 要求使用“用户名”作為帳户 ID,而不是像以往的電話號碼或電子郵件。 +payment.account.revolut.addUserNameInfo={0}\n您現有的 Revolut 帳户({1})尚未設置“用户名”。\n請輸入您的 Revolut ``用户名''以更新您的帳户數據。\n這不會影響您的賬齡驗證狀態。 +payment.revolut.addUserNameInfo.headLine=更新 Revolut 賬户 -payment.usPostalMoneyOrder.info=在 Bisq 上交易 US Postal Money Orders (USPMO)您必須理解下述條款:\n\n- BTC 買方必須在傳送方和收款人欄位中都寫上 BTC 賣方的名稱,並在傳送之前對 USPMO 和信封進行高解析度照片拍照,並帶有跟蹤證明。\n- BTC 買方必須將 USPMO 連同交貨確認書一起傳送給 BTC 賣方。\n\n如果需要調解,或有交易糾紛,您將需要將照片連同 USPMO 編號,郵局編號和交易金額一起傳送給 Bisq 調解員或退款代理,以便他們進行驗證美國郵局網站上的詳細資訊。\n\n如未能提供要求的交易資料將在糾紛中直接判負\n\n在所有爭議案件中,USPMO 傳送方在向調解人或仲裁員提供證據/證明時承擔 100% 的責任。\n\n如果您不理解這些要求,請不要在 Bisq 上使用 USPMO 進行交易。 +payment.usPostalMoneyOrder.info=在 Bisq 上交易 US Postal Money Orders (USPMO)您必須理解下述條款:\n\n- BTC 買方必須在發送方和收款人字段中都寫上 BTC 賣方的名稱,並在發送之前對 USPMO 和信封進行高分辨率照片拍照,並帶有跟蹤證明。\n- BTC 買方必須將 USPMO 連同交貨確認書一起發送給 BTC 賣方。\n\n如果需要調解,或有交易糾紛,您將需要將照片連同 USPMO 編號,郵局編號和交易金額一起發送給 Bisq 調解員或退款代理,以便他們進行驗證美國郵局網站上的詳細信息。\n\n如未能提供要求的交易數據將在糾紛中直接判負\n\n在所有爭議案件中,USPMO 發送方在向調解人或仲裁員提供證據/證明時承擔 100% 的責任。\n\n如果您不理解這些要求,請不要在 Bisq 上使用 USPMO 進行交易。 -payment.f2f.contact=聯絡方式 -payment.f2f.contact.prompt=How would you like to be contacted by the trading peer? (email address, phone number,...) +payment.f2f.contact=聯繫方式 +payment.f2f.contact.prompt=您希望如何與交易夥伴聯繫?(電子郵箱、電話號碼、…) payment.f2f.city=“面對面”會議的城市 payment.f2f.city.prompt=城市將與報價一同顯示 -payment.f2f.optionalExtra=可選的附加資訊 -payment.f2f.extra=附加資訊 +payment.f2f.optionalExtra=可選的附加信息 +payment.f2f.extra=附加信息 -payment.f2f.extra.prompt=交易方可以定義“條款和條件”或新增公共聯絡資訊。它將與報價一同顯示。 -payment.f2f.info='Face to Face' trades have different rules and come with different risks than online transactions.\n\nThe main differences are:\n● The trading peers need to exchange information about the meeting location and time by using their provided contact details.\n● The trading peers need to bring their laptops and do the confirmation of 'payment sent' and 'payment received' at the meeting place.\n● If a maker has special 'terms and conditions' they must state those in the 'Additional information' text field in the account.\n● By taking an offer the taker agrees to the maker's stated 'terms and conditions'.\n● In case of a dispute the mediator or arbitrator cannot be of much assistance as it is usually difficult to get tamper-proof evidence of what happened at the meeting. In such cases the BTC funds might get locked indefinitely or until the trading peers come to an agreement.\n\nTo be sure you fully understand the differences with 'Face to Face' trades please read the instructions and recommendations at: [HYPERLINK:https://docs.bisq.network/trading-rules.html#f2f-trading] -payment.f2f.info.openURL=開啟網頁 +payment.f2f.extra.prompt=交易方可以定義“條款和條件”或添加公共聯繫信息。它將與報價一同顯示。 +payment.f2f.info=與網上交易相比,“面對面”交易有不同的規則,也有不同的風險。\n\n主要區別是:\n●交易夥伴需要使用他們提供的聯繫方式交換關於會面地點和時間的信息。\n●交易雙方需要攜帶筆記本電腦,在會面地點確認“已發送付款”和“已收到付款”。\n●如果交易方有特殊的“條款和條件”,他們必須在賬户的“附加信息”文本框中聲明這些條款和條件。\n●在發生爭議時,調解員或仲裁員不能提供太多幫助,因為通常很難獲得有關會面上所發生情況的篡改證據。在這種情況下,BTC 資金可能會被無限期鎖定,或者直到交易雙方達成協議。\n\n為確保您完全理解“面對面”交易的不同之處,請閲讀以下説明和建議:“https://docs.bisq.network/trading-rules.html#f2f-trading” +payment.f2f.info.openURL=打開網頁 payment.f2f.offerbook.tooltip.countryAndCity=國家或地區及城市:{0} / {1} -payment.f2f.offerbook.tooltip.extra=附加資訊:{0} +payment.f2f.offerbook.tooltip.extra=附加信息:{0} payment.japan.bank=銀行 payment.japan.branch=分行 -payment.japan.account=賬戶 +payment.japan.account=賬户 payment.japan.recipient=名稱 payment.australia.payid=PayID -payment.payid=PayID linked to financial institution. Like email address or mobile phone. -payment.payid.info=A PayID like a phone number, email address or an Australian Business Number (ABN), that you can securely link to your bank, credit union or building society account. You need to have already created a PayID with your Australian financial institution. Both sending and receiving financial institutions must support PayID. For more information please check [HYPERLINK:https://payid.com.au/faqs/] -payment.amazonGiftCard.info=To pay with Amazon eGift Card you need to purchase an Amazon eGift Card at your Amazon account and use the BTC seller''s email or mobile nr. as receiver. Amazon sends then an email or text message to the receiver. Use the trade ID for the message field.\n\nAmazon eGift Cards can only be redeemed by Amazon accounts with the same currency.\n\nFor more information visit the Amazon eGift Card webpage. [HYPERLINK:https://www.amazon.com/Amazon-1_US_Email-eGift-Card/dp/B004LLIKVU] +payment.payid=PayID 需鏈接至金融機構。例如電子郵件地址或手機。 +payment.payid.info=PayID,如電話號碼、電子郵件地址或澳大利亞商業號碼(ABN),您可以安全地連接到您的銀行、信用合作社或建立社會帳户。你需要在你的澳大利亞金融機構創建一個 PayID。發送和接收金融機構都必須支持 PayID。更多信息請查看[HYPERLINK:https://payid.com.au/faqs/] +payment.amazonGiftCard.info=To pay with Amazon eGift Card, you will need to send an Amazon eGift Card to the BTC seller via your Amazon account. \n\nBisq will show the BTC seller''s email address or phone number where the gift card should be sent, and you must include the trade ID in the gift card''s message field. Please see the wiki [HYPERLINK:https://bisq.wiki/Amazon_eGift_card] for further details and best practices. \n\nThree important notes:\n- try to send gift cards with amounts of 100 USD or smaller, as Amazon is known to flag larger gift cards as fraudulent\n- try to use creative, believable text for the gift card''s message (e.g., "Happy birthday Susan!") along with the trade ID (and use trader chat to tell your trading peer the reference text you picked so they can verify your payment)\n- Amazon eGift Cards can only be redeemed on the Amazon website they were purchased on (e.g., a gift card purchased on amazon.it can only be redeemed on amazon.it) + # We use constants from the code so we do not use our normal naming convention # dynamic values are not recognized by IntelliJ @@ -2650,7 +2681,7 @@ MONEY_GRAM=MoneyGram WESTERN_UNION=西聯匯款 F2F=面對面(當面交易) JAPAN_BANK=日本銀行匯款 -AUSTRALIA_PAYID=Australian PayID +AUSTRALIA_PAYID=澳大利亞 PayID # suppress inspection "UnusedProperty" NATIONAL_BANK_SHORT=國內銀行 @@ -2671,7 +2702,7 @@ F2F_SHORT=F2F # suppress inspection "UnusedProperty" JAPAN_BANK_SHORT=Japan Furikomi # suppress inspection "UnusedProperty" -AUSTRALIA_PAYID_SHORT=PayID +AUSTRALIA_PAYID_SHORT=支付 ID # Do not translate brand names # suppress inspection "UnusedProperty" @@ -2713,7 +2744,7 @@ ADVANCED_CASH=Advanced Cash # suppress inspection "UnusedProperty" TRANSFERWISE=TransferWise # suppress inspection "UnusedProperty" -AMAZON_GIFT_CARD=Amazon eGift Card +AMAZON_GIFT_CARD=亞馬遜電子禮品卡 # suppress inspection "UnusedProperty" BLOCK_CHAINS_INSTANT=Altcoins Instant @@ -2765,7 +2796,7 @@ ADVANCED_CASH_SHORT=Advanced Cash # suppress inspection "UnusedProperty" TRANSFERWISE_SHORT=TransferWise # suppress inspection "UnusedProperty" -AMAZON_GIFT_CARD_SHORT=Amazon eGift Card +AMAZON_GIFT_CARD_SHORT=亞馬遜電子禮品卡 # suppress inspection "UnusedProperty" BLOCK_CHAINS_INSTANT_SHORT=Altcoins Instant @@ -2789,16 +2820,16 @@ validation.zero=不允許輸入0。 validation.negative=不允許輸入負值。 validation.fiat.toSmall=不允許輸入比最小可能值還小的數值。 validation.fiat.toLarge=不允許輸入比最大可能值還大的數值。 -validation.btc.fraction=Input will result in a bitcoin value of less than 1 satoshi +validation.btc.fraction=此充值將會產生小於 1 聰的比特幣數量。 validation.btc.toLarge=不允許充值大於{0} validation.btc.toSmall=不允許充值小於{0} -validation.passwordTooShort=The password you entered is too short. It needs to have a min. of 8 characters. -validation.passwordTooLong=你輸入的密碼太長。最長不要超過50個字元。 +validation.passwordTooShort=你輸入的密碼太短。最少 8 個字符。 +validation.passwordTooLong=你輸入的密碼太長。最長不要超過50個字符。 validation.sortCodeNumber={0} 必須由 {1} 個數字構成。 -validation.sortCodeChars={0} 必須由 {1} 個字元構成。 +validation.sortCodeChars={0} 必須由 {1} 個字符構成。 validation.bankIdNumber={0} 必須由 {1} 個數字構成。 validation.accountNr=賬號必須由 {0} 個數字構成。 -validation.accountNrChars=賬戶必須由 {0} 個字元構成。 +validation.accountNrChars=賬户必須由 {0} 個字符構成。 validation.btc.invalidAddress=地址不正確,請檢查地址格式。 validation.integerOnly=請輸入整數。 validation.inputError=您的輸入引起了錯誤:\n{0} @@ -2813,46 +2844,46 @@ validation.accountNrFormat=帳號必須是格式:{0} # suppress inspection "UnusedProperty" validation.altcoin.wrongStructure=地址驗證失敗,因為它與 {0} 地址的結構不匹配。 # suppress inspection "UnusedProperty" -validation.altcoin.ltz.zAddressesNotSupported=LTZ address must start with L. Addresses starting with z are not supported. +validation.altcoin.ltz.zAddressesNotSupported=LTZ 地址需要以 L 開頭。 不支持以 Z 開頭的地址。 # suppress inspection "UnusedProperty" -validation.altcoin.zAddressesNotSupported=ZEC addresses must start with t. Addresses starting with z are not supported. +validation.altcoin.zAddressesNotSupported=LTZ 地址需要以 L 開頭。 不支持以 Z 開頭的地址。 # suppress inspection "UnusedProperty" validation.altcoin.invalidAddress=這個地址不是有效的{0}地址!{1} # suppress inspection "UnusedProperty" -validation.altcoin.liquidBitcoin.invalidAddress=不支援本地 segwit 地址(以“lq”開頭的地址)。 -validation.bic.invalidLength=Input length must be 8 or 11 -validation.bic.letters=必須輸入銀行和國家或地區程式碼 -validation.bic.invalidLocationCode=BIC 包含無效的地址程式碼 -validation.bic.invalidBranchCode=BIC 包含無效的分行程式碼 -validation.bic.sepaRevolutBic=不支援 Revolut Sepa 賬戶 -validation.btc.invalidFormat=Invalid format for a Bitcoin address. -validation.bsq.invalidFormat=Invalid format for a BSQ address. +validation.altcoin.liquidBitcoin.invalidAddress=不支持本地 segwit 地址(以“lq”開頭的地址)。 +validation.bic.invalidLength=輸入長度既不是 8 也不是 11 +validation.bic.letters=必須輸入銀行和國家或地區代碼 +validation.bic.invalidLocationCode=BIC 包含無效的地址代碼 +validation.bic.invalidBranchCode=BIC 包含無效的分行代碼 +validation.bic.sepaRevolutBic=不支持 Revolut Sepa 賬户 +validation.btc.invalidFormat=無效格式的比特幣地址 +validation.bsq.invalidFormat=無效格式的 BSQ 地址 validation.email.invalidAddress=無效地址 -validation.iban.invalidCountryCode=國家或地區程式碼無效 +validation.iban.invalidCountryCode=國家或地區代碼無效 validation.iban.checkSumNotNumeric=校驗必須是數字 -validation.iban.nonNumericChars=檢測到非字母數字字元 +validation.iban.nonNumericChars=檢測到非字母數字字符 validation.iban.checkSumInvalid=IBAN 校驗無效 -validation.iban.invalidLength=Number must have a length of 15 to 34 chars. +validation.iban.invalidLength=數字的長度必須為15到34個字符。 validation.interacETransfer.invalidAreaCode=非加拿大區號 -validation.interacETransfer.invalidPhone=Please enter a valid 11 digit phone number (ex: 1-123-456-7890) or an email address +validation.interacETransfer.invalidPhone=請輸入可用的 11 為電話號碼(例如 1-123-456-7890)或郵箱地址 validation.interacETransfer.invalidQuestion=必須只包含字母、數字、空格和/或符號“_ , . ? -” validation.interacETransfer.invalidAnswer=必須是一個單詞,只包含字母、數字和/或符號- validation.inputTooLarge=輸入不能大於 {0} validation.inputTooSmall=輸入必須大於 {0} validation.inputToBeAtLeast=輸入必須至少為 {0} -validation.amountBelowDust=An amount below the dust limit of {0} satoshi is not allowed. +validation.amountBelowDust=不允許低於 {0} 聰的零頭限制。 validation.length=長度必須在 {0} 和 {1} 之間 validation.pattern=輸入格式必須為:{0} -validation.noHexString=輸入不是十六進位制格式。 +validation.noHexString=輸入不是十六進制格式。 validation.advancedCash.invalidFormat=必須是有效的電子郵箱或錢包 ID 的格式為:X000000000000 -validation.invalidUrl=輸入的不是有效 URL 連結。 +validation.invalidUrl=輸入的不是有效 URL 鏈接。 validation.mustBeDifferent=您輸入的值必須與當前值不同 -validation.cannotBeChanged=引數不能更改 +validation.cannotBeChanged=參數不能更改 validation.numberFormatException=數字格式異常 {0} validation.mustNotBeNegative=不能輸入負值 -validation.phone.missingCountryCode=需要兩個字母的國家或地區程式碼來驗證電話號碼 -validation.phone.invalidCharacters=電話號碼 {0} 包含無效字元 -validation.phone.insufficientDigits=There are not enough digits in {0} to be a valid phone number -validation.phone.tooManyDigits=There are too many digits in {0} to be a valid phone number -validation.phone.invalidDialingCode=Country dialing code for number {0} is invalid for country {1}. The correct dialing code is {2}. +validation.phone.missingCountryCode=需要兩個字母的國家或地區代碼來驗證電話號碼 +validation.phone.invalidCharacters=電話號碼 {0} 包含無效字符 +validation.phone.insufficientDigits={0} 中沒有足夠的數字作為有效的電話號碼 +validation.phone.tooManyDigits={0} 中的數字太多,不是有效的電話號碼 +validation.phone.invalidDialingCode=數字 {0} 中的國際撥號代碼對於 {1} 無效。正確的撥號號碼是 {2} 。 validation.invalidAddressList=使用逗號分隔有效地址列表 diff --git a/core/src/main/resources/wallet/checkpoints.txt b/core/src/main/resources/wallet/checkpoints.txt index 8e22a7f75a..51a1adad07 100644 --- a/core/src/main/resources/wallet/checkpoints.txt +++ b/core/src/main/resources/wallet/checkpoints.txt @@ -1,6 +1,6 @@ TXT CHECKPOINTS 1 0 -325 +327 AAAAAAAAB+EH4QfhAAAH4AEAAABjl7tqvU/FIcDT9gcbVlA4nwtFUbxAtOawZzBpAAAAAKzkcK7NqciBjI/ldojNKncrWleVSgDfBCCn3VRrbSxXaw5/Sf//AB0z8Bkv AAAAAAAAD8EPwQ/BAAAPwAEAAADfP83Sx8MZ9RsrnZCvqzAwqB2Ma+ZesNAJrTfwAAAAACwESaNKhvRgz6WuE7UFdFk1xwzfRY/OIdIOPzX5yaAdjnWUSf//AB0GrNq5 AAAAAAAAF6EXoRehAAAXoAEAAADonWzAaUAKd30XT3NnHKobZMnLOuHdzm/xtehsAAAAAD8cUJA6NBIHHcqPHLc4IrfHw+6mjCGu3e+wRO81EvpnMVqrSf//AB1ffy8G @@ -326,3 +326,5 @@ E7TgpleovIarz4zNAAnnwADg/zelTTDUGas2KxqgEH2WV5EilGEY8VASBgAAAAAAAAAAAJVJFZNI4Kxh FD83ZUplM/sW8MloAAnvoAAAQCBUTUlenrKovQvyeNaLUYJBmxfT5hcuDQAAAAAAAAAAAIaxf5jfjr8MifLPauOJeh6OWDYxSUUPluG5E8hVh+rrWD95X96VDhf7Be0Q FMlwaWsoL8M1y3sGAAn3gAAAICD2It4VF1dZC7XR51SjkuBPy2c1ot7iBQAAAAAAAAAAAOto2NUucHczD9ZpnC5X1L05HcifvGpMh8gwIt7mZ2DW3BWLX04TDhdKX1k6 FVin/nTPxZEaUhFJAAn/YADg/zdLnpRRoj5nb9aeuWAA1TG1ZV/ig3PhBQAAAAAAAAAAAP7jjrVesvd94nsFrp03Zj496k0mgpUa+z2F/FaP1R7omhShXzPEEBcdNBS1 +FdDmSXs4LVrTs1CaAAoHQAAAACDvuQVfiWazEOmUBkUubcV9HD6bQ4YDCQAAAAAAAAAAAIpAWQyuvdv0i6cfyxgL/cqONcYtUdP6eDTQOlOgmOc5h7CyX93+DxdiV5Q4 +Fk7wqQvRa3I8HIU0AAoPIAAAACClMk0cUuhV+1lsN2AW0bLOzyOjOxhvBAAAAAAAAAAAAHvW0itHeUSYGKmni03ZQ4CQz/twR/T8aM+iCLhkzgVuGaXDX1axDheZrIxe diff --git a/core/src/test/java/bisq/core/account/witness/AccountAgeWitnessServiceTest.java b/core/src/test/java/bisq/core/account/witness/AccountAgeWitnessServiceTest.java index 946e4db64d..9782e37ce1 100644 --- a/core/src/test/java/bisq/core/account/witness/AccountAgeWitnessServiceTest.java +++ b/core/src/test/java/bisq/core/account/witness/AccountAgeWitnessServiceTest.java @@ -109,7 +109,7 @@ public class AccountAgeWitnessServiceTest { AppendOnlyDataStoreService appendOnlyDataStoreService = mock(AppendOnlyDataStoreService.class); filterManager = mock(FilterManager.class); signedWitnessService = new SignedWitnessService(keyRing, p2pService, arbitratorManager, null, appendOnlyDataStoreService, null, filterManager); - service = new AccountAgeWitnessService(null, null, null, signedWitnessService, chargeBackRisk, null, dataStoreService, filterManager); + service = new AccountAgeWitnessService(null, null, null, signedWitnessService, chargeBackRisk, null, dataStoreService, null, filterManager); } private File makeDir(String name) throws IOException { diff --git a/core/src/test/java/bisq/core/offer/OpenOfferManagerTest.java b/core/src/test/java/bisq/core/offer/OpenOfferManagerTest.java index 0fcf60daa4..5cc984687a 100644 --- a/core/src/test/java/bisq/core/offer/OpenOfferManagerTest.java +++ b/core/src/test/java/bisq/core/offer/OpenOfferManagerTest.java @@ -49,7 +49,7 @@ public class OpenOfferManagerTest { final OpenOfferManager manager = new OpenOfferManager(null, null, null, p2PService, null, null, null, offerBookService, null, null, null, - null, null, null, null, null, null, + null, null, null, null, null, null, null, persistenceManager); AtomicBoolean startEditOfferSuccessful = new AtomicBoolean(false); @@ -81,7 +81,7 @@ public class OpenOfferManagerTest { final OpenOfferManager manager = new OpenOfferManager(null, null, null, p2PService, null, null, null, offerBookService, null, null, null, - null, null, null, null, null, null, + null, null, null, null, null, null, null, persistenceManager); AtomicBoolean startEditOfferSuccessful = new AtomicBoolean(false); @@ -106,7 +106,7 @@ public class OpenOfferManagerTest { final OpenOfferManager manager = new OpenOfferManager(null, null, null, p2PService, null, null, null, offerBookService, null, null, null, - null, null, null, null, null, null, + null, null, null, null, null, null, null, persistenceManager); AtomicBoolean startEditOfferSuccessful = new AtomicBoolean(false); diff --git a/core/src/test/java/bisq/core/user/UserPayloadModelVOTest.java b/core/src/test/java/bisq/core/user/UserPayloadModelVOTest.java index 144e299181..bc18d6e2c4 100644 --- a/core/src/test/java/bisq/core/user/UserPayloadModelVOTest.java +++ b/core/src/test/java/bisq/core/user/UserPayloadModelVOTest.java @@ -25,6 +25,8 @@ import bisq.core.proto.CoreProtoResolver; import com.google.common.collect.Lists; +import java.util.HashSet; + import org.junit.Ignore; public class UserPayloadModelVOTest { @@ -64,7 +66,9 @@ public class UserPayloadModelVOTest { null, null, false, - Lists.newArrayList())); + Lists.newArrayList(), + new HashSet<>(), + false)); vo.setRegisteredArbitrator(ArbitratorTest.getArbitratorMock()); vo.setRegisteredMediator(MediatorTest.getMediatorMock()); diff --git a/core/src/test/java/bisq/core/util/FeeReceiverSelectorTest.java b/core/src/test/java/bisq/core/util/FeeReceiverSelectorTest.java index ca7b77bcff..731dcfb6cc 100644 --- a/core/src/test/java/bisq/core/util/FeeReceiverSelectorTest.java +++ b/core/src/test/java/bisq/core/util/FeeReceiverSelectorTest.java @@ -26,6 +26,7 @@ import com.google.common.collect.Lists; import com.google.common.primitives.Longs; import java.util.HashMap; +import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Random; @@ -123,6 +124,8 @@ public class FeeReceiverSelectorTest { null, null, false, - Lists.newArrayList()); + Lists.newArrayList(), + new HashSet<>(), + false); } } diff --git a/daemon/src/main/java/bisq/daemon/grpc/GrpcOffersService.java b/daemon/src/main/java/bisq/daemon/grpc/GrpcOffersService.java index 9b6690864f..e92d05863f 100644 --- a/daemon/src/main/java/bisq/daemon/grpc/GrpcOffersService.java +++ b/daemon/src/main/java/bisq/daemon/grpc/GrpcOffersService.java @@ -25,6 +25,10 @@ import bisq.proto.grpc.CancelOfferReply; import bisq.proto.grpc.CancelOfferRequest; import bisq.proto.grpc.CreateOfferReply; import bisq.proto.grpc.CreateOfferRequest; +import bisq.proto.grpc.GetMyOfferReply; +import bisq.proto.grpc.GetMyOfferRequest; +import bisq.proto.grpc.GetMyOffersReply; +import bisq.proto.grpc.GetMyOffersRequest; import bisq.proto.grpc.GetOfferReply; import bisq.proto.grpc.GetOfferRequest; import bisq.proto.grpc.GetOffersReply; @@ -69,6 +73,21 @@ class GrpcOffersService extends OffersGrpc.OffersImplBase { } } + @Override + public void getMyOffer(GetMyOfferRequest req, + StreamObserver responseObserver) { + try { + Offer offer = coreApi.getMyOffer(req.getId()); + var reply = GetMyOfferReply.newBuilder() + .setOffer(toOfferInfo(offer).toProtoMessage()) + .build(); + responseObserver.onNext(reply); + responseObserver.onCompleted(); + } catch (Throwable cause) { + exceptionHandler.handleException(cause, responseObserver); + } + } + @Override public void getOffers(GetOffersRequest req, StreamObserver responseObserver) { @@ -88,6 +107,25 @@ class GrpcOffersService extends OffersGrpc.OffersImplBase { } } + @Override + public void getMyOffers(GetMyOffersRequest req, + StreamObserver responseObserver) { + try { + List result = coreApi.getMyOffers(req.getDirection(), req.getCurrencyCode()) + .stream().map(OfferInfo::toOfferInfo) + .collect(Collectors.toList()); + var reply = GetMyOffersReply.newBuilder() + .addAllOffers(result.stream() + .map(OfferInfo::toProtoMessage) + .collect(Collectors.toList())) + .build(); + responseObserver.onNext(reply); + responseObserver.onCompleted(); + } catch (Throwable cause) { + exceptionHandler.handleException(cause, responseObserver); + } + } + @Override public void createOffer(CreateOfferRequest req, StreamObserver responseObserver) { diff --git a/desktop/package/linux/Dockerfile b/desktop/package/linux/Dockerfile index 52b22011cb..214fa7ff22 100644 --- a/desktop/package/linux/Dockerfile +++ b/desktop/package/linux/Dockerfile @@ -8,7 +8,7 @@ # pull base image FROM openjdk:8-jdk -ENV version 1.5.1-SNAPSHOT +ENV version 1.5.4-SNAPSHOT RUN apt-get update && apt-get install -y --no-install-recommends openjfx && rm -rf /var/lib/apt/lists/* && apt-get install -y vim fakeroot diff --git a/desktop/package/linux/package.sh b/desktop/package/linux/package.sh index 5f6641aade..5064b086c8 100755 --- a/desktop/package/linux/package.sh +++ b/desktop/package/linux/package.sh @@ -6,7 +6,7 @@ # - Update version below # - Ensure JAVA_HOME below is pointing to OracleJDK 10 directory -version=1.5.1-SNAPSHOT +version=1.5.4-SNAPSHOT version_base=$(echo $version | awk -F'[_-]' '{print $1}') if [ ! -f "$JAVA_HOME/bin/javapackager" ]; then if [ -d "/usr/lib/jvm/jdk-10.0.2" ]; then diff --git a/desktop/package/linux/release.sh b/desktop/package/linux/release.sh index 2f00bab04c..9ebfbc603b 100755 --- a/desktop/package/linux/release.sh +++ b/desktop/package/linux/release.sh @@ -4,7 +4,7 @@ # Prior to running this script: # - Update version below -version=1.5.1-SNAPSHOT +version=1.5.4-SNAPSHOT base_dir=$( cd "$(dirname "$0")" ; pwd -P )/../../.. package_dir=$base_dir/desktop/package release_dir=$base_dir/desktop/release/$version diff --git a/desktop/package/macosx/Info.plist b/desktop/package/macosx/Info.plist index 0aebad9532..81ce46bd1b 100644 --- a/desktop/package/macosx/Info.plist +++ b/desktop/package/macosx/Info.plist @@ -5,10 +5,10 @@ CFBundleVersion - 1.5.1 + 1.5.4 CFBundleShortVersionString - 1.5.1 + 1.5.4 CFBundleExecutable Bisq diff --git a/desktop/package/macosx/copy_dbs.sh b/desktop/package/macosx/copy_dbs.sh index 520841cd2f..6da5e4def4 100755 --- a/desktop/package/macosx/copy_dbs.sh +++ b/desktop/package/macosx/copy_dbs.sh @@ -2,7 +2,7 @@ cd $(dirname $0)/../../../ -version="1.5.0" +version="1.5.2" # Set BISQ_DIR as environment var to the path of your locally synced Bisq data directory e.g. BISQ_DIR=~/Library/Application\ Support/Bisq diff --git a/desktop/package/macosx/create_app.sh b/desktop/package/macosx/create_app.sh index 57c712a106..faf91d43ac 100755 --- a/desktop/package/macosx/create_app.sh +++ b/desktop/package/macosx/create_app.sh @@ -6,7 +6,7 @@ mkdir -p deploy set -e -version="1.5.1-SNAPSHOT" +version="1.5.4-SNAPSHOT" cd .. ./gradlew :desktop:build -x test shadowJar diff --git a/desktop/package/macosx/finalize.sh b/desktop/package/macosx/finalize.sh index fa3a8a7544..0655fa3cad 100755 --- a/desktop/package/macosx/finalize.sh +++ b/desktop/package/macosx/finalize.sh @@ -2,7 +2,7 @@ cd ../../ -version="1.5.1-SNAPSHOT" +version="1.5.4-SNAPSHOT" target_dir="releases/$version" diff --git a/desktop/package/macosx/insert_snapshot_version.sh b/desktop/package/macosx/insert_snapshot_version.sh index b034b42f77..836f8c0993 100755 --- a/desktop/package/macosx/insert_snapshot_version.sh +++ b/desktop/package/macosx/insert_snapshot_version.sh @@ -2,7 +2,7 @@ cd $(dirname $0)/../../../ -version=1.5.1 +version=1.5.4 find . -type f \( -name "finalize.sh" \ -o -name "create_app.sh" \ diff --git a/desktop/package/macosx/replace_version_number.sh b/desktop/package/macosx/replace_version_number.sh index be7cca70d7..00472218bb 100755 --- a/desktop/package/macosx/replace_version_number.sh +++ b/desktop/package/macosx/replace_version_number.sh @@ -1,9 +1,9 @@ #!/bin/bash -cd $(dirname $0)/../../../ +cd $(dirname $0)/../../../. -oldVersion=1.5.0 -newVersion=1.5.1 +oldVersion=1.5.3 +newVersion=1.5.4 find . -type f \( -name "finalize.sh" \ -o -name "create_app.sh" \ diff --git a/desktop/package/windows/package.bat b/desktop/package/windows/package.bat index 8d0af674d8..8853525df2 100644 --- a/desktop/package/windows/package.bat +++ b/desktop/package/windows/package.bat @@ -11,7 +11,7 @@ @echo off -set version=1.5.1-SNAPSHOT +set version=1.5.4-SNAPSHOT if not exist "%JAVA_HOME%\bin\javapackager.exe" ( if not exist "%ProgramFiles%\Java\jdk-10.0.2" ( echo Javapackager not found. Update JAVA_HOME variable to point to OracleJDK. diff --git a/desktop/package/windows/release.bat b/desktop/package/windows/release.bat index f79d4184fd..b12aa702db 100644 --- a/desktop/package/windows/release.bat +++ b/desktop/package/windows/release.bat @@ -6,7 +6,7 @@ @echo off -set version=1.5.1-SNAPSHOT +set version=1.5.4-SNAPSHOT set release_dir=%~dp0..\..\..\releases\%version% set package_dir=%~dp0.. diff --git a/desktop/src/main/java/bisq/desktop/app/BisqApp.java b/desktop/src/main/java/bisq/desktop/app/BisqApp.java index 8c1410a61b..31419d525a 100644 --- a/desktop/src/main/java/bisq/desktop/app/BisqApp.java +++ b/desktop/src/main/java/bisq/desktop/app/BisqApp.java @@ -38,7 +38,10 @@ import bisq.core.dao.governance.voteresult.MissingDataRequestService; import bisq.core.locale.Res; import bisq.core.offer.OpenOffer; import bisq.core.offer.OpenOfferManager; +import bisq.core.user.Cookie; +import bisq.core.user.CookieKey; import bisq.core.user.Preferences; +import bisq.core.user.User; import bisq.common.app.DevEnv; import bisq.common.app.Log; @@ -67,6 +70,7 @@ import javafx.scene.input.KeyEvent; import javafx.scene.layout.StackPane; import javafx.geometry.Rectangle2D; +import javafx.geometry.BoundingBox; import java.util.ArrayList; import java.util.List; @@ -102,6 +106,7 @@ public class BisqApp extends Application implements UncaughtExceptionHandler { private boolean popupOpened; private Scene scene; private boolean shutDownRequested; + private MainView mainView; public BisqApp() { shutDownHandler = this::stop; @@ -126,7 +131,7 @@ public class BisqApp extends Application implements UncaughtExceptionHandler { public void startApplication(Runnable onApplicationStartedHandler) { try { - MainView mainView = loadMainView(injector); + mainView = loadMainView(injector); mainView.setOnApplicationStartedHandler(onApplicationStartedHandler); scene = createAndConfigScene(mainView, injector); setupStage(scene); @@ -254,10 +259,47 @@ public class BisqApp extends Application implements UncaughtExceptionHandler { stage.setMinHeight(MIN_WINDOW_HEIGHT); stage.getIcons().add(ImageUtil.getApplicationIconImage()); + User user = injector.getInstance(User.class); + layoutStageFromPersistedData(stage, user); + addStageLayoutListeners(stage, user); + // make the UI visible stage.show(); } + private void layoutStageFromPersistedData(Stage stage, User user) { + Cookie cookie = user.getCookie(); + cookie.getAsOptionalDouble(CookieKey.STAGE_X).flatMap(x -> + cookie.getAsOptionalDouble(CookieKey.STAGE_Y).flatMap(y -> + cookie.getAsOptionalDouble(CookieKey.STAGE_W).flatMap(w -> + cookie.getAsOptionalDouble(CookieKey.STAGE_H).map(h -> new BoundingBox(x, y, w, h))))) + .ifPresent(stageBoundingBox -> { + stage.setX(stageBoundingBox.getMinX()); + stage.setY(stageBoundingBox.getMinY()); + stage.setWidth(stageBoundingBox.getWidth()); + stage.setHeight(stageBoundingBox.getHeight()); + }); + } + + private void addStageLayoutListeners(Stage stage, User user) { + stage.widthProperty().addListener((observable, oldValue, newValue) -> { + user.getCookie().putAsDouble(CookieKey.STAGE_W, (double) newValue); + user.requestPersistence(); + }); + stage.heightProperty().addListener((observable, oldValue, newValue) -> { + user.getCookie().putAsDouble(CookieKey.STAGE_H, (double) newValue); + user.requestPersistence(); + }); + stage.xProperty().addListener((observable, oldValue, newValue) -> { + user.getCookie().putAsDouble(CookieKey.STAGE_X, (double) newValue); + user.requestPersistence(); + }); + stage.yProperty().addListener((observable, oldValue, newValue) -> { + user.getCookie().putAsDouble(CookieKey.STAGE_Y, (double) newValue); + user.requestPersistence(); + }); + } + private MainView loadMainView(Injector injector) { CachingViewLoader viewLoader = injector.getInstance(CachingViewLoader.class); return (MainView) viewLoader.load(MainView.class); diff --git a/desktop/src/main/java/bisq/desktop/common/fxml/FxmlViewLoader.java b/desktop/src/main/java/bisq/desktop/common/fxml/FxmlViewLoader.java index 9e88dfb99e..95135a0561 100644 --- a/desktop/src/main/java/bisq/desktop/common/fxml/FxmlViewLoader.java +++ b/desktop/src/main/java/bisq/desktop/common/fxml/FxmlViewLoader.java @@ -23,9 +23,13 @@ import bisq.desktop.common.view.View; import bisq.desktop.common.view.ViewFactory; import bisq.desktop.common.view.ViewLoader; +import bisq.common.util.Utilities; + import javax.inject.Inject; import javax.inject.Singleton; +import com.google.common.base.Joiner; + import javafx.fxml.FXMLLoader; import java.net.URL; @@ -36,8 +40,11 @@ import java.util.ResourceBundle; import java.lang.annotation.Annotation; +import lombok.extern.slf4j.Slf4j; + import static com.google.common.base.Preconditions.checkNotNull; +@Slf4j @Singleton public class FxmlViewLoader implements ViewLoader { @@ -107,7 +114,17 @@ public class FxmlViewLoader implements ViewLoader { "does not implement [%s] as expected.", controller.getClass(), fxmlUrl, View.class); return (View) controller; } catch (IOException ex) { - throw new ViewfxException(ex, "Failed to load view from FXML file at [%s]", fxmlUrl); + Throwable cause = ex.getCause(); + if (cause != null) { + cause.printStackTrace(); + log.error(cause.toString()); + // We want to show stackTrace in error popup + String stackTrace = Utilities.toTruncatedString(Joiner.on("\n").join(cause.getStackTrace()), 800, false); + throw new ViewfxException(cause, "%s at loading view class\nStack trace:\n%s", + cause.getClass().getSimpleName(), stackTrace); + } else { + throw new ViewfxException(ex, "Failed to load view from FXML file at [%s]", fxmlUrl); + } } } @@ -122,8 +139,7 @@ public class FxmlViewLoader implements ViewLoader { } try { return annotationType.getDeclaredMethod(attributeName).getDefaultValue(); - } - catch (Exception ex) { + } catch (Exception ex) { return null; } } diff --git a/desktop/src/main/java/bisq/desktop/common/view/CachingViewLoader.java b/desktop/src/main/java/bisq/desktop/common/view/CachingViewLoader.java index cab1bc9d70..9f92d77919 100644 --- a/desktop/src/main/java/bisq/desktop/common/view/CachingViewLoader.java +++ b/desktop/src/main/java/bisq/desktop/common/view/CachingViewLoader.java @@ -21,11 +21,12 @@ import javax.inject.Inject; import javax.inject.Singleton; import java.util.HashMap; +import java.util.Map; @Singleton public class CachingViewLoader implements ViewLoader { - private final HashMap cache = new HashMap<>(); + private final Map, View> cache = new HashMap<>(); private final ViewLoader viewLoader; @Inject diff --git a/desktop/src/main/java/bisq/desktop/components/InfoInputTextField.java b/desktop/src/main/java/bisq/desktop/components/InfoInputTextField.java index 190e3f80c6..6d625c956f 100644 --- a/desktop/src/main/java/bisq/desktop/components/InfoInputTextField.java +++ b/desktop/src/main/java/bisq/desktop/components/InfoInputTextField.java @@ -19,6 +19,7 @@ package bisq.desktop.components; import bisq.desktop.components.controlsfx.control.PopOver; +import de.jensd.fx.fontawesome.AwesomeDude; import de.jensd.fx.fontawesome.AwesomeIcon; import javafx.scene.Node; @@ -30,23 +31,18 @@ import javafx.beans.property.StringProperty; import lombok.Getter; -import static bisq.desktop.util.FormBuilder.getIcon; +import javax.annotation.Nullable; + +import static com.google.common.base.Preconditions.checkNotNull; public class InfoInputTextField extends AnchorPane { - private final StringProperty text = new SimpleStringProperty(); - @Getter private final InputTextField inputTextField; - @Getter - private final Label infoIcon; - @Getter - private final Label warningIcon; - @Getter - private final Label privacyIcon; - - private Label currentIcon; - private PopOverWrapper popoverWrapper = new PopOverWrapper(); + private final Label icon; + private final PopOverWrapper popoverWrapper = new PopOverWrapper(); + @Nullable + private Node node; public InfoInputTextField() { this(0); @@ -56,79 +52,67 @@ public class InfoInputTextField extends AnchorPane { super(); inputTextField = new InputTextField(inputLineExtension); - - infoIcon = getIcon(AwesomeIcon.INFO_SIGN); - infoIcon.setLayoutY(3); - infoIcon.getStyleClass().addAll("icon", "info"); - - warningIcon = getIcon(AwesomeIcon.WARNING_SIGN); - warningIcon.setLayoutY(3); - warningIcon.getStyleClass().addAll("icon", "warning"); - - privacyIcon = getIcon(AwesomeIcon.EYE_CLOSE); - privacyIcon.setLayoutY(3); - privacyIcon.getStyleClass().addAll("icon", "info"); - - AnchorPane.setLeftAnchor(infoIcon, 7.0); - AnchorPane.setLeftAnchor(warningIcon, 7.0); - AnchorPane.setLeftAnchor(privacyIcon, 7.0); AnchorPane.setRightAnchor(inputTextField, 0.0); AnchorPane.setLeftAnchor(inputTextField, 0.0); - hideIcons(); + icon = new Label(); + icon.setLayoutY(3); + AnchorPane.setLeftAnchor(icon, 7.0); + icon.setOnMouseEntered(e -> { + if (node != null) { + popoverWrapper.showPopOver(() -> checkNotNull(createPopOver())); + } + }); + icon.setOnMouseExited(e -> { + if (node != null) { + popoverWrapper.hidePopOver(); + } + }); - getChildren().addAll(inputTextField, infoIcon, warningIcon, privacyIcon); + hideIcon(); + + getChildren().addAll(inputTextField, icon); } - private void hideIcons() { - infoIcon.setManaged(false); - infoIcon.setVisible(false); - warningIcon.setManaged(false); - warningIcon.setVisible(false); - privacyIcon.setManaged(false); - privacyIcon.setVisible(false); - } - /////////////////////////////////////////////////////////////////////////////////////////// // Public /////////////////////////////////////////////////////////////////////////////////////////// public void setContentForInfoPopOver(Node node) { - currentIcon = infoIcon; - - hideIcons(); - setActionHandlers(node); + setContentForPopOver(node, AwesomeIcon.INFO_SIGN); } public void setContentForWarningPopOver(Node node) { - currentIcon = warningIcon; - - hideIcons(); - setActionHandlers(node); + setContentForPopOver(node, AwesomeIcon.WARNING_SIGN, "warning"); } public void setContentForPrivacyPopOver(Node node) { - currentIcon = privacyIcon; - - hideIcons(); - setActionHandlers(node); + setContentForPopOver(node, AwesomeIcon.EYE_CLOSE); } - public void hideInfoContent() { - currentIcon = null; - hideIcons(); + public void setContentForPopOver(Node node, AwesomeIcon awesomeIcon) { + setContentForPopOver(node, awesomeIcon, null); + } + + public void setContentForPopOver(Node node, AwesomeIcon awesomeIcon, @Nullable String style) { + this.node = node; + AwesomeDude.setIcon(icon, awesomeIcon); + icon.getStyleClass().addAll("icon", style == null ? "info" : style); + icon.setManaged(true); + icon.setVisible(true); + } + + public void hideIcon() { + icon.setManaged(false); + icon.setVisible(false); } public void setIconsRightAligned() { - AnchorPane.clearConstraints(infoIcon); - AnchorPane.clearConstraints(warningIcon); - AnchorPane.clearConstraints(privacyIcon); + AnchorPane.clearConstraints(icon); AnchorPane.clearConstraints(inputTextField); - AnchorPane.setRightAnchor(infoIcon, 7.0); - AnchorPane.setRightAnchor(warningIcon, 7.0); - AnchorPane.setRightAnchor(privacyIcon, 7.0); + AnchorPane.setRightAnchor(icon, 7.0); AnchorPane.setLeftAnchor(inputTextField, 0.0); AnchorPane.setRightAnchor(inputTextField, 0.0); } @@ -146,7 +130,7 @@ public class InfoInputTextField extends AnchorPane { return text.get(); } - public final StringProperty textProperty() { + public StringProperty textProperty() { return text; } @@ -155,28 +139,18 @@ public class InfoInputTextField extends AnchorPane { // Private /////////////////////////////////////////////////////////////////////////////////////////// - private void setActionHandlers(Node node) { - - if (node != null) { - currentIcon.setManaged(true); - currentIcon.setVisible(true); - - // As we don't use binding here we need to recreate it on mouse over to reflect the current state - currentIcon.setOnMouseEntered(e -> popoverWrapper.showPopOver(() -> createPopOver(node))); - currentIcon.setOnMouseExited(e -> popoverWrapper.hidePopOver()); + private PopOver createPopOver() { + if (node == null) { + return null; } - } - private PopOver createPopOver(Node node) { node.getStyleClass().add("default-text"); - PopOver popover = new PopOver(node); - if (currentIcon.getScene() != null) { + if (icon.getScene() != null) { popover.setDetachable(false); popover.setArrowLocation(PopOver.ArrowLocation.LEFT_TOP); popover.setArrowIndent(5); - - popover.show(currentIcon, -17); + popover.show(icon, -17); } return popover; } diff --git a/desktop/src/main/java/bisq/desktop/components/InputTextField.java b/desktop/src/main/java/bisq/desktop/components/InputTextField.java index abe9b49468..7313074506 100644 --- a/desktop/src/main/java/bisq/desktop/components/InputTextField.java +++ b/desktop/src/main/java/bisq/desktop/components/InputTextField.java @@ -78,6 +78,9 @@ public class InputTextField extends JFXTextField { if (newValue != null) { resetValidation(); if (!newValue.isValid) { + if (!newValue.errorMessageEquals(oldValue)) { // avoid blinking + validate(); // ensure that the new error message replaces the old one + } if (this.errorMessage != null) { jfxValidationWrapper.applyErrorMessage(this.errorMessage); } else { diff --git a/desktop/src/main/java/bisq/desktop/components/PeerInfoIcon.java b/desktop/src/main/java/bisq/desktop/components/PeerInfoIcon.java index 47679d650f..e400b29692 100644 --- a/desktop/src/main/java/bisq/desktop/components/PeerInfoIcon.java +++ b/desktop/src/main/java/bisq/desktop/components/PeerInfoIcon.java @@ -355,10 +355,10 @@ public class PeerInfoIcon extends Group { tagLabel.setText(tag.substring(0, 1)); if (numTrades > 0) { - numTradesLabel.setText(String.valueOf(numTrades)); + numTradesLabel.setText(numTrades > 99 ? "*" : String.valueOf(numTrades)); double scaleFactor = getScaleFactor(); - if (numTrades > 9) { + if (numTrades > 9 && numTrades < 100) { numTradesLabel.relocate(scaleFactor * 2, scaleFactor * 1); } else { numTradesLabel.relocate(scaleFactor * 5, scaleFactor * 1); diff --git a/desktop/src/main/java/bisq/desktop/components/SeparatedPhaseBars.java b/desktop/src/main/java/bisq/desktop/components/SeparatedPhaseBars.java index c5daaa3d47..6867df4b8a 100644 --- a/desktop/src/main/java/bisq/desktop/components/SeparatedPhaseBars.java +++ b/desktop/src/main/java/bisq/desktop/components/SeparatedPhaseBars.java @@ -43,6 +43,8 @@ import lombok.extern.slf4j.Slf4j; @Slf4j public class SeparatedPhaseBars extends VBox { + // Last day for creating github compensation request issue, as decided by general consensus + private static final double LAST_COMP_REQ_GH_ISSUE = (double) 18 / 25; private double labelMinWidth = 150; private double breakMinWidth = 20; private int totalDuration; @@ -68,11 +70,14 @@ public class SeparatedPhaseBars extends VBox { item.setTitleLabel(titleLabel); titlesBars.getChildren().addAll(titleLabel); - ProgressBar progressBar = new JFXProgressBar(); + JFXProgressBar progressBar = new JFXProgressBar(); progressBar.setMinHeight(9); progressBar.setMaxHeight(9); progressBar.progressProperty().bind(item.progressProperty); progressBar.setOpacity(item.isShowBlocks() ? 1 : 0.25); + if (item.phase.name().startsWith("PROPOSAL")) { + progressBar.setSecondaryProgress(LAST_COMP_REQ_GH_ISSUE); + } progressBars.getChildren().add(progressBar); item.setProgressBar(progressBar); }); @@ -141,6 +146,9 @@ public class SeparatedPhaseBars extends VBox { private Label titleLabel; @Setter private ProgressBar progressBar; + @Setter + private int indicatorBlock; + private ProgressBar indicatorBar; public SeparatedPhaseBarsItem(DaoPhase.Phase phase, boolean showBlocks) { this.phase = phase; @@ -160,5 +168,6 @@ public class SeparatedPhaseBars extends VBox { lastBlockProperty.set(lastBlock); this.duration = duration; } + } } diff --git a/desktop/src/main/java/bisq/desktop/components/paymentmethods/AmazonGiftCardForm.java b/desktop/src/main/java/bisq/desktop/components/paymentmethods/AmazonGiftCardForm.java index 32d961ea44..a9532ff0fd 100644 --- a/desktop/src/main/java/bisq/desktop/components/paymentmethods/AmazonGiftCardForm.java +++ b/desktop/src/main/java/bisq/desktop/components/paymentmethods/AmazonGiftCardForm.java @@ -69,7 +69,6 @@ public class AmazonGiftCardForm extends PaymentMethodForm { public void addTradeCurrency() { addTradeCurrencyComboBox(); currencyComboBox.setItems(FXCollections.observableArrayList(CurrencyUtil.getAllAmazonGiftCardCurrencies())); - currencyComboBox.getSelectionModel().select(0); } @Override diff --git a/desktop/src/main/java/bisq/desktop/components/paymentmethods/PerfectMoneyForm.java b/desktop/src/main/java/bisq/desktop/components/paymentmethods/PerfectMoneyForm.java index c54aeafd54..b91e036d79 100644 --- a/desktop/src/main/java/bisq/desktop/components/paymentmethods/PerfectMoneyForm.java +++ b/desktop/src/main/java/bisq/desktop/components/paymentmethods/PerfectMoneyForm.java @@ -54,7 +54,6 @@ public class PerfectMoneyForm extends GeneralAccountNumberForm { public void addTradeCurrency() { addTradeCurrencyComboBox(); currencyComboBox.setItems(FXCollections.observableArrayList(new FiatCurrency("USD"), new FiatCurrency("EUR"))); - currencyComboBox.getSelectionModel().select(0); } @Override diff --git a/desktop/src/main/java/bisq/desktop/main/MainViewModel.java b/desktop/src/main/java/bisq/desktop/main/MainViewModel.java index e40d129724..313670d0bd 100644 --- a/desktop/src/main/java/bisq/desktop/main/MainViewModel.java +++ b/desktop/src/main/java/bisq/desktop/main/MainViewModel.java @@ -352,7 +352,6 @@ public class MainViewModel implements ViewModel, BisqSetup.BisqSetupListener { bisqSetup.setDisplayPrivateNotificationHandler(privateNotification -> new Popup().headLine(Res.get("popup.privateNotification.headline")) .attention(privateNotification.getMessage()) - .setHeadlineStyle("-fx-text-fill: -bs-error-red; -fx-font-weight: bold; -fx-font-size: 16;") .onClose(privateNotificationManager::removePrivateNotification) .useIUnderstandButton() .show()); diff --git a/desktop/src/main/java/bisq/desktop/main/PriceUtil.java b/desktop/src/main/java/bisq/desktop/main/PriceUtil.java new file mode 100644 index 0000000000..a63e0086b1 --- /dev/null +++ b/desktop/src/main/java/bisq/desktop/main/PriceUtil.java @@ -0,0 +1,233 @@ +/* + * This file is part of Bisq. + * + * Bisq is free software: you can redistribute it and/or modify it + * under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or (at + * your option) any later version. + * + * Bisq is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public + * License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with Bisq. If not, see . + */ + +package bisq.desktop.main; + +import bisq.desktop.util.validation.AltcoinValidator; +import bisq.desktop.util.validation.FiatPriceValidator; +import bisq.desktop.util.validation.MonetaryValidator; + +import bisq.core.locale.CurrencyUtil; +import bisq.core.locale.Res; +import bisq.core.monetary.Altcoin; +import bisq.core.monetary.Price; +import bisq.core.offer.Offer; +import bisq.core.offer.OfferPayload; +import bisq.core.provider.price.MarketPrice; +import bisq.core.provider.price.PriceFeedService; +import bisq.core.trade.statistics.TradeStatisticsManager; +import bisq.core.user.Preferences; +import bisq.core.util.AveragePriceUtil; +import bisq.core.util.FormattingUtils; +import bisq.core.util.ParsingUtils; +import bisq.core.util.validation.InputValidator; + +import bisq.common.util.MathUtils; + +import org.bitcoinj.utils.Fiat; + +import javax.inject.Inject; +import javax.inject.Singleton; + +import java.util.Optional; + +import javax.annotation.Nullable; + +import static bisq.desktop.main.shared.ChatView.log; +import static com.google.common.base.Preconditions.checkNotNull; + +@Singleton +public class PriceUtil { + private final PriceFeedService priceFeedService; + private final TradeStatisticsManager tradeStatisticsManager; + private final Preferences preferences; + @Nullable + private Price bsq30DayAveragePrice; + + @Inject + public PriceUtil(PriceFeedService priceFeedService, + TradeStatisticsManager tradeStatisticsManager, + Preferences preferences) { + this.priceFeedService = priceFeedService; + this.tradeStatisticsManager = tradeStatisticsManager; + this.preferences = preferences; + } + + public static MonetaryValidator getPriceValidator(boolean isFiatCurrency) { + return isFiatCurrency ? + new FiatPriceValidator() : + new AltcoinValidator(); + } + + public static InputValidator.ValidationResult isTriggerPriceValid(String triggerPriceAsString, + Price price, + boolean isSellOffer, + boolean isFiatCurrency) { + if (triggerPriceAsString == null || triggerPriceAsString.isEmpty()) { + return new InputValidator.ValidationResult(true); + } + + InputValidator.ValidationResult result = getPriceValidator(isFiatCurrency).validate(triggerPriceAsString); + if (!result.isValid) { + return result; + } + + long triggerPriceAsLong = PriceUtil.getMarketPriceAsLong(triggerPriceAsString, price.getCurrencyCode()); + long priceAsLong = price.getValue(); + String priceAsString = FormattingUtils.formatPrice(price); + if ((isSellOffer && isFiatCurrency) || (!isSellOffer && !isFiatCurrency)) { + if (triggerPriceAsLong >= priceAsLong) { + return new InputValidator.ValidationResult(false, + Res.get("createOffer.triggerPrice.invalid.tooHigh", priceAsString)); + } else { + return new InputValidator.ValidationResult(true); + } + } else { + if (triggerPriceAsLong <= priceAsLong) { + return new InputValidator.ValidationResult(false, + Res.get("createOffer.triggerPrice.invalid.tooLow", priceAsString)); + } else { + return new InputValidator.ValidationResult(true); + } + } + } + + public void recalculateBsq30DayAveragePrice() { + bsq30DayAveragePrice = null; + bsq30DayAveragePrice = getBsq30DayAveragePrice(); + } + + public Price getBsq30DayAveragePrice() { + if (bsq30DayAveragePrice == null) { + bsq30DayAveragePrice = AveragePriceUtil.getAveragePriceTuple(preferences, + tradeStatisticsManager, 30).second; + } + return bsq30DayAveragePrice; + } + + public boolean hasMarketPrice(Offer offer) { + String currencyCode = offer.getCurrencyCode(); + checkNotNull(priceFeedService, "priceFeed must not be null"); + MarketPrice marketPrice = priceFeedService.getMarketPrice(currencyCode); + Price price = offer.getPrice(); + return price != null && marketPrice != null && marketPrice.isRecentExternalPriceAvailable(); + } + + public Optional getMarketBasedPrice(Offer offer, + OfferPayload.Direction direction) { + if (offer.isUseMarketBasedPrice()) { + return Optional.of(offer.getMarketPriceMargin()); + } + + if (!hasMarketPrice(offer)) { + if (offer.getCurrencyCode().equals("BSQ")) { + Price bsq30DayAveragePrice = getBsq30DayAveragePrice(); + if (bsq30DayAveragePrice.isPositive()) { + double scaled = MathUtils.scaleDownByPowerOf10(bsq30DayAveragePrice.getValue(), 8); + return calculatePercentage(offer, scaled, direction); + } else { + return Optional.empty(); + } + } else { + log.trace("We don't have a market price. " + + "That case could only happen if you don't have a price feed."); + return Optional.empty(); + } + } + + String currencyCode = offer.getCurrencyCode(); + checkNotNull(priceFeedService, "priceFeed must not be null"); + MarketPrice marketPrice = priceFeedService.getMarketPrice(currencyCode); + double marketPriceAsDouble = checkNotNull(marketPrice).getPrice(); + return calculatePercentage(offer, marketPriceAsDouble, direction); + } + + public Optional calculatePercentage(Offer offer, + double marketPrice, + OfferPayload.Direction direction) { + // If the offer did not use % price we calculate % from current market price + String currencyCode = offer.getCurrencyCode(); + Price price = offer.getPrice(); + int precision = CurrencyUtil.isCryptoCurrency(currencyCode) ? + Altcoin.SMALLEST_UNIT_EXPONENT : + Fiat.SMALLEST_UNIT_EXPONENT; + long priceAsLong = checkNotNull(price).getValue(); + double scaled = MathUtils.scaleDownByPowerOf10(priceAsLong, precision); + double value; + if (direction == OfferPayload.Direction.SELL) { + if (CurrencyUtil.isFiatCurrency(currencyCode)) { + if (marketPrice == 0) { + return Optional.empty(); + } + value = 1 - scaled / marketPrice; + } else { + if (marketPrice == 1) { + return Optional.empty(); + } + value = scaled / marketPrice - 1; + } + } else { + if (CurrencyUtil.isFiatCurrency(currencyCode)) { + if (marketPrice == 1) { + return Optional.empty(); + } + value = scaled / marketPrice - 1; + } else { + if (marketPrice == 0) { + return Optional.empty(); + } + value = 1 - scaled / marketPrice; + } + } + return Optional.of(value); + } + + public static long getMarketPriceAsLong(String inputValue, String currencyCode) { + if (inputValue == null || inputValue.isEmpty() || currencyCode == null) { + return 0; + } + + try { + int precision = getMarketPricePrecision(currencyCode); + String stringValue = reformatMarketPrice(inputValue, currencyCode); + return ParsingUtils.parsePriceStringToLong(currencyCode, stringValue, precision); + } catch (Throwable t) { + return 0; + } + } + + public static String reformatMarketPrice(String inputValue, String currencyCode) { + if (inputValue == null || inputValue.isEmpty() || currencyCode == null) { + return ""; + } + + double priceAsDouble = ParsingUtils.parseNumberStringToDouble(inputValue); + int precision = getMarketPricePrecision(currencyCode); + return FormattingUtils.formatRoundedDoubleWithPrecision(priceAsDouble, precision); + } + + public static String formatMarketPrice(long price, String currencyCode) { + int marketPricePrecision = getMarketPricePrecision(currencyCode); + double scaled = MathUtils.scaleDownByPowerOf10(price, marketPricePrecision); + return FormattingUtils.formatMarketPrice(scaled, marketPricePrecision); + } + + public static int getMarketPricePrecision(String currencyCode) { + return CurrencyUtil.isCryptoCurrency(currencyCode) ? + Altcoin.SMALLEST_UNIT_EXPONENT : Fiat.SMALLEST_UNIT_EXPONENT; + } +} diff --git a/desktop/src/main/java/bisq/desktop/main/account/content/PaymentAccountsView.java b/desktop/src/main/java/bisq/desktop/main/account/content/PaymentAccountsView.java index 6b26f66312..34184860d3 100644 --- a/desktop/src/main/java/bisq/desktop/main/account/content/PaymentAccountsView.java +++ b/desktop/src/main/java/bisq/desktop/main/account/content/PaymentAccountsView.java @@ -62,7 +62,7 @@ public abstract class PaymentAccountsView { currencyComboBox.getSelectionModel().select(optionalTradeCurrency.get()); onSelectedTradeCurrency(); + priceAlertHighInputTextField.setText(PriceUtil.formatMarketPrice(priceAlertFilter.getHigh(), currencyCode)); priceAlertHighInputTextField.setText(FormattingUtils.formatMarketPrice(priceAlertFilter.getHigh() / 10000d, currencyCode)); priceAlertLowInputTextField.setText(FormattingUtils.formatMarketPrice(priceAlertFilter.getLow() / 10000d, currencyCode)); } else { @@ -742,37 +743,13 @@ public class MobileNotificationsView extends ActivatableView { } private long getPriceAsLong(InputTextField inputTextField) { - try { - String inputValue = inputTextField.getText(); - if (inputValue != null && !inputValue.isEmpty() && selectedPriceAlertTradeCurrency != null) { - double priceAsDouble = ParsingUtils.parseNumberStringToDouble(inputValue); - String currencyCode = selectedPriceAlertTradeCurrency; - int precision = CurrencyUtil.isCryptoCurrency(currencyCode) ? - Altcoin.SMALLEST_UNIT_EXPONENT : 2; - // We want to use the converted value not the inout value as we apply the converted value at focus out. - // E.g. if input is 5555.5555 it will be rounded to 5555.55 and we use that as the value for comparing - // low and high price... - String stringValue = FormattingUtils.formatRoundedDoubleWithPrecision(priceAsDouble, precision); - return ParsingUtils.parsePriceStringToLong(currencyCode, stringValue, precision); - } else { - return 0; - } - } catch (Throwable ignore) { - return 0; - } + return PriceUtil.getMarketPriceAsLong(inputTextField.getText(), selectedPriceAlertTradeCurrency); } private void applyPriceFormatting(InputTextField inputTextField) { try { - String inputValue = inputTextField.getText(); - if (inputValue != null && !inputValue.isEmpty() && selectedPriceAlertTradeCurrency != null) { - double priceAsDouble = ParsingUtils.parseNumberStringToDouble(inputValue); - String currencyCode = selectedPriceAlertTradeCurrency; - int precision = CurrencyUtil.isCryptoCurrency(currencyCode) ? - Altcoin.SMALLEST_UNIT_EXPONENT : 2; - String stringValue = FormattingUtils.formatRoundedDoubleWithPrecision(priceAsDouble, precision); - inputTextField.setText(stringValue); - } + String reformattedPrice = PriceUtil.reformatMarketPrice(inputTextField.getText(), selectedPriceAlertTradeCurrency); + inputTextField.setText(reformattedPrice); } catch (Throwable ignore) { updatePriceAlertFields(); } diff --git a/desktop/src/main/java/bisq/desktop/main/dao/economy/dashboard/BsqDashboardView.java b/desktop/src/main/java/bisq/desktop/main/dao/economy/dashboard/BsqDashboardView.java index 7cf25b4f3d..693ec87cd6 100644 --- a/desktop/src/main/java/bisq/desktop/main/dao/economy/dashboard/BsqDashboardView.java +++ b/desktop/src/main/java/bisq/desktop/main/dao/economy/dashboard/BsqDashboardView.java @@ -150,13 +150,6 @@ public class BsqDashboardView extends ActivatableView implements marketPriceBox.second.getStyleClass().add("dao-kpi-subtext"); - avgPrice90TextField = addTopLabelReadOnlyTextField(root, ++gridRow, - Res.get("dao.factsAndFigures.dashboard.avgPrice90")).second; - - avgPrice30TextField = addTopLabelTextFieldWithIcon(root, gridRow, 1, - Res.get("dao.factsAndFigures.dashboard.avgPrice30"), -15).second; - AnchorPane.setRightAnchor(avgPrice30TextField.getIconLabel(), 10d); - avgUSDPrice90TextField = addTopLabelReadOnlyTextField(root, ++gridRow, Res.get("dao.factsAndFigures.dashboard.avgUSDPrice90")).second; @@ -164,6 +157,13 @@ public class BsqDashboardView extends ActivatableView implements Res.get("dao.factsAndFigures.dashboard.avgUSDPrice30"), -15).second; AnchorPane.setRightAnchor(avgUSDPrice30TextField.getIconLabel(), 10d); + avgPrice90TextField = addTopLabelReadOnlyTextField(root, ++gridRow, + Res.get("dao.factsAndFigures.dashboard.avgPrice90")).second; + + avgPrice30TextField = addTopLabelTextFieldWithIcon(root, gridRow, 1, + Res.get("dao.factsAndFigures.dashboard.avgPrice30"), -15).second; + AnchorPane.setRightAnchor(avgPrice30TextField.getIconLabel(), 10d); + marketCapTextField = addTopLabelReadOnlyTextField(root, ++gridRow, Res.get("dao.factsAndFigures.dashboard.marketCap")).second; @@ -171,7 +171,6 @@ public class BsqDashboardView extends ActivatableView implements Res.get("dao.factsAndFigures.dashboard.availableAmount")).second; } - @Override protected void activate() { daoFacade.addBsqStateListener(this); diff --git a/desktop/src/main/java/bisq/desktop/main/dao/economy/supply/SupplyView.java b/desktop/src/main/java/bisq/desktop/main/dao/economy/supply/SupplyView.java index 7d07b2bac4..cd3d05b965 100644 --- a/desktop/src/main/java/bisq/desktop/main/dao/economy/supply/SupplyView.java +++ b/desktop/src/main/java/bisq/desktop/main/dao/economy/supply/SupplyView.java @@ -61,8 +61,6 @@ import javafx.collections.ListChangeListener; import javafx.util.StringConverter; -import java.text.DecimalFormat; - import java.time.Instant; import java.time.LocalDate; import java.time.LocalDateTime; @@ -73,6 +71,8 @@ import java.time.format.DateTimeFormatter; import java.time.temporal.TemporalAdjuster; import java.time.temporal.TemporalAdjusters; +import java.text.DecimalFormat; + import java.util.Comparator; import java.util.HashMap; import java.util.HashSet; @@ -630,10 +630,10 @@ public class SupplyView extends ActivatableView implements DaoSt .toLocalDate() .with(ADJUSTERS.get(MONTH))); - Stream bsqByCompensation = daoStateService.getIssuanceSet(IssuanceType.COMPENSATION).stream() + Stream bsqByCompensation = daoStateService.getIssuanceSetForType(IssuanceType.COMPENSATION).stream() .sorted(Comparator.comparing(Issuance::getChainHeight)); - Stream bsqByReimbursement = daoStateService.getIssuanceSet(IssuanceType.REIMBURSEMENT).stream() + Stream bsqByReimbursement = daoStateService.getIssuanceSetForType(IssuanceType.REIMBURSEMENT).stream() .sorted(Comparator.comparing(Issuance::getChainHeight)); Map> bsqAddedByVote = Stream.concat(bsqByCompensation, bsqByReimbursement) diff --git a/desktop/src/main/java/bisq/desktop/main/funds/deposit/DepositView.java b/desktop/src/main/java/bisq/desktop/main/funds/deposit/DepositView.java index 8aeb4ac4c1..cc2c4fed01 100644 --- a/desktop/src/main/java/bisq/desktop/main/funds/deposit/DepositView.java +++ b/desktop/src/main/java/bisq/desktop/main/funds/deposit/DepositView.java @@ -42,6 +42,7 @@ import bisq.core.util.coin.CoinFormatter; import bisq.common.UserThread; import bisq.common.app.DevEnv; import bisq.common.config.Config; +import bisq.common.util.Tuple3; import org.bitcoinj.core.Address; import org.bitcoinj.core.Coin; @@ -66,9 +67,9 @@ import javafx.scene.control.Tooltip; import javafx.scene.image.Image; import javafx.scene.image.ImageView; import javafx.scene.layout.GridPane; +import javafx.scene.layout.HBox; import javafx.scene.layout.VBox; -import javafx.geometry.HPos; import javafx.geometry.Insets; import org.fxmisc.easybind.EasyBind; @@ -198,17 +199,15 @@ public class DepositView extends ActivatableView { addressTextField.setManaged(false); amountTextField.setManaged(false); - generateNewAddressButton = addButton(gridPane, ++gridRow, Res.get("funds.deposit.generateAddress"), -20); - GridPane.setColumnIndex(generateNewAddressButton, 0); - GridPane.setHalignment(generateNewAddressButton, HPos.LEFT); - - generateNewAddressSegwitCheckbox = addCheckBox(gridPane, gridRow, - Res.get("funds.deposit.generateAddressSegwit"), 0); + Tuple3 buttonCheckBoxHBox = addButtonCheckBoxWithBox(gridPane, ++gridRow, + Res.get("funds.deposit.generateAddress"), + Res.get("funds.deposit.generateAddressSegwit"), + 15); + buttonCheckBoxHBox.third.setSpacing(25); + generateNewAddressButton = buttonCheckBoxHBox.first; + generateNewAddressSegwitCheckbox = buttonCheckBoxHBox.second; generateNewAddressSegwitCheckbox.setAllowIndeterminate(false); generateNewAddressSegwitCheckbox.setSelected(true); - GridPane.setColumnIndex(generateNewAddressSegwitCheckbox, 0); - GridPane.setHalignment(generateNewAddressSegwitCheckbox, HPos.LEFT); - GridPane.setMargin(generateNewAddressSegwitCheckbox, new Insets(15, 0, 0, 250)); generateNewAddressButton.setOnAction(event -> { boolean segwit = generateNewAddressSegwitCheckbox.isSelected(); diff --git a/desktop/src/main/java/bisq/desktop/main/funds/locked/LockedView.java b/desktop/src/main/java/bisq/desktop/main/funds/locked/LockedView.java index df3db4eadc..0148bd4baf 100644 --- a/desktop/src/main/java/bisq/desktop/main/funds/locked/LockedView.java +++ b/desktop/src/main/java/bisq/desktop/main/funds/locked/LockedView.java @@ -179,7 +179,7 @@ public class LockedView extends ActivatableView { exportButton.setOnAction(event -> { ObservableList> tableColumns = tableView.getColumns(); int reportColumns = tableColumns.size(); - CSVEntryConverter headerConverter = transactionsListItem -> { + CSVEntryConverter headerConverter = item -> { String[] columns = new String[reportColumns]; for (int i = 0; i < columns.length; i++) columns[i] = ((AutoTooltipLabel) tableColumns.get(i).getGraphic()).getText(); diff --git a/desktop/src/main/java/bisq/desktop/main/funds/reserved/ReservedView.java b/desktop/src/main/java/bisq/desktop/main/funds/reserved/ReservedView.java index cac62e6c44..f113524665 100644 --- a/desktop/src/main/java/bisq/desktop/main/funds/reserved/ReservedView.java +++ b/desktop/src/main/java/bisq/desktop/main/funds/reserved/ReservedView.java @@ -179,7 +179,7 @@ public class ReservedView extends ActivatableView { exportButton.setOnAction(event -> { ObservableList> tableColumns = tableView.getColumns(); int reportColumns = tableColumns.size(); - CSVEntryConverter headerConverter = transactionsListItem -> { + CSVEntryConverter headerConverter = item -> { String[] columns = new String[reportColumns]; for (int i = 0; i < columns.length; i++) columns[i] = ((AutoTooltipLabel) tableColumns.get(i).getGraphic()).getText(); diff --git a/desktop/src/main/java/bisq/desktop/main/funds/transactions/TransactionsView.java b/desktop/src/main/java/bisq/desktop/main/funds/transactions/TransactionsView.java index 3020828aa1..4aefbe9b9d 100644 --- a/desktop/src/main/java/bisq/desktop/main/funds/transactions/TransactionsView.java +++ b/desktop/src/main/java/bisq/desktop/main/funds/transactions/TransactionsView.java @@ -212,7 +212,7 @@ public class TransactionsView extends ActivatableView { exportButton.setOnAction(event -> { final ObservableList> tableColumns = tableView.getColumns(); final int reportColumns = tableColumns.size() - 1; // CSV report excludes the last column (an icon) - CSVEntryConverter headerConverter = transactionsListItem -> { + CSVEntryConverter headerConverter = item -> { String[] columns = new String[reportColumns]; for (int i = 0; i < columns.length; i++) columns[i] = ((AutoTooltipLabel) tableColumns.get(i).getGraphic()).getText(); diff --git a/desktop/src/main/java/bisq/desktop/main/funds/withdrawal/WithdrawalView.java b/desktop/src/main/java/bisq/desktop/main/funds/withdrawal/WithdrawalView.java index 26adadf8e3..e67cd9903e 100644 --- a/desktop/src/main/java/bisq/desktop/main/funds/withdrawal/WithdrawalView.java +++ b/desktop/src/main/java/bisq/desktop/main/funds/withdrawal/WithdrawalView.java @@ -269,8 +269,8 @@ public class WithdrawalView extends ActivatableView { feeToggleGroupListener = (observable, oldValue, newValue) -> { feeExcluded = newValue == feeExcludedRadioButton; amountLabel.setText(feeExcluded ? - Res.get("funds.withdrawal.receiverAmount", Res.getBaseCurrencyCode()) : - Res.get("funds.withdrawal.senderAmount", Res.getBaseCurrencyCode())); + Res.get("funds.withdrawal.receiverAmount") : + Res.get("funds.withdrawal.senderAmount")); }; } diff --git a/desktop/src/main/java/bisq/desktop/main/market/MarketView.fxml b/desktop/src/main/java/bisq/desktop/main/market/MarketView.fxml index ead1b39904..74568ee5be 100644 --- a/desktop/src/main/java/bisq/desktop/main/market/MarketView.fxml +++ b/desktop/src/main/java/bisq/desktop/main/market/MarketView.fxml @@ -32,6 +32,7 @@ AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0"/> + { @FXML - Tab offerBookTab, tradesTab, spreadTab; + Tab offerBookTab, tradesTab, spreadTab, spreadTabPaymentMethod; private final ViewLoader viewLoader; - private final P2PService p2PService; + private final TradeStatistics3StorageService tradeStatistics3StorageService; private final OfferBook offerBook; private final CoinFormatter formatter; private final Navigation navigation; @@ -83,12 +83,12 @@ public class MarketView extends ActivatableView { @Inject public MarketView(CachingViewLoader viewLoader, - P2PService p2PService, + TradeStatistics3StorageService tradeStatistics3StorageService, OfferBook offerBook, @Named(FormattingUtils.BTC_FORMATTER_KEY) CoinFormatter formatter, Navigation navigation) { this.viewLoader = viewLoader; - this.p2PService = p2PService; + this.tradeStatistics3StorageService = tradeStatistics3StorageService; this.offerBook = offerBook; this.formatter = formatter; this.navigation = navigation; @@ -97,7 +97,8 @@ public class MarketView extends ActivatableView { @Override public void initialize() { offerBookTab.setText(Res.get("market.tabs.offerBook").toUpperCase()); - spreadTab.setText(Res.get("market.tabs.spread").toUpperCase()); + spreadTab.setText(Res.get("market.tabs.spreadCurrency").toUpperCase()); + spreadTabPaymentMethod.setText(Res.get("market.tabs.spreadPayment").toUpperCase()); tradesTab.setText(Res.get("market.tabs.trades").toUpperCase()); navigationListener = viewPath -> { @@ -112,6 +113,8 @@ public class MarketView extends ActivatableView { navigation.navigateTo(MainView.class, MarketView.class, TradesChartsView.class); else if (newValue == spreadTab) navigation.navigateTo(MainView.class, MarketView.class, SpreadView.class); + else if (newValue == spreadTabPaymentMethod) + navigation.navigateTo(MainView.class, MarketView.class, SpreadViewPaymentMethod.class); }; keyEventEventHandler = keyEvent -> { @@ -140,8 +143,10 @@ public class MarketView extends ActivatableView { navigation.navigateTo(MainView.class, MarketView.class, OfferBookChartView.class); else if (root.getSelectionModel().getSelectedItem() == tradesTab) navigation.navigateTo(MainView.class, MarketView.class, TradesChartsView.class); - else + else if (root.getSelectionModel().getSelectedItem() == spreadTab) navigation.navigateTo(MainView.class, MarketView.class, SpreadView.class); + else + navigation.navigateTo(MainView.class, MarketView.class, SpreadViewPaymentMethod.class); if (root.getScene() != null) { scene = root.getScene(); @@ -165,6 +170,7 @@ public class MarketView extends ActivatableView { if (view instanceof OfferBookChartView) tab = offerBookTab; else if (view instanceof TradesChartsView) tab = tradesTab; + else if (view instanceof SpreadViewPaymentMethod) tab = spreadTabPaymentMethod; else if (view instanceof SpreadView) tab = spreadTab; else throw new IllegalArgumentException("Navigation to " + viewClass + " is not supported"); @@ -181,7 +187,7 @@ public class MarketView extends ActivatableView { // all items of both traders in case the referral ID was only set by one trader. // If both traders had set it the tradeStatistics is only delivered once. // If both traders used a different referral ID then we would get 2 objects. - List list = p2PService.getP2PDataStorage().getAppendOnlyDataStoreMap().values().stream() + List list = tradeStatistics3StorageService.getMapOfAllData().values().stream() .filter(e -> e instanceof TradeStatistics3) .map(e -> (TradeStatistics3) e) .filter(tradeStatistics3 -> tradeStatistics3.getExtraDataMap() != null) diff --git a/desktop/src/main/java/bisq/desktop/main/market/spread/SpreadView.java b/desktop/src/main/java/bisq/desktop/main/market/spread/SpreadView.java index 539ab5ffad..68325ba38f 100644 --- a/desktop/src/main/java/bisq/desktop/main/market/spread/SpreadView.java +++ b/desktop/src/main/java/bisq/desktop/main/market/spread/SpreadView.java @@ -95,7 +95,8 @@ public class SpreadView extends ActivatableViewAndModel CurrencyUtil.getNameByCode(o.currencyCode))); + currencyColumn.setComparator(Comparator.comparing(o -> + model.isIncludePaymentMethod() ? o.currencyCode : CurrencyUtil.getNameByCode(o.currencyCode))); numberOfOffersColumn.setComparator(Comparator.comparingInt(o3 -> o3.numberOfOffers)); numberOfBuyOffersColumn.setComparator(Comparator.comparingInt(o3 -> o3.numberOfBuyOffers)); numberOfSellOffersColumn.setComparator(Comparator.comparingInt(o2 -> o2.numberOfSellOffers)); @@ -139,7 +140,7 @@ public class SpreadView extends ActivatableViewAndModel getCurrencyColumn() { - TableColumn column = new AutoTooltipTableColumn<>(Res.get("shared.currency")) { + TableColumn column = new AutoTooltipTableColumn<>(model.getKeyColumnName()) { { setMinWidth(160); } @@ -156,7 +157,10 @@ public class SpreadView extends ActivatableViewAndModel listChangeListener; final ObservableList spreadItems = FXCollections.observableArrayList(); final IntegerProperty maxPlacesForAmount = new SimpleIntegerProperty(); - + @Setter + @Getter + private boolean includePaymentMethod; + @Getter + private boolean expandedView; /////////////////////////////////////////////////////////////////////////////////////////// // Constructor, lifecycle @@ -80,11 +87,20 @@ class SpreadViewModel extends ActivatableViewModel { this.offerBook = offerBook; this.priceFeedService = priceFeedService; this.formatter = formatter; - + includePaymentMethod = false; offerBookListItems = offerBook.getOfferBookListItems(); listChangeListener = c -> update(offerBookListItems); } + public String getKeyColumnName() { + return includePaymentMethod ? Res.get("shared.paymentMethod") : Res.get("shared.currency"); + } + + public void setExpandedView(boolean expandedView) { + this.expandedView = expandedView; + update(offerBookListItems); + } + @Override protected void activate() { offerBookListItems.addListener(listChangeListener); @@ -106,18 +122,24 @@ class SpreadViewModel extends ActivatableViewModel { Map> offersByCurrencyMap = new HashMap<>(); for (OfferBookListItem offerBookListItem : offerBookListItems) { Offer offer = offerBookListItem.getOffer(); - String currencyCode = offer.getCurrencyCode(); - if (!offersByCurrencyMap.containsKey(currencyCode)) - offersByCurrencyMap.put(currencyCode, new ArrayList<>()); - offersByCurrencyMap.get(currencyCode).add(offer); + String key = offer.getCurrencyCode(); + if (includePaymentMethod) { + key = offer.getPaymentMethod().getShortName(); + if (expandedView) { + key += ":" + offer.getCurrencyCode(); + } + } + if (!offersByCurrencyMap.containsKey(key)) + offersByCurrencyMap.put(key, new ArrayList<>()); + offersByCurrencyMap.get(key).add(offer); } spreadItems.clear(); Coin totalAmount = null; - for (String currencyCode : offersByCurrencyMap.keySet()) { - List offers = offersByCurrencyMap.get(currencyCode); - final boolean isFiatCurrency = CurrencyUtil.isFiatCurrency(currencyCode); + for (String key : offersByCurrencyMap.keySet()) { + List offers = offersByCurrencyMap.get(key); + final boolean isFiatCurrency = (offers.size() > 0 && !offers.get(0).getPaymentMethod().isAsset()); List uniqueOffers = offers.stream().filter(distinctByKey(Offer::getId)).collect(Collectors.toList()); @@ -160,8 +182,9 @@ class SpreadViewModel extends ActivatableViewModel { double percentageValue = 0; Price bestSellOfferPrice = sellOffers.isEmpty() ? null : sellOffers.get(0).getPrice(); Price bestBuyOfferPrice = buyOffers.isEmpty() ? null : buyOffers.get(0).getPrice(); - if (bestBuyOfferPrice != null && bestSellOfferPrice != null) { - MarketPrice marketPrice = priceFeedService.getMarketPrice(currencyCode); + if (bestBuyOfferPrice != null && bestSellOfferPrice != null && + sellOffers.get(0).getCurrencyCode().equals(buyOffers.get(0).getCurrencyCode())) { + MarketPrice marketPrice = priceFeedService.getMarketPrice(sellOffers.get(0).getCurrencyCode()); // There have been some bug reports that an offer caused an overflow exception. // We never found out which offer it was. So add here a try/catch to get better info if it @@ -213,7 +236,7 @@ class SpreadViewModel extends ActivatableViewModel { } totalAmount = Coin.valueOf(offers.stream().mapToLong(offer -> offer.getAmount().getValue()).sum()); - spreadItems.add(new SpreadItem(currencyCode, buyOffers.size(), sellOffers.size(), + spreadItems.add(new SpreadItem(key, buyOffers.size(), sellOffers.size(), uniqueOffers.size(), spread, percentage, percentageValue, totalAmount)); } diff --git a/desktop/src/main/java/bisq/desktop/main/market/spread/SpreadViewPaymentMethod.fxml b/desktop/src/main/java/bisq/desktop/main/market/spread/SpreadViewPaymentMethod.fxml new file mode 100644 index 0000000000..6e8854fd09 --- /dev/null +++ b/desktop/src/main/java/bisq/desktop/main/market/spread/SpreadViewPaymentMethod.fxml @@ -0,0 +1,32 @@ + + + + + + + + + + + + + diff --git a/desktop/src/main/java/bisq/desktop/main/market/spread/SpreadViewPaymentMethod.java b/desktop/src/main/java/bisq/desktop/main/market/spread/SpreadViewPaymentMethod.java new file mode 100644 index 0000000000..c89791d003 --- /dev/null +++ b/desktop/src/main/java/bisq/desktop/main/market/spread/SpreadViewPaymentMethod.java @@ -0,0 +1,68 @@ +/* + * This file is part of Bisq. + * + * Bisq is free software: you can redistribute it and/or modify it + * under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or (at + * your option) any later version. + * + * Bisq is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public + * License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with Bisq. If not, see . + */ + +package bisq.desktop.main.market.spread; + +import bisq.desktop.common.view.FxmlView; + +import bisq.core.locale.Res; +import bisq.core.util.FormattingUtils; +import bisq.core.util.coin.CoinFormatter; + +import javax.inject.Inject; +import javax.inject.Named; + +import javafx.scene.control.ToggleButton; + +import static bisq.desktop.util.FormBuilder.addSlideToggleButton; + +@FxmlView +public class SpreadViewPaymentMethod extends SpreadView { + private ToggleButton expandedMode; + + /////////////////////////////////////////////////////////////////////////////////////////// + // Constructor, lifecycle + /////////////////////////////////////////////////////////////////////////////////////////// + + @Inject + public SpreadViewPaymentMethod(SpreadViewModel model, @Named(FormattingUtils.BTC_FORMATTER_KEY) CoinFormatter formatter) { + super(model, formatter); + model.setIncludePaymentMethod(true); + } + + @Override + public void initialize() { + super.initialize(); + int gridRow = 0; + expandedMode = addSlideToggleButton(root, ++gridRow, Res.get("market.spread.expanded")); + } + + @Override + protected void activate() { + super.activate(); + expandedMode.setSelected(model.isExpandedView()); + expandedMode.setOnAction(e -> model.setExpandedView(expandedMode.isSelected())); + } + + @Override + protected void deactivate() { + expandedMode.setOnAction(null); + super.deactivate(); + } +} + + diff --git a/desktop/src/main/java/bisq/desktop/main/market/trades/TradesChartsView.java b/desktop/src/main/java/bisq/desktop/main/market/trades/TradesChartsView.java index b3d699cd80..4320599881 100644 --- a/desktop/src/main/java/bisq/desktop/main/market/trades/TradesChartsView.java +++ b/desktop/src/main/java/bisq/desktop/main/market/trades/TradesChartsView.java @@ -378,7 +378,7 @@ public class TradesChartsView extends ActivatableViewAndModel headerConverter = transactionsListItem -> { + CSVEntryConverter headerConverter = item -> { String[] columns = new String[reportColumns]; columns[0] = "Epoch time in ms"; for (int i = 0; i < tableColumns.size(); i++) { diff --git a/desktop/src/main/java/bisq/desktop/main/offer/MutableOfferDataModel.java b/desktop/src/main/java/bisq/desktop/main/offer/MutableOfferDataModel.java index e4fe866783..39a8f81f7a 100644 --- a/desktop/src/main/java/bisq/desktop/main/offer/MutableOfferDataModel.java +++ b/desktop/src/main/java/bisq/desktop/main/offer/MutableOfferDataModel.java @@ -88,6 +88,8 @@ import java.util.Optional; import java.util.function.Predicate; import java.util.stream.Collectors; +import lombok.Getter; + import javax.annotation.Nullable; import static com.google.common.base.Preconditions.checkNotNull; @@ -129,6 +131,7 @@ public abstract class MutableOfferDataModel extends OfferDataModel implements Bs boolean isTabSelected; protected double marketPriceMargin = 0; private Coin txFeeFromFeeService = Coin.ZERO; + @Getter private boolean marketPriceAvailable; private int feeTxVsize = TxFeeEstimationService.TYPICAL_TX_WITH_1_INPUT_VSIZE; protected boolean allowAmountUpdate = true; @@ -137,6 +140,9 @@ public abstract class MutableOfferDataModel extends OfferDataModel implements Bs private final Predicate> isNonZeroAmount = (c) -> c.get() != null && !c.get().isZero(); private final Predicate> isNonZeroPrice = (p) -> p.get() != null && !p.get().isZero(); private final Predicate> isNonZeroVolume = (v) -> v.get() != null && !v.get().isZero(); + @Getter + protected long triggerPrice; + /////////////////////////////////////////////////////////////////////////////////////////// // Constructor, lifecycle @@ -315,6 +321,7 @@ public abstract class MutableOfferDataModel extends OfferDataModel implements Bs openOfferManager.placeOffer(offer, buyerSecurityDeposit.get(), useSavingsWallet, + triggerPrice, resultHandler, log::error); } @@ -467,6 +474,14 @@ public abstract class MutableOfferDataModel extends OfferDataModel implements Bs return direction; } + boolean isSellOffer() { + return direction == OfferPayload.Direction.SELL; + } + + boolean isBuyOffer() { + return direction == OfferPayload.Direction.BUY; + } + AddressEntry getAddressEntry() { return addressEntry; } @@ -595,10 +610,6 @@ public abstract class MutableOfferDataModel extends OfferDataModel implements Bs return isBuyOffer() ? getBuyerSecurityDepositAsCoin() : getSellerSecurityDepositAsCoin(); } - boolean isBuyOffer() { - return offerUtil.isBuyOffer(getDirection()); - } - public Coin getTxFee() { if (isCurrencyForMakerFeeBtc()) return txFeeFromFeeService; @@ -668,6 +679,18 @@ public abstract class MutableOfferDataModel extends OfferDataModel implements Bs return tradeCurrencyCode; } + public String getCurrencyCode() { + return tradeCurrencyCode.get(); + } + + boolean isCryptoCurrency() { + return CurrencyUtil.isCryptoCurrency(tradeCurrencyCode.get()); + } + + boolean isFiatCurrency() { + return CurrencyUtil.isFiatCurrency(tradeCurrencyCode.get()); + } + ReadOnlyBooleanProperty getUseMarketBasedPrice() { return useMarketBasedPrice; } @@ -751,4 +774,8 @@ public abstract class MutableOfferDataModel extends OfferDataModel implements Bs public boolean isMinBuyerSecurityDeposit() { return !getBuyerSecurityDepositAsCoin().isGreaterThan(Restrictions.getMinBuyerSecurityDepositAsCoin()); } + + public void setTriggerPrice(long triggerPrice) { + this.triggerPrice = triggerPrice; + } } diff --git a/desktop/src/main/java/bisq/desktop/main/offer/MutableOfferView.java b/desktop/src/main/java/bisq/desktop/main/offer/MutableOfferView.java index 78bb8dafd7..21a5832107 100644 --- a/desktop/src/main/java/bisq/desktop/main/offer/MutableOfferView.java +++ b/desktop/src/main/java/bisq/desktop/main/offer/MutableOfferView.java @@ -68,6 +68,7 @@ import org.bitcoinj.core.Coin; import net.glxn.qrgen.QRCode; import net.glxn.qrgen.image.ImageType; +import de.jensd.fx.fontawesome.AwesomeIcon; import de.jensd.fx.glyphs.materialdesignicons.MaterialDesignIcon; import javafx.scene.Node; @@ -133,32 +134,31 @@ public abstract class MutableOfferView> exten private BusyAnimation waitingForFundsSpinner; private AutoTooltipButton nextButton, cancelButton1, cancelButton2, placeOfferButton; private Button priceTypeToggleButton; - private InputTextField fixedPriceTextField, marketBasedPriceTextField; + private InputTextField fixedPriceTextField, marketBasedPriceTextField, triggerPriceInputTextField; protected InputTextField amountTextField, minAmountTextField, volumeTextField, buyerSecurityDepositInputTextField; private TextField currencyTextField; private AddressTextField addressTextField; private BalanceTextField balanceTextField; private FundsTextField totalToPayTextField; private Label amountDescriptionLabel, priceCurrencyLabel, priceDescriptionLabel, volumeDescriptionLabel, - waitingForFundsLabel, marketBasedPriceLabel, percentagePriceDescription, tradeFeeDescriptionLabel, + waitingForFundsLabel, marketBasedPriceLabel, percentagePriceDescriptionLabel, tradeFeeDescriptionLabel, resultLabel, tradeFeeInBtcLabel, tradeFeeInBsqLabel, xLabel, fakeXLabel, buyerSecurityDepositLabel, - buyerSecurityDepositPercentageLabel; + buyerSecurityDepositPercentageLabel, triggerPriceCurrencyLabel, triggerPriceDescriptionLabel; protected Label amountBtcLabel, volumeCurrencyLabel, minAmountBtcLabel; private ComboBox paymentAccountsComboBox; private ComboBox currencyComboBox; private ImageView qrCodeImageView; - private VBox currencySelection, fixedPriceBox, percentagePriceBox, - currencyTextFieldBox; + private VBox currencySelection, fixedPriceBox, percentagePriceBox, currencyTextFieldBox, triggerPriceVBox; private HBox fundingHBox, firstRowHBox, secondRowHBox, placeOfferBox, amountValueCurrencyBox, priceAsPercentageValueCurrencyBox, volumeValueCurrencyBox, priceValueCurrencyBox, - minAmountValueCurrencyBox, advancedOptionsBox; + minAmountValueCurrencyBox, advancedOptionsBox, triggerPriceHBox; private Subscription isWaitingForFundsSubscription, balanceSubscription; private ChangeListener amountFocusedListener, minAmountFocusedListener, volumeFocusedListener, buyerSecurityDepositFocusedListener, priceFocusedListener, placeOfferCompletedListener, priceAsPercentageFocusedListener, getShowWalletFundedNotificationListener, tradeFeeInBtcToggleListener, tradeFeeInBsqToggleListener, tradeFeeVisibleListener, - isMinBuyerSecurityDepositListener; + isMinBuyerSecurityDepositListener, triggerPriceFocusedListener; private ChangeListener missingCoinListener; private ChangeListener tradeCurrencyCodeListener, errorMessageListener, marketPriceMarginListener, volumeListener, buyerSecurityDepositInBTCListener; @@ -170,10 +170,11 @@ public abstract class MutableOfferView> exten private final List editOfferElements = new ArrayList<>(); private boolean clearXchangeWarningDisplayed, fasterPaymentsWarningDisplayed, isActivated; private InfoInputTextField marketBasedPriceInfoInputTextField, volumeInfoInputTextField, - buyerSecurityDepositInfoInputTextField; + buyerSecurityDepositInfoInputTextField, triggerPriceInfoInputTextField; private AutoTooltipSlideToggleButton tradeFeeInBtcToggle, tradeFeeInBsqToggle; private Text xIcon, fakeXIcon; + /////////////////////////////////////////////////////////////////////////////////////////// // Constructor, lifecycle /////////////////////////////////////////////////////////////////////////////////////////// @@ -237,7 +238,6 @@ public abstract class MutableOfferView> exten if (waitingForFundsSpinner != null) waitingForFundsSpinner.play(); - //directionLabel.setText(model.getDirectionLabel()); amountDescriptionLabel.setText(model.getAmountDescription()); addressTextField.setAddress(model.getAddressAsString()); addressTextField.setPaymentLabel(model.getPaymentLabel()); @@ -261,6 +261,9 @@ public abstract class MutableOfferView> exten tradeFeeInBsqToggle.setVisible(false); tradeFeeInBsqToggle.setManaged(false); } + + Label popOverLabel = OfferViewUtil.createPopOverLabel(Res.get("createOffer.triggerPrice.tooltip")); + triggerPriceInfoInputTextField.setContentForPopOver(popOverLabel, AwesomeIcon.SHIELD); } } @@ -305,14 +308,11 @@ public abstract class MutableOfferView> exten } if (direction == OfferPayload.Direction.BUY) { - placeOfferButton.setId("buy-button-big"); placeOfferButton.updateText(Res.get("createOffer.placeOfferButton", Res.get("shared.buy"))); - percentagePriceDescription.setText(Res.get("shared.belowInPercent")); } else { placeOfferButton.setId("sell-button-big"); placeOfferButton.updateText(Res.get("createOffer.placeOfferButton", Res.get("shared.sell"))); - percentagePriceDescription.setText(Res.get("shared.aboveInPercent")); } updatePriceToggle(); @@ -449,8 +449,8 @@ public abstract class MutableOfferView> exten private void updateOfferElementsStyle() { GridPane.setColumnSpan(firstRowHBox, 2); - final String activeInputStyle = "input-with-border"; - final String readOnlyInputStyle = "input-with-border-readonly"; + String activeInputStyle = "input-with-border"; + String readOnlyInputStyle = "input-with-border-readonly"; amountValueCurrencyBox.getStyleClass().remove(activeInputStyle); amountValueCurrencyBox.getStyleClass().add(readOnlyInputStyle); priceAsPercentageValueCurrencyBox.getStyleClass().remove(activeInputStyle); @@ -461,6 +461,12 @@ public abstract class MutableOfferView> exten priceValueCurrencyBox.getStyleClass().add(readOnlyInputStyle); minAmountValueCurrencyBox.getStyleClass().remove(activeInputStyle); minAmountValueCurrencyBox.getStyleClass().add(readOnlyInputStyle); + triggerPriceHBox.getStyleClass().remove(activeInputStyle); + triggerPriceHBox.getStyleClass().add(readOnlyInputStyle); + + GridPane.setColumnSpan(secondRowHBox, 1); + priceTypeToggleButton.setVisible(false); + HBox.setMargin(priceTypeToggleButton, new Insets(16, -14, 0, 0)); resultLabel.getStyleClass().add("small"); xLabel.getStyleClass().add("small"); @@ -542,7 +548,10 @@ public abstract class MutableOfferView> exten private void addBindings() { priceCurrencyLabel.textProperty().bind(createStringBinding(() -> CurrencyUtil.getCounterCurrency(model.tradeCurrencyCode.get()), model.tradeCurrencyCode)); - + triggerPriceCurrencyLabel.textProperty().bind(createStringBinding(() -> + CurrencyUtil.getCounterCurrency(model.tradeCurrencyCode.get()), model.tradeCurrencyCode)); + triggerPriceDescriptionLabel.textProperty().bind(model.triggerPriceDescription); + percentagePriceDescriptionLabel.textProperty().bind(model.percentagePriceDescription); marketBasedPriceLabel.prefWidthProperty().bind(priceCurrencyLabel.widthProperty()); volumeCurrencyLabel.textProperty().bind(model.tradeCurrencyCode); priceDescriptionLabel.textProperty().bind(createStringBinding(() -> CurrencyUtil.getPriceWithCurrencyCode(model.tradeCurrencyCode.get(), "shared.fixedPriceInCurForCur"), model.tradeCurrencyCode)); @@ -550,6 +559,7 @@ public abstract class MutableOfferView> exten amountTextField.textProperty().bindBidirectional(model.amount); minAmountTextField.textProperty().bindBidirectional(model.minAmount); fixedPriceTextField.textProperty().bindBidirectional(model.price); + triggerPriceInputTextField.textProperty().bindBidirectional(model.triggerPrice); marketBasedPriceTextField.textProperty().bindBidirectional(model.marketPriceMargin); volumeTextField.textProperty().bindBidirectional(model.volume); volumeTextField.promptTextProperty().bind(model.volumePromptLabel); @@ -568,6 +578,7 @@ public abstract class MutableOfferView> exten amountTextField.validationResultProperty().bind(model.amountValidationResult); minAmountTextField.validationResultProperty().bind(model.minAmountValidationResult); fixedPriceTextField.validationResultProperty().bind(model.priceValidationResult); + triggerPriceInputTextField.validationResultProperty().bind(model.triggerPriceValidationResult); volumeTextField.validationResultProperty().bind(model.volumeValidationResult); buyerSecurityDepositInputTextField.validationResultProperty().bind(model.buyerSecurityDepositValidationResult); @@ -590,16 +601,16 @@ public abstract class MutableOfferView> exten private void removeBindings() { priceCurrencyLabel.textProperty().unbind(); - fixedPriceTextField.disableProperty().unbind(); - priceCurrencyLabel.disableProperty().unbind(); - marketBasedPriceTextField.disableProperty().unbind(); - marketBasedPriceLabel.disableProperty().unbind(); + triggerPriceCurrencyLabel.textProperty().unbind(); + triggerPriceDescriptionLabel.textProperty().unbind(); + percentagePriceDescriptionLabel.textProperty().unbind(); volumeCurrencyLabel.textProperty().unbind(); priceDescriptionLabel.textProperty().unbind(); volumeDescriptionLabel.textProperty().unbind(); amountTextField.textProperty().unbindBidirectional(model.amount); minAmountTextField.textProperty().unbindBidirectional(model.minAmount); fixedPriceTextField.textProperty().unbindBidirectional(model.price); + triggerPriceInputTextField.textProperty().unbindBidirectional(model.triggerPrice); marketBasedPriceTextField.textProperty().unbindBidirectional(model.marketPriceMargin); marketBasedPriceLabel.prefWidthProperty().unbind(); volumeTextField.textProperty().unbindBidirectional(model.volume); @@ -619,6 +630,7 @@ public abstract class MutableOfferView> exten amountTextField.validationResultProperty().unbind(); minAmountTextField.validationResultProperty().unbind(); fixedPriceTextField.validationResultProperty().unbind(); + triggerPriceInputTextField.validationResultProperty().unbind(); volumeTextField.validationResultProperty().unbind(); buyerSecurityDepositInputTextField.validationResultProperty().unbind(); @@ -686,6 +698,11 @@ public abstract class MutableOfferView> exten buyerSecurityDepositInputTextField.setText(model.buyerSecurityDeposit.get()); }; + triggerPriceFocusedListener = (o, oldValue, newValue) -> { + model.onFocusOutTriggerPriceTextField(oldValue, newValue); + triggerPriceInputTextField.setText(model.triggerPrice.get()); + }; + errorMessageListener = (o, oldValue, newValue) -> { if (newValue != null) UserThread.runAfter(() -> new Popup().error(Res.get("createOffer.amountPriceBox.error.message", model.errorMessage.get())) @@ -699,6 +716,7 @@ public abstract class MutableOfferView> exten fixedPriceTextField.clear(); marketBasedPriceTextField.clear(); volumeTextField.clear(); + triggerPriceInputTextField.clear(); }; placeOfferCompletedListener = (o, oldValue, newValue) -> { @@ -743,7 +761,7 @@ public abstract class MutableOfferView> exten buyerSecurityDepositInBTCListener = (observable, oldValue, newValue) -> { if (!newValue.equals("")) { - Label depositInBTCInfo = createPopoverLabel(model.getSecurityDepositPopOverLabel(newValue)); + Label depositInBTCInfo = OfferViewUtil.createPopOverLabel(model.getSecurityDepositPopOverLabel(newValue)); buyerSecurityDepositInfoInputTextField.setContentForInfoPopOver(depositInBTCInfo); } else { buyerSecurityDepositInfoInputTextField.setContentForInfoPopOver(null); @@ -752,9 +770,10 @@ public abstract class MutableOfferView> exten volumeListener = (observable, oldValue, newValue) -> { if (!newValue.equals("") && CurrencyUtil.isFiatCurrency(model.tradeCurrencyCode.get())) { - volumeInfoInputTextField.setContentForPrivacyPopOver(createPopoverLabel(Res.get("offerbook.info.roundedFiatVolume"))); + Label popOverLabel = OfferViewUtil.createPopOverLabel(Res.get("offerbook.info.roundedFiatVolume")); + volumeInfoInputTextField.setContentForPrivacyPopOver(popOverLabel); } else { - volumeInfoInputTextField.hideInfoContent(); + volumeInfoInputTextField.hideIcon(); } }; @@ -780,7 +799,7 @@ public abstract class MutableOfferView> exten } else { tooltip = Res.get("createOffer.info.buyAtMarketPrice"); } - final Label atMarketPriceLabel = createPopoverLabel(tooltip); + final Label atMarketPriceLabel = OfferViewUtil.createPopOverLabel(tooltip); marketBasedPriceInfoInputTextField.setContentForInfoPopOver(atMarketPriceLabel); } else if (newValue.contains("-")) { if (model.isSellOffer()) { @@ -788,7 +807,7 @@ public abstract class MutableOfferView> exten } else { tooltip = Res.get("createOffer.warning.buyAboveMarketPrice", newValue.substring(1)); } - final Label negativePercentageLabel = createPopoverLabel(tooltip); + final Label negativePercentageLabel = OfferViewUtil.createPopOverLabel(tooltip); marketBasedPriceInfoInputTextField.setContentForWarningPopOver(negativePercentageLabel); } else if (!newValue.equals("")) { if (model.isSellOffer()) { @@ -796,7 +815,7 @@ public abstract class MutableOfferView> exten } else { tooltip = Res.get("createOffer.info.buyBelowMarketPrice", newValue); } - Label positivePercentageLabel = createPopoverLabel(tooltip); + Label positivePercentageLabel = OfferViewUtil.createPopOverLabel(tooltip); marketBasedPriceInfoInputTextField.setContentForInfoPopOver(positivePercentageLabel); } } @@ -850,14 +869,6 @@ public abstract class MutableOfferView> exten } } - private Label createPopoverLabel(String text) { - final Label label = new Label(text); - label.setPrefWidth(300); - label.setWrapText(true); - label.setPadding(new Insets(10)); - return label; - } - protected void updatePriceToggle() { int marketPriceAvailableValue = model.marketPriceAvailableProperty.get(); if (marketPriceAvailableValue > -1) { @@ -887,6 +898,7 @@ public abstract class MutableOfferView> exten amountTextField.focusedProperty().addListener(amountFocusedListener); minAmountTextField.focusedProperty().addListener(minAmountFocusedListener); fixedPriceTextField.focusedProperty().addListener(priceFocusedListener); + triggerPriceInputTextField.focusedProperty().addListener(triggerPriceFocusedListener); marketBasedPriceTextField.focusedProperty().addListener(priceAsPercentageFocusedListener); volumeTextField.focusedProperty().addListener(volumeFocusedListener); buyerSecurityDepositInputTextField.focusedProperty().addListener(buyerSecurityDepositFocusedListener); @@ -921,6 +933,7 @@ public abstract class MutableOfferView> exten amountTextField.focusedProperty().removeListener(amountFocusedListener); minAmountTextField.focusedProperty().removeListener(minAmountFocusedListener); fixedPriceTextField.focusedProperty().removeListener(priceFocusedListener); + triggerPriceInputTextField.focusedProperty().removeListener(triggerPriceFocusedListener); marketBasedPriceTextField.focusedProperty().removeListener(priceAsPercentageFocusedListener); volumeTextField.focusedProperty().removeListener(volumeFocusedListener); buyerSecurityDepositInputTextField.focusedProperty().removeListener(buyerSecurityDepositFocusedListener); @@ -1294,10 +1307,10 @@ public abstract class MutableOfferView> exten marketBasedPriceLabel = priceAsPercentageTuple.third; editOfferElements.add(marketBasedPriceLabel); Tuple2 priceAsPercentageInputBoxTuple = getTradeInputBox(priceAsPercentageValueCurrencyBox, - Res.get("shared.distanceInPercent")); - percentagePriceDescription = priceAsPercentageInputBoxTuple.first; + model.getPercentagePriceDescription()); + percentagePriceDescriptionLabel = priceAsPercentageInputBoxTuple.first; - getSmallIconForLabel(MaterialDesignIcon.CHART_LINE, percentagePriceDescription, "small-icon-label"); + getSmallIconForLabel(MaterialDesignIcon.CHART_LINE, percentagePriceDescriptionLabel, "small-icon-label"); percentagePriceBox = priceAsPercentageInputBoxTuple.second; @@ -1356,6 +1369,9 @@ public abstract class MutableOfferView> exten if (!secondRowHBox.getChildren().contains(fixedPriceBox)) secondRowHBox.getChildren().add(2, fixedPriceBox); } + + triggerPriceVBox.setVisible(!fixedPriceSelected); + model.onFixPriceToggleChange(fixedPriceSelected); } private void addSecondRow() { @@ -1387,7 +1403,6 @@ public abstract class MutableOfferView> exten Tuple2 amountInputBoxTuple = getTradeInputBox(minAmountValueCurrencyBox, Res.get("createOffer.amountPriceBox.minAmountDescription")); - fakeXLabel = new Label(); fakeXIcon = getIconForLabel(MaterialDesignIcon.CLOSE, "2em", fakeXLabel); fakeXLabel.getStyleClass().add("opaque-icon-character"); @@ -1396,16 +1411,28 @@ public abstract class MutableOfferView> exten // Fixed/Percentage toggle priceTypeToggleButton = getIconButton(MaterialDesignIcon.SWAP_VERTICAL); editOfferElements.add(priceTypeToggleButton); - HBox.setMargin(priceTypeToggleButton, new Insets(16, 0, 0, 0)); - + HBox.setMargin(priceTypeToggleButton, new Insets(16, 1.5, 0, 0)); priceTypeToggleButton.setOnAction((actionEvent) -> updatePriceToggleButtons(model.getDataModel().getUseMarketBasedPrice().getValue())); - secondRowHBox = new HBox(); + // triggerPrice + Tuple3 triggerPriceTuple3 = getEditableValueBoxWithInfo(Res.get("createOffer.triggerPrice.prompt")); + triggerPriceHBox = triggerPriceTuple3.first; + triggerPriceInfoInputTextField = triggerPriceTuple3.second; + editOfferElements.add(triggerPriceInfoInputTextField); + triggerPriceInputTextField = triggerPriceInfoInputTextField.getInputTextField(); + triggerPriceCurrencyLabel = triggerPriceTuple3.third; + editOfferElements.add(triggerPriceCurrencyLabel); + Tuple2 triggerPriceTuple2 = getTradeInputBox(triggerPriceHBox, model.getTriggerPriceDescriptionLabel()); + triggerPriceDescriptionLabel = triggerPriceTuple2.first; + triggerPriceDescriptionLabel.setPrefWidth(290); + triggerPriceVBox = triggerPriceTuple2.second; + secondRowHBox = new HBox(); secondRowHBox.setSpacing(5); secondRowHBox.setAlignment(Pos.CENTER_LEFT); - secondRowHBox.getChildren().addAll(amountInputBoxTuple.second, fakeXLabel, fixedPriceBox, priceTypeToggleButton); + secondRowHBox.getChildren().addAll(amountInputBoxTuple.second, fakeXLabel, fixedPriceBox, priceTypeToggleButton, triggerPriceVBox); + GridPane.setColumnSpan(secondRowHBox, 2); GridPane.setRowIndex(secondRowHBox, ++gridRow); GridPane.setColumnIndex(secondRowHBox, 0); GridPane.setMargin(secondRowHBox, new Insets(0, 10, 10, 0)); diff --git a/desktop/src/main/java/bisq/desktop/main/offer/MutableOfferViewModel.java b/desktop/src/main/java/bisq/desktop/main/offer/MutableOfferViewModel.java index 0b0566988b..8d435ede85 100644 --- a/desktop/src/main/java/bisq/desktop/main/offer/MutableOfferViewModel.java +++ b/desktop/src/main/java/bisq/desktop/main/offer/MutableOfferViewModel.java @@ -20,6 +20,7 @@ package bisq.desktop.main.offer; import bisq.desktop.Navigation; import bisq.desktop.common.model.ActivatableWithDataModel; import bisq.desktop.main.MainView; +import bisq.desktop.main.PriceUtil; import bisq.desktop.main.funds.FundsView; import bisq.desktop.main.funds.deposit.DepositView; import bisq.desktop.main.overlays.popups.Popup; @@ -124,6 +125,7 @@ public abstract class MutableOfferViewModel ext // The domain (dataModel) uses always the same price model (otherCurrencyBTC) // If we would change the price representation in the domain we would not be backward compatible public final StringProperty price = new SimpleStringProperty(); + public final StringProperty triggerPrice = new SimpleStringProperty(""); final StringProperty tradeFee = new SimpleStringProperty(); final StringProperty tradeFeeInBtcWithFiat = new SimpleStringProperty(); final StringProperty tradeFeeInBsqWithFiat = new SimpleStringProperty(); @@ -143,6 +145,8 @@ public abstract class MutableOfferViewModel ext final StringProperty errorMessage = new SimpleStringProperty(); final StringProperty tradeCurrencyCode = new SimpleStringProperty(); final StringProperty waitingForFundsText = new SimpleStringProperty(""); + final StringProperty triggerPriceDescription = new SimpleStringProperty(""); + final StringProperty percentagePriceDescription = new SimpleStringProperty(""); final BooleanProperty isPlaceOfferButtonDisabled = new SimpleBooleanProperty(true); final BooleanProperty cancelButtonDisabled = new SimpleBooleanProperty(); @@ -156,6 +160,7 @@ public abstract class MutableOfferViewModel ext final ObjectProperty amountValidationResult = new SimpleObjectProperty<>(); final ObjectProperty minAmountValidationResult = new SimpleObjectProperty<>(); final ObjectProperty priceValidationResult = new SimpleObjectProperty<>(); + final ObjectProperty triggerPriceValidationResult = new SimpleObjectProperty<>(new InputValidator.ValidationResult(true)); final ObjectProperty volumeValidationResult = new SimpleObjectProperty<>(); final ObjectProperty buyerSecurityDepositValidationResult = new SimpleObjectProperty<>(); @@ -231,7 +236,7 @@ public abstract class MutableOfferViewModel ext if (DevEnv.isDevMode()) { UserThread.runAfter(() -> { amount.set("0.001"); - price.set("70000"); + price.set("210000"); minAmount.set(amount.get()); onFocusOutPriceAsPercentageTextField(true, false); applyMakerFee(); @@ -277,12 +282,15 @@ public abstract class MutableOfferViewModel ext totalToPay.bind(createStringBinding(() -> btcFormatter.formatCoinWithCode(dataModel.totalToPayAsCoinProperty().get()), dataModel.totalToPayAsCoinProperty())); - tradeAmount.bind(createStringBinding(() -> btcFormatter.formatCoinWithCode(dataModel.getAmount().get()), dataModel.getAmount())); - tradeCurrencyCode.bind(dataModel.getTradeCurrencyCode()); + + triggerPriceDescription.bind(createStringBinding(this::getTriggerPriceDescriptionLabel, + dataModel.getTradeCurrencyCode())); + percentagePriceDescription.bind(createStringBinding(this::getPercentagePriceDescription, + dataModel.getTradeCurrencyCode())); } private void removeBindings() { @@ -291,6 +299,8 @@ public abstract class MutableOfferViewModel ext tradeCurrencyCode.unbind(); volumeDescriptionLabel.unbind(); volumePromptLabel.unbind(); + triggerPriceDescription.unbind(); + percentagePriceDescription.unbind(); } private void createListeners() { @@ -769,12 +779,49 @@ public abstract class MutableOfferViewModel ext } } + void onFocusOutTriggerPriceTextField(boolean oldValue, boolean newValue) { + if (oldValue && !newValue) { + onTriggerPriceTextFieldChanged(); + } + } + + public void onTriggerPriceTextFieldChanged() { + String triggerPriceAsString = triggerPrice.get(); + + // Error field does not update if there was an error and then another different error + // if not reset here. Not clear why... + triggerPriceValidationResult.set(new InputValidator.ValidationResult(true)); + + InputValidator.ValidationResult result = PriceUtil.isTriggerPriceValid(triggerPriceAsString, + dataModel.getPrice().get(), + dataModel.isSellOffer(), + dataModel.isFiatCurrency()); + triggerPriceValidationResult.set(result); + updateButtonDisableState(); + if (result.isValid) { + // In case of 0 or empty string we set the string to empty string and data value to 0 + long triggerPriceAsLong = PriceUtil.getMarketPriceAsLong(triggerPriceAsString, dataModel.getCurrencyCode()); + dataModel.setTriggerPrice(triggerPriceAsLong); + if (dataModel.getTriggerPrice() == 0) { + triggerPrice.set(""); + } else { + triggerPrice.set(PriceUtil.formatMarketPrice(dataModel.getTriggerPrice(), dataModel.getCurrencyCode())); + } + } + } + + void onFixPriceToggleChange(boolean fixedPriceSelected) { + updateButtonDisableState(); + if (!fixedPriceSelected) { + onTriggerPriceTextFieldChanged(); + } + } + void onFocusOutPriceTextField(boolean oldValue, boolean newValue) { if (oldValue && !newValue) { InputValidator.ValidationResult result = isPriceInputValid(price.get()); - boolean isValid = result.isValid; priceValidationResult.set(result); - if (isValid) { + if (result.isValid) { setPriceToModel(); ignorePriceStringListener = true; if (dataModel.getPrice().get() != null) @@ -808,8 +855,11 @@ public abstract class MutableOfferViewModel ext marketPriceMargin.set(FormattingUtils.formatRoundedDoubleWithPrecision(dataModel.getMarketPriceMargin() * 100, 2)); } - // We want to trigger a recalculation of the volume - UserThread.execute(() -> onFocusOutVolumeTextField(true, false)); + // We want to trigger a recalculation of the volume, as well as update trigger price validation + UserThread.execute(() -> { + onFocusOutVolumeTextField(true, false); + onTriggerPriceTextFieldChanged(); + }); } void onFocusOutVolumeTextField(boolean oldValue, boolean newValue) { @@ -1052,6 +1102,33 @@ public abstract class MutableOfferViewModel ext return dataModel; } + String getTriggerPriceDescriptionLabel() { + String details; + if (dataModel.isBuyOffer()) { + details = dataModel.isCryptoCurrency() ? + Res.get("account.notifications.marketAlert.message.msg.below") : + Res.get("account.notifications.marketAlert.message.msg.above"); + } else { + details = dataModel.isCryptoCurrency() ? + Res.get("account.notifications.marketAlert.message.msg.above") : + Res.get("account.notifications.marketAlert.message.msg.below"); + } + return Res.get("createOffer.triggerPrice.label", details); + } + + String getPercentagePriceDescription() { + if (dataModel.isBuyOffer()) { + return dataModel.isCryptoCurrency() ? + Res.get("shared.aboveInPercent") : + Res.get("shared.belowInPercent"); + } else { + return dataModel.isCryptoCurrency() ? + Res.get("shared.belowInPercent") : + Res.get("shared.aboveInPercent"); + } + } + + /////////////////////////////////////////////////////////////////////////////////////////// // Utils /////////////////////////////////////////////////////////////////////////////////////////// @@ -1195,8 +1272,7 @@ public abstract class MutableOfferViewModel ext } } - private void updateButtonDisableState() { - log.debug("updateButtonDisableState"); + void updateButtonDisableState() { boolean inputDataValid = isBtcInputValid(amount.get()).isValid && isBtcInputValid(minAmount.get()).isValid && isPriceInputValid(price.get()).isValid && @@ -1206,6 +1282,10 @@ public abstract class MutableOfferViewModel ext isVolumeInputValid(DisplayUtils.formatVolume(dataModel.getMinVolume().get())).isValid && dataModel.isMinAmountLessOrEqualAmount(); + if (dataModel.useMarketBasedPrice.get() && dataModel.isMarketPriceAvailable()) { + inputDataValid = inputDataValid && triggerPriceValidationResult.get().isValid; + } + // validating the percentage deposit value only makes sense if it is actually used if (!dataModel.isMinBuyerSecurityDeposit()) { inputDataValid = inputDataValid && securityDepositValidator.validate(buyerSecurityDeposit.get()).isValid; diff --git a/desktop/src/main/java/bisq/desktop/main/offer/OfferViewUtil.java b/desktop/src/main/java/bisq/desktop/main/offer/OfferViewUtil.java new file mode 100644 index 0000000000..dfd6a37580 --- /dev/null +++ b/desktop/src/main/java/bisq/desktop/main/offer/OfferViewUtil.java @@ -0,0 +1,36 @@ +/* + * This file is part of Bisq. + * + * Bisq is free software: you can redistribute it and/or modify it + * under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or (at + * your option) any later version. + * + * Bisq is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public + * License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with Bisq. If not, see . + */ + +package bisq.desktop.main.offer; + +import javafx.scene.control.Label; + +import javafx.geometry.Insets; + +/** + * Reusable methods for CreateOfferView, TakeOfferView or other related views + */ +public class OfferViewUtil { + public static Label createPopOverLabel(String text) { + final Label label = new Label(text); + label.setPrefWidth(300); + label.setWrapText(true); + label.setLineSpacing(1); + label.setPadding(new Insets(10)); + return label; + } +} diff --git a/desktop/src/main/java/bisq/desktop/main/offer/offerbook/OfferBookView.java b/desktop/src/main/java/bisq/desktop/main/offer/offerbook/OfferBookView.java index e1133a16b2..caa01deea4 100644 --- a/desktop/src/main/java/bisq/desktop/main/offer/offerbook/OfferBookView.java +++ b/desktop/src/main/java/bisq/desktop/main/offer/offerbook/OfferBookView.java @@ -22,6 +22,7 @@ import bisq.desktop.common.view.ActivatableViewAndModel; import bisq.desktop.common.view.FxmlView; import bisq.desktop.components.AutoTooltipButton; import bisq.desktop.components.AutoTooltipLabel; +import bisq.desktop.components.AutoTooltipSlideToggleButton; import bisq.desktop.components.AutoTooltipTableColumn; import bisq.desktop.components.AutocompleteComboBox; import bisq.desktop.components.ColoredDecimalPlacesWithZerosText; @@ -51,6 +52,7 @@ import bisq.core.locale.Res; import bisq.core.locale.TradeCurrency; import bisq.core.monetary.Price; import bisq.core.offer.Offer; +import bisq.core.offer.OfferFilter; import bisq.core.offer.OfferPayload; import bisq.core.offer.OfferRestrictions; import bisq.core.payment.PaymentAccount; @@ -61,6 +63,7 @@ import bisq.core.util.coin.CoinFormatter; import bisq.network.p2p.NodeAddress; +import bisq.common.app.DevEnv; import bisq.common.config.Config; import bisq.common.util.Tuple3; @@ -126,6 +129,7 @@ public class OfferBookView extends ActivatableViewAndModel currencyComboBox; private AutocompleteComboBox paymentMethodComboBox; private AutoTooltipButton createOfferButton; + private AutoTooltipSlideToggleButton matchingOffersToggle; private AutoTooltipTableColumn amountColumn, volumeColumn, marketColumn, priceColumn, paymentMethodColumn, depositColumn, signingStateColumn, avatarColumn; private TableView tableView; @@ -174,10 +178,25 @@ public class OfferBookView extends ActivatableViewAndModel> currencyBoxTuple = FormBuilder.addTopLabelAutocompleteComboBox( + Tuple3> currencyBoxTuple = FormBuilder.addTopLabelAutocompleteComboBox( Res.get("offerbook.filterByCurrency")); - final Tuple3> paymentBoxTuple = FormBuilder.addTopLabelAutocompleteComboBox( + currencyComboBox = currencyBoxTuple.third; + currencyComboBox.setPrefWidth(270); + + Tuple3> paymentBoxTuple = FormBuilder.addTopLabelAutocompleteComboBox( Res.get("offerbook.filterByPaymentMethod")); + paymentMethodComboBox = paymentBoxTuple.third; + paymentMethodComboBox.setCellFactory(GUIUtil.getPaymentMethodCellFactory()); + paymentMethodComboBox.setPrefWidth(270); + + matchingOffersToggle = new AutoTooltipSlideToggleButton(); + matchingOffersToggle.setText(Res.get("offerbook.matchingOffers")); + HBox.setMargin(matchingOffersToggle, new Insets(7, 0, -9, -15)); + + hBox.getChildren().addAll(currencyBoxTuple.first, paymentBoxTuple.first, matchingOffersToggle); + AnchorPane.setLeftAnchor(hBox, 0d); + AnchorPane.setTopAnchor(hBox, 0d); + AnchorPane.setBottomAnchor(hBox, 0d); createOfferButton = new AutoTooltipButton(); createOfferButton.setMinHeight(40); @@ -185,11 +204,6 @@ public class OfferBookView extends ActivatableViewAndModel(); GridPane.setRowIndex(tableView, ++gridRow); @@ -324,13 +333,14 @@ public class OfferBookView extends ActivatableViewAndModel model.onShowOffersMatchingMyAccounts(matchingOffersToggle.isSelected())); + volumeColumn.sortableProperty().bind(model.showAllTradeCurrenciesProperty.not()); model.getOfferList().comparatorProperty().bind(tableView.comparatorProperty()); @@ -359,6 +369,7 @@ public class OfferBookView extends ActivatableViewAndModel account = model.getMostMaturePaymentAccountForOffer(offer); - if (account.isPresent()) { - final long tradeLimit = model.accountAgeWitnessService.getMyTradeLimit(account.get(), - offer.getCurrencyCode(), offer.getMirroredDirection()); - new Popup() - .warning(Res.get("popup.warning.tradeLimitDueAccountAgeRestriction.buyer", - formatter.formatCoinWithCode(Coin.valueOf(tradeLimit)), - Res.get("offerbook.warning.newVersionAnnouncement"))) - .show(); - } else { - log.warn("We don't found a payment account but got called the isInsufficientTradeLimit case. That must not happen."); - } + private void onShowInfo(Offer offer, OfferFilter.Result result) { + switch (result) { + case VALID: + break; + case API_DISABLED: + DevEnv.logErrorAndThrowIfDevMode("We are in desktop and in the taker position " + + "viewing offers, so it cannot be that we got that result as we are not an API user."); + break; + case HAS_NO_PAYMENT_ACCOUNT_VALID_FOR_OFFER: + openPopupForMissingAccountSetup(Res.get("offerbook.warning.noMatchingAccount.headline"), + Res.get("offerbook.warning.noMatchingAccount.msg"), + FiatAccountsView.class, + "navigation.account"); + break; + case HAS_NOT_SAME_PROTOCOL_VERSION: + new Popup().warning(Res.get("offerbook.warning.wrongTradeProtocol")).show(); + break; + case IS_IGNORED: + new Popup().warning(Res.get("offerbook.warning.userIgnored")).show(); + break; + case IS_OFFER_BANNED: + new Popup().warning(Res.get("offerbook.warning.offerBlocked")).show(); + break; + case IS_CURRENCY_BANNED: + new Popup().warning(Res.get("offerbook.warning.currencyBanned")).show(); + break; + case IS_PAYMENT_METHOD_BANNED: + new Popup().warning(Res.get("offerbook.warning.paymentMethodBanned")).show(); + break; + case IS_NODE_ADDRESS_BANNED: + new Popup().warning(Res.get("offerbook.warning.nodeBlocked")).show(); + break; + case REQUIRE_UPDATE_TO_NEW_VERSION: + new Popup().warning(Res.get("offerbook.warning.requireUpdateToNewVersion")).show(); + break; + case IS_INSUFFICIENT_COUNTERPARTY_TRADE_LIMIT: + new Popup().warning(Res.get("offerbook.warning.counterpartyTradeRestrictions")).show(); + break; + case IS_MY_INSUFFICIENT_TRADE_LIMIT: + Optional account = model.getMostMaturePaymentAccountForOffer(offer); + if (account.isPresent()) { + long tradeLimit = model.accountAgeWitnessService.getMyTradeLimit(account.get(), + offer.getCurrencyCode(), offer.getMirroredDirection()); + new Popup() + .warning(Res.get("popup.warning.tradeLimitDueAccountAgeRestriction.buyer", + formatter.formatCoinWithCode(Coin.valueOf(tradeLimit)), + Res.get("offerbook.warning.newVersionAnnouncement"))) + .show(); + } else { + DevEnv.logErrorAndThrowIfDevMode("We don't found a payment account but got called the " + + "isInsufficientTradeLimit case."); + } + break; + default: + break; } } @@ -996,11 +1027,7 @@ public class OfferBookView extends ActivatableViewAndModel() { final ImageView iconView = new ImageView(); final AutoTooltipButton button = new AutoTooltipButton(); - boolean isTradable, isPaymentAccountValidForOffer, - isInsufficientCounterpartyTradeLimit, - hasSameProtocolVersion, isIgnored, isOfferBanned, isCurrencyBanned, - isPaymentMethodBanned, isNodeAddressBanned, isMyInsufficientTradeLimit, - requireUpdateToNewVersion; + OfferFilter.Result canTakeOfferResult = null; { button.setGraphic(iconView); @@ -1015,33 +1042,14 @@ public class OfferBookView extends ActivatableViewAndModel tableRow = getTableRow(); if (item != null && !empty) { - final Offer offer = item.getOffer(); + Offer offer = item.getOffer(); boolean myOffer = model.isMyOffer(offer); + if (tableRow != null) { - isPaymentAccountValidForOffer = model.isAnyPaymentAccountValidForOffer(offer); - isInsufficientCounterpartyTradeLimit = model.isInsufficientCounterpartyTradeLimit(offer); - hasSameProtocolVersion = model.hasSameProtocolVersion(offer); - isIgnored = model.isIgnored(offer); - isOfferBanned = model.isOfferBanned(offer); - isCurrencyBanned = model.isCurrencyBanned(offer); - isPaymentMethodBanned = model.isPaymentMethodBanned(offer); - isNodeAddressBanned = model.isNodeAddressBanned(offer); - requireUpdateToNewVersion = model.requireUpdateToNewVersion(); - isMyInsufficientTradeLimit = model.isMyInsufficientTradeLimit(offer); - isTradable = isPaymentAccountValidForOffer && - !isInsufficientCounterpartyTradeLimit && - hasSameProtocolVersion && - !isIgnored && - !isOfferBanned && - !isCurrencyBanned && - !isPaymentMethodBanned && - !isNodeAddressBanned && - !requireUpdateToNewVersion && - !isMyInsufficientTradeLimit; + canTakeOfferResult = model.offerFilter.canTakeOffer(offer, false); + tableRow.setOpacity(canTakeOfferResult.isValid() || myOffer ? 1 : 0.4); - tableRow.setOpacity(isTradable || myOffer ? 1 : 0.4); - - if (isTradable) { + if (canTakeOfferResult.isValid()) { // set first row button as default button.setDefaultButton(getIndex() == 0); tableRow.setOnMousePressed(null); @@ -1050,17 +1058,7 @@ public class OfferBookView extends ActivatableViewAndModel { // ugly hack to get the icon clickable when deactivated if (!(e.getTarget() instanceof ImageView || e.getTarget() instanceof Canvas)) - onShowInfo(offer, - isPaymentAccountValidForOffer, - isInsufficientCounterpartyTradeLimit, - hasSameProtocolVersion, - isIgnored, - isOfferBanned, - isCurrencyBanned, - isPaymentMethodBanned, - isNodeAddressBanned, - requireUpdateToNewVersion, - isMyInsufficientTradeLimit); + onShowInfo(offer, canTakeOfferResult); }); } } @@ -1090,18 +1088,15 @@ public class OfferBookView extends ActivatableViewAndModel onTakeOffer(offer)); } - if (!myOffer && !isTradable) - button.setOnAction(e -> onShowInfo(offer, - isPaymentAccountValidForOffer, - isInsufficientCounterpartyTradeLimit, - hasSameProtocolVersion, - isIgnored, - isOfferBanned, - isCurrencyBanned, - isPaymentMethodBanned, - isNodeAddressBanned, - requireUpdateToNewVersion, - isMyInsufficientTradeLimit)); + if (!myOffer) { + if (canTakeOfferResult == null) { + canTakeOfferResult = model.offerFilter.canTakeOffer(offer, false); + } + + if (!canTakeOfferResult.isValid()) { + button.setOnAction(e -> onShowInfo(offer, canTakeOfferResult)); + } + } button.updateText(title); setPadding(new Insets(0, 15, 0, 0)); diff --git a/desktop/src/main/java/bisq/desktop/main/offer/offerbook/OfferBookViewModel.java b/desktop/src/main/java/bisq/desktop/main/offer/offerbook/OfferBookViewModel.java index 2216cfd8c4..6e0ddd0fa3 100644 --- a/desktop/src/main/java/bisq/desktop/main/offer/offerbook/OfferBookViewModel.java +++ b/desktop/src/main/java/bisq/desktop/main/offer/offerbook/OfferBookViewModel.java @@ -20,6 +20,7 @@ package bisq.desktop.main.offer.offerbook; import bisq.desktop.Navigation; import bisq.desktop.common.model.ActivatableViewModel; import bisq.desktop.main.MainView; +import bisq.desktop.main.PriceUtil; import bisq.desktop.main.settings.SettingsView; import bisq.desktop.main.settings.preferences.PreferencesView; import bisq.desktop.util.DisplayUtils; @@ -27,7 +28,6 @@ import bisq.desktop.util.GUIUtil; import bisq.core.account.witness.AccountAgeWitnessService; import bisq.core.btc.setup.WalletsSetup; -import bisq.core.filter.FilterManager; import bisq.core.locale.BankUtil; import bisq.core.locale.CountryUtil; import bisq.core.locale.CryptoCurrency; @@ -35,23 +35,20 @@ import bisq.core.locale.CurrencyUtil; import bisq.core.locale.GlobalSettings; import bisq.core.locale.Res; import bisq.core.locale.TradeCurrency; -import bisq.core.monetary.Altcoin; import bisq.core.monetary.Price; import bisq.core.monetary.Volume; import bisq.core.offer.Offer; +import bisq.core.offer.OfferFilter; import bisq.core.offer.OfferPayload; import bisq.core.offer.OpenOfferManager; import bisq.core.payment.PaymentAccount; import bisq.core.payment.PaymentAccountUtil; import bisq.core.payment.payload.PaymentMethod; -import bisq.core.provider.price.MarketPrice; import bisq.core.provider.price.PriceFeedService; import bisq.core.trade.Trade; import bisq.core.trade.closed.ClosedTradableManager; -import bisq.core.trade.statistics.TradeStatisticsManager; import bisq.core.user.Preferences; import bisq.core.user.User; -import bisq.core.util.AveragePriceUtil; import bisq.core.util.FormattingUtils; import bisq.core.util.coin.BsqFormatter; import bisq.core.util.coin.CoinFormatter; @@ -59,13 +56,10 @@ import bisq.core.util.coin.CoinFormatter; import bisq.network.p2p.NodeAddress; import bisq.network.p2p.P2PService; -import bisq.common.app.Version; import bisq.common.handlers.ErrorMessageHandler; import bisq.common.handlers.ResultHandler; -import bisq.common.util.MathUtils; import org.bitcoinj.core.Coin; -import org.bitcoinj.utils.Fiat; import com.google.inject.Inject; @@ -92,14 +86,12 @@ import java.util.Comparator; import java.util.List; import java.util.Map; import java.util.Optional; +import java.util.Set; +import java.util.function.Predicate; import java.util.stream.Collectors; import lombok.extern.slf4j.Slf4j; -import javax.annotation.Nullable; - -import static com.google.common.base.Preconditions.checkNotNull; - @Slf4j class OfferBookViewModel extends ActivatableViewModel { private final OpenOfferManager openOfferManager; @@ -110,10 +102,10 @@ class OfferBookViewModel extends ActivatableViewModel { private final P2PService p2PService; final PriceFeedService priceFeedService; private final ClosedTradableManager closedTradableManager; - private final FilterManager filterManager; final AccountAgeWitnessService accountAgeWitnessService; private final Navigation navigation; - private final TradeStatisticsManager tradeStatisticsManager; + private final PriceUtil priceUtil; + final OfferFilter offerFilter; private final CoinFormatter btcFormatter; private final BsqFormatter bsqFormatter; @@ -130,17 +122,17 @@ class OfferBookViewModel extends ActivatableViewModel { // If id is empty string we ignore filter (display all methods) - PaymentMethod selectedPaymentMethod = PaymentMethod.getDummyPaymentMethod(GUIUtil.SHOW_ALL_FLAG); + PaymentMethod selectedPaymentMethod = getShowAllEntryForPaymentMethod(); private boolean isTabSelected; final BooleanProperty showAllTradeCurrenciesProperty = new SimpleBooleanProperty(true); + final BooleanProperty disableMatchToggle = new SimpleBooleanProperty(); final IntegerProperty maxPlacesForAmount = new SimpleIntegerProperty(); final IntegerProperty maxPlacesForVolume = new SimpleIntegerProperty(); final IntegerProperty maxPlacesForPrice = new SimpleIntegerProperty(); final IntegerProperty maxPlacesForMarketPriceMargin = new SimpleIntegerProperty(); boolean showAllPaymentMethods = true; - @Nullable - private Price bsq30DayAveragePrice; + boolean useOffersMatchingMyAccountsFilter; /////////////////////////////////////////////////////////////////////////////////////////// @@ -156,10 +148,10 @@ class OfferBookViewModel extends ActivatableViewModel { P2PService p2PService, PriceFeedService priceFeedService, ClosedTradableManager closedTradableManager, - FilterManager filterManager, AccountAgeWitnessService accountAgeWitnessService, Navigation navigation, - TradeStatisticsManager tradeStatisticsManager, + PriceUtil priceUtil, + OfferFilter offerFilter, @Named(FormattingUtils.BTC_FORMATTER_KEY) CoinFormatter btcFormatter, BsqFormatter bsqFormatter) { super(); @@ -172,10 +164,10 @@ class OfferBookViewModel extends ActivatableViewModel { this.p2PService = p2PService; this.priceFeedService = priceFeedService; this.closedTradableManager = closedTradableManager; - this.filterManager = filterManager; this.accountAgeWitnessService = accountAgeWitnessService; this.navigation = navigation; - this.tradeStatisticsManager = tradeStatisticsManager; + this.priceUtil = priceUtil; + this.offerFilter = offerFilter; this.btcFormatter = btcFormatter; this.bsqFormatter = bsqFormatter; @@ -223,7 +215,7 @@ class OfferBookViewModel extends ActivatableViewModel { filteredItems.addListener(filterItemsListener); String code = direction == OfferPayload.Direction.BUY ? preferences.getBuyScreenCurrencyCode() : preferences.getSellScreenCurrencyCode(); - if (code != null && !code.equals(GUIUtil.SHOW_ALL_FLAG) && !code.isEmpty() && + if (code != null && !code.isEmpty() && !isShowAllEntry(code) && CurrencyUtil.getTradeCurrency(code).isPresent()) { showAllTradeCurrenciesProperty.set(false); selectedTradeCurrency = CurrencyUtil.getTradeCurrency(code).get(); @@ -233,18 +225,18 @@ class OfferBookViewModel extends ActivatableViewModel { } tradeCurrencyCode.set(selectedTradeCurrency.getCode()); + if (user != null) { + disableMatchToggle.set(user.getPaymentAccounts() == null || user.getPaymentAccounts().isEmpty()); + } + useOffersMatchingMyAccountsFilter = !disableMatchToggle.get() && isShowOffersMatchingMyAccounts(); + fillAllTradeCurrencies(); preferences.getTradeCurrenciesAsObservable().addListener(tradeCurrencyListChangeListener); offerBook.fillOfferBookListItems(); - applyFilterPredicate(); + filterOffers(); setMarketPriceFeedCurrency(); - // Null check needed for tests passing null for tradeStatisticsManager - if (tradeStatisticsManager != null) { - bsq30DayAveragePrice = AveragePriceUtil.getAveragePriceTuple(preferences, - tradeStatisticsManager, - 30).second; - } + priceUtil.recalculateBsq30DayAveragePrice(); } @Override @@ -253,6 +245,7 @@ class OfferBookViewModel extends ActivatableViewModel { preferences.getTradeCurrenciesAsObservable().removeListener(tradeCurrencyListChangeListener); } + /////////////////////////////////////////////////////////////////////////////////////////// // API /////////////////////////////////////////////////////////////////////////////////////////// @@ -283,7 +276,7 @@ class OfferBookViewModel extends ActivatableViewModel { } setMarketPriceFeedCurrency(); - applyFilterPredicate(); + filterOffers(); if (direction == OfferPayload.Direction.BUY) preferences.setBuyScreenCurrencyCode(code); @@ -297,22 +290,40 @@ class OfferBookViewModel extends ActivatableViewModel { return; showAllPaymentMethods = isShowAllEntry(paymentMethod.getId()); - if (!showAllPaymentMethods) + if (!showAllPaymentMethods) { this.selectedPaymentMethod = paymentMethod; - else - this.selectedPaymentMethod = PaymentMethod.getDummyPaymentMethod(GUIUtil.SHOW_ALL_FLAG); - applyFilterPredicate(); + // If we select TransferWise we switch to show all currencies as TransferWise supports + // sending to most currencies. + if (paymentMethod.getId().equals(PaymentMethod.TRANSFERWISE_ID)) { + onSetTradeCurrency(getShowAllEntryForCurrency()); + } + } else { + this.selectedPaymentMethod = getShowAllEntryForPaymentMethod(); + } + + filterOffers(); } void onRemoveOpenOffer(Offer offer, ResultHandler resultHandler, ErrorMessageHandler errorMessageHandler) { openOfferManager.removeOffer(offer, resultHandler, errorMessageHandler); } + void onShowOffersMatchingMyAccounts(boolean isSelected) { + useOffersMatchingMyAccountsFilter = isSelected; + preferences.setShowOffersMatchingMyAccounts(useOffersMatchingMyAccountsFilter); + filterOffers(); + } + + /////////////////////////////////////////////////////////////////////////////////////////// // Getters /////////////////////////////////////////////////////////////////////////////////////////// + boolean isShowOffersMatchingMyAccounts() { + return preferences.isShowOffersMatchingMyAccounts(); + } + SortedList getOfferList() { return sortedItems; } @@ -347,8 +358,16 @@ class OfferBookViewModel extends ActivatableViewModel { ObservableList getPaymentMethods() { ObservableList list = FXCollections.observableArrayList(PaymentMethod.getPaymentMethods()); + if (preferences.isHideNonAccountPaymentMethods() && user.getPaymentAccounts() != null) { + Set supportedPaymentMethods = user.getPaymentAccounts().stream() + .map(PaymentAccount::getPaymentMethod).collect(Collectors.toSet()); + if (!supportedPaymentMethods.isEmpty()) { + list = FXCollections.observableArrayList(supportedPaymentMethods); + } + } + list.sort(Comparator.naturalOrder()); - list.add(0, PaymentMethod.getDummyPaymentMethod(GUIUtil.SHOW_ALL_FLAG)); + list.add(0, getShowAllEntryForPaymentMethod()); return list; } @@ -390,77 +409,7 @@ class OfferBookViewModel extends ActivatableViewModel { } public Optional getMarketBasedPrice(Offer offer) { - if (offer.isUseMarketBasedPrice()) { - return Optional.of(offer.getMarketPriceMargin()); - } - - if (!hasMarketPrice(offer)) { - if (offer.getCurrencyCode().equals("BSQ")) { - if (bsq30DayAveragePrice != null && bsq30DayAveragePrice.isPositive()) { - double scaled = MathUtils.scaleDownByPowerOf10(bsq30DayAveragePrice.getValue(), 8); - return calculatePercentage(offer, scaled); - } else { - return Optional.empty(); - } - } else { - log.trace("We don't have a market price. " + - "That case could only happen if you don't have a price feed."); - return Optional.empty(); - } - } - - String currencyCode = offer.getCurrencyCode(); - checkNotNull(priceFeedService, "priceFeed must not be null"); - MarketPrice marketPrice = priceFeedService.getMarketPrice(currencyCode); - double marketPriceAsDouble = checkNotNull(marketPrice).getPrice(); - return calculatePercentage(offer, marketPriceAsDouble); - } - - protected Optional calculatePercentage(Offer offer, double marketPrice) { - // If the offer did not use % price we calculate % from current market price - String currencyCode = offer.getCurrencyCode(); - Price price = offer.getPrice(); - int precision = CurrencyUtil.isCryptoCurrency(currencyCode) ? - Altcoin.SMALLEST_UNIT_EXPONENT : - Fiat.SMALLEST_UNIT_EXPONENT; - long priceAsLong = checkNotNull(price).getValue(); - double scaled = MathUtils.scaleDownByPowerOf10(priceAsLong, precision); - - double value; - if (direction == OfferPayload.Direction.SELL) { - if (CurrencyUtil.isFiatCurrency(currencyCode)) { - if (marketPrice == 0) { - return Optional.empty(); - } - value = 1 - scaled / marketPrice; - } else { - if (marketPrice == 1) { - return Optional.empty(); - } - value = scaled / marketPrice - 1; - } - } else { - if (CurrencyUtil.isFiatCurrency(currencyCode)) { - if (marketPrice == 1) { - return Optional.empty(); - } - value = scaled / marketPrice - 1; - } else { - if (marketPrice == 0) { - return Optional.empty(); - } - value = 1 - scaled / marketPrice; - } - } - return Optional.of(value); - } - - public boolean hasMarketPrice(Offer offer) { - String currencyCode = offer.getCurrencyCode(); - checkNotNull(priceFeedService, "priceFeed must not be null"); - MarketPrice marketPrice = priceFeedService.getMarketPrice(currencyCode); - Price price = offer.getPrice(); - return price != null && marketPrice != null && marketPrice.isRecentExternalPriceAvailable(); + return priceUtil.getMarketBasedPrice(offer, direction); } String formatMarketPriceMargin(Offer offer, boolean decimalAligned) { @@ -598,20 +547,16 @@ class OfferBookViewModel extends ActivatableViewModel { private void fillAllTradeCurrencies() { allTradeCurrencies.clear(); // Used for ignoring filter (show all) - allTradeCurrencies.add(new CryptoCurrency(GUIUtil.SHOW_ALL_FLAG, "")); + allTradeCurrencies.add(getShowAllEntryForCurrency()); allTradeCurrencies.addAll(preferences.getTradeCurrenciesAsObservable()); - allTradeCurrencies.add(new CryptoCurrency(GUIUtil.EDIT_FLAG, "")); + allTradeCurrencies.add(getEditEntryForCurrency()); } + /////////////////////////////////////////////////////////////////////////////////////////// // Checks /////////////////////////////////////////////////////////////////////////////////////////// - boolean isAnyPaymentAccountValidForOffer(Offer offer) { - return user.getPaymentAccounts() != null && - PaymentAccountUtil.isAnyTakerPaymentAccountValidForOffer(offer, user.getPaymentAccounts()); - } - boolean hasPaymentAccountForCurrency() { return (showAllTradeCurrenciesProperty.get() && user.getPaymentAccounts() != null && @@ -630,8 +575,15 @@ class OfferBookViewModel extends ActivatableViewModel { // Filters /////////////////////////////////////////////////////////////////////////////////////////// - private void applyFilterPredicate() { - filteredItems.setPredicate(offerBookListItem -> { + private void filterOffers() { + Predicate predicate = useOffersMatchingMyAccountsFilter ? + getCurrencyAndMethodPredicate().and(getOffersMatchingMyAccountsPredicate()) : + getCurrencyAndMethodPredicate(); + filteredItems.setPredicate(predicate); + } + + private Predicate getCurrencyAndMethodPredicate() { + return offerBookListItem -> { Offer offer = offerBookListItem.getOffer(); boolean directionResult = offer.getDirection() != direction; boolean currencyResult = (showAllTradeCurrenciesProperty.get()) || @@ -640,58 +592,18 @@ class OfferBookViewModel extends ActivatableViewModel { offer.getPaymentMethod().equals(selectedPaymentMethod); boolean notMyOfferOrShowMyOffersActivated = !isMyOffer(offerBookListItem.getOffer()) || preferences.isShowOwnOffersInOfferBook(); return directionResult && currencyResult && paymentMethodResult && notMyOfferOrShowMyOffersActivated; - }); + }; } - boolean isIgnored(Offer offer) { - return preferences.getIgnoreTradersList().stream() - .anyMatch(i -> i.equals(offer.getMakerNodeAddress().getFullAddress())); + private Predicate getOffersMatchingMyAccountsPredicate() { + // This code duplicates code in the view at the button column. We need there the different results for + // display in popups so we cannot replace that with the predicate. Any change need to be applied in both + // places. + return offerBookListItem -> offerFilter.canTakeOffer(offerBookListItem.getOffer(), false).isValid(); } boolean isOfferBanned(Offer offer) { - return filterManager.isOfferIdBanned(offer.getId()); - } - - boolean isCurrencyBanned(Offer offer) { - return filterManager.isCurrencyBanned(offer.getCurrencyCode()); - } - - boolean isPaymentMethodBanned(Offer offer) { - return filterManager.isPaymentMethodBanned(offer.getPaymentMethod()); - } - - boolean isNodeAddressBanned(Offer offer) { - return filterManager.isNodeAddressBanned(offer.getMakerNodeAddress()); - } - - boolean requireUpdateToNewVersion() { - return filterManager.requireUpdateToNewVersionForTrading(); - } - - boolean isInsufficientCounterpartyTradeLimit(Offer offer) { - return CurrencyUtil.isFiatCurrency(offer.getCurrencyCode()) && - !accountAgeWitnessService.verifyPeersTradeAmount(offer, offer.getAmount(), errorMessage -> { - }); - } - - boolean isMyInsufficientTradeLimit(Offer offer) { - Optional accountOptional = getMostMaturePaymentAccountForOffer(offer); - long myTradeLimit = accountOptional - .map(paymentAccount -> accountAgeWitnessService.getMyTradeLimit(paymentAccount, - offer.getCurrencyCode(), offer.getMirroredDirection())) - .orElse(0L); - long offerMinAmount = offer.getMinAmount().value; - log.debug("isInsufficientTradeLimit accountOptional={}, myTradeLimit={}, offerMinAmount={}, ", - accountOptional.isPresent() ? accountOptional.get().getAccountName() : "null", - Coin.valueOf(myTradeLimit).toFriendlyString(), - Coin.valueOf(offerMinAmount).toFriendlyString()); - return CurrencyUtil.isFiatCurrency(offer.getCurrencyCode()) && - accountOptional.isPresent() && - myTradeLimit < offerMinAmount; - } - - boolean hasSameProtocolVersion(Offer offer) { - return offer.getProtocolVersion() == Version.TRADE_PROTOCOL_VERSION; + return offerFilter.isOfferBanned(offer); } private boolean isShowAllEntry(String id) { @@ -715,11 +627,11 @@ class OfferBookViewModel extends ActivatableViewModel { public boolean hasSelectionAccountSigning() { if (showAllTradeCurrenciesProperty.get()) { - if (!selectedPaymentMethod.getId().equals(GUIUtil.SHOW_ALL_FLAG)) { + if (!isShowAllEntry(selectedPaymentMethod.getId())) { return PaymentMethod.hasChargebackRisk(selectedPaymentMethod); } } else { - if (selectedPaymentMethod.getId().equals(GUIUtil.SHOW_ALL_FLAG)) + if (isShowAllEntry(selectedPaymentMethod.getId())) return CurrencyUtil.getMatureMarketCurrencies().stream() .anyMatch(c -> c.getCode().equals(selectedTradeCurrency.getCode())); else @@ -745,4 +657,16 @@ class OfferBookViewModel extends ActivatableViewModel { var percentage = FormattingUtils.formatToRoundedPercentWithSymbol(deposit.getValue() / (double) amount); return btcFormatter.formatCoin(deposit) + " (" + percentage + ")"; } + + private TradeCurrency getShowAllEntryForCurrency() { + return new CryptoCurrency(GUIUtil.SHOW_ALL_FLAG, ""); + } + + private TradeCurrency getEditEntryForCurrency() { + return new CryptoCurrency(GUIUtil.EDIT_FLAG, ""); + } + + private PaymentMethod getShowAllEntryForPaymentMethod() { + return PaymentMethod.getDummyPaymentMethod(GUIUtil.SHOW_ALL_FLAG); + } } diff --git a/desktop/src/main/java/bisq/desktop/main/offer/takeoffer/TakeOfferDataModel.java b/desktop/src/main/java/bisq/desktop/main/offer/takeoffer/TakeOfferDataModel.java index 7e89492481..9c3eacd330 100644 --- a/desktop/src/main/java/bisq/desktop/main/offer/takeoffer/TakeOfferDataModel.java +++ b/desktop/src/main/java/bisq/desktop/main/offer/takeoffer/TakeOfferDataModel.java @@ -171,6 +171,7 @@ class TakeOfferDataModel extends OfferDataModel { if (canTakeOffer()) { tradeManager.checkOfferAvailability(offer, + false, () -> { }, errorMessage -> new Popup().warning(errorMessage).show()); @@ -319,7 +320,8 @@ class TakeOfferDataModel extends OfferDataModel { offer, paymentAccount.getId(), useSavingsWallet, - tradeResultHandler::handleResult, + false, + tradeResultHandler, errorMessage -> { log.warn(errorMessage); new Popup().warning(errorMessage).show(); @@ -500,10 +502,18 @@ class TakeOfferDataModel extends OfferDataModel { } } - private boolean isBuyOffer() { + boolean isBuyOffer() { return getDirection() == OfferPayload.Direction.BUY; } + boolean isSellOffer() { + return getDirection() == OfferPayload.Direction.SELL; + } + + boolean isCryptoCurrency() { + return CurrencyUtil.isCryptoCurrency(getCurrencyCode()); + } + @Nullable Coin getTakerFee(boolean isCurrencyForTakerFeeBtc) { Coin amount = this.amount.get(); diff --git a/desktop/src/main/java/bisq/desktop/main/offer/takeoffer/TakeOfferView.java b/desktop/src/main/java/bisq/desktop/main/offer/takeoffer/TakeOfferView.java index 8309ed8066..0539962f54 100644 --- a/desktop/src/main/java/bisq/desktop/main/offer/takeoffer/TakeOfferView.java +++ b/desktop/src/main/java/bisq/desktop/main/offer/takeoffer/TakeOfferView.java @@ -37,6 +37,7 @@ import bisq.desktop.main.dao.wallet.receive.BsqReceiveView; import bisq.desktop.main.funds.FundsView; import bisq.desktop.main.funds.withdrawal.WithdrawalView; import bisq.desktop.main.offer.OfferView; +import bisq.desktop.main.offer.OfferViewUtil; import bisq.desktop.main.overlays.notifications.Notification; import bisq.desktop.main.overlays.popups.Popup; import bisq.desktop.main.overlays.windows.OfferDetailsWindow; @@ -347,13 +348,12 @@ public class TakeOfferView extends ActivatableViewAndModel 1; paymentAccountsComboBox.setVisible(showComboBox); @@ -383,8 +383,10 @@ public class TakeOfferView extends ActivatableViewAndModel priceAsPercentageInputBoxTuple = getTradeInputBox(priceAsPercentageValueCurrencyBox, - Res.get("shared.distanceInPercent")); + Tuple2 priceAsPercentageInputBoxTuple = getTradeInputBox(priceAsPercentageValueCurrencyBox, ""); priceAsPercentageDescription = priceAsPercentageInputBoxTuple.first; getSmallIconForLabel(MaterialDesignIcon.CHART_LINE, priceAsPercentageDescription, "small-icon-label"); @@ -1273,14 +1274,6 @@ public class TakeOfferView extends ActivatableViewAndModel im ComboBox paymentAccountsComboBox) { return GUIUtil.getPaymentAccountListCellFactory(paymentAccountsComboBox, accountAgeWitnessService); } + + String getPercentagePriceDescription() { + if (dataModel.isBuyOffer()) { + return dataModel.isCryptoCurrency() ? + Res.get("shared.aboveInPercent") : + Res.get("shared.belowInPercent"); + } else { + return dataModel.isCryptoCurrency() ? + Res.get("shared.belowInPercent") : + Res.get("shared.aboveInPercent"); + } + } } diff --git a/desktop/src/main/java/bisq/desktop/main/overlays/windows/ContractWindow.java b/desktop/src/main/java/bisq/desktop/main/overlays/windows/ContractWindow.java index a1bbf47298..4f025afec0 100644 --- a/desktop/src/main/java/bisq/desktop/main/overlays/windows/ContractWindow.java +++ b/desktop/src/main/java/bisq/desktop/main/overlays/windows/ContractWindow.java @@ -33,6 +33,7 @@ import bisq.core.payment.payload.PaymentMethod; import bisq.core.support.dispute.Dispute; import bisq.core.support.dispute.DisputeList; import bisq.core.support.dispute.DisputeManager; +import bisq.core.support.dispute.agent.DisputeAgentLookupMap; import bisq.core.support.dispute.arbitration.ArbitrationManager; import bisq.core.support.dispute.mediation.MediationManager; import bisq.core.support.dispute.refund.RefundManager; @@ -193,17 +194,20 @@ public class ContractWindow extends Overlay { sellerPaymentAccountPayload.getPaymentDetails()).second.setMouseTransparent(false); String title = ""; + String agentKeyBaseUserName = ""; if (dispute.getSupportType() != null) { switch (dispute.getSupportType()) { case ARBITRATION: title = Res.get("shared.selectedArbitrator"); break; case MEDIATION: + agentKeyBaseUserName = DisputeAgentLookupMap.getKeyBaseUserName(contract.getMediatorNodeAddress().getFullAddress()); title = Res.get("shared.selectedMediator"); break; case TRADE: break; case REFUND: + agentKeyBaseUserName = DisputeAgentLookupMap.getKeyBaseUserName(contract.getRefundAgentNodeAddress().getFullAddress()); title = Res.get("shared.selectedRefundAgent"); break; } @@ -212,7 +216,8 @@ public class ContractWindow extends Overlay { if (disputeManager != null) { NodeAddress agentNodeAddress = disputeManager.getAgentNodeAddress(dispute); if (agentNodeAddress != null) { - addConfirmationLabelTextFieldWithCopyIcon(gridPane, ++rowIndex, title, agentNodeAddress.getFullAddress()); + String value = agentKeyBaseUserName + " (" + agentNodeAddress.getFullAddress() + ")"; + addConfirmationLabelTextFieldWithCopyIcon(gridPane, ++rowIndex, title, value); } } diff --git a/desktop/src/main/java/bisq/desktop/main/overlays/windows/FilterWindow.java b/desktop/src/main/java/bisq/desktop/main/overlays/windows/FilterWindow.java index a82f00d02b..5ff3f216ea 100644 --- a/desktop/src/main/java/bisq/desktop/main/overlays/windows/FilterWindow.java +++ b/desktop/src/main/java/bisq/desktop/main/overlays/windows/FilterWindow.java @@ -37,8 +37,6 @@ import javax.inject.Named; import org.apache.commons.lang3.StringUtils; -import javafx.collections.FXCollections; - import javafx.scene.Scene; import javafx.scene.control.Button; import javafx.scene.control.CheckBox; @@ -51,7 +49,11 @@ import javafx.scene.layout.Region; import javafx.geometry.HPos; import javafx.geometry.Insets; +import javafx.collections.FXCollections; + import java.util.Arrays; +import java.util.Collection; +import java.util.HashSet; import java.util.List; import java.util.stream.Collectors; @@ -122,9 +124,11 @@ public class FilterWindow extends Overlay { InputTextField offerIdsTF = addInputTextField(gridPane, ++rowIndex, Res.get("filterWindow.offers")); - InputTextField nodesTF = addTopLabelInputTextField(gridPane, ++rowIndex, + InputTextField bannedFromTradingTF = addTopLabelInputTextField(gridPane, ++rowIndex, Res.get("filterWindow.onions")).second; - nodesTF.setPromptText("E.g. zqnzx6o3nifef5df.onion:9999"); // Do not translate + InputTextField bannedFromNetworkTF = addTopLabelInputTextField(gridPane, ++rowIndex, + Res.get("filterWindow.bannedFromNetwork")).second; + bannedFromTradingTF.setPromptText("E.g. zqnzx6o3nifef5df.onion:9999"); // Do not translate InputTextField paymentAccountFilterTF = addTopLabelInputTextField(gridPane, ++rowIndex, Res.get("filterWindow.accounts")).second; GridPane.setHalignment(paymentAccountFilterTF, HPos.RIGHT); @@ -165,11 +169,14 @@ public class FilterWindow extends Overlay { Res.get("filterWindow.bannedPrivilegedDevPubKeys")).second; InputTextField autoConfExplorersTF = addTopLabelInputTextField(gridPane, ++rowIndex, Res.get("filterWindow.autoConfExplorers")).second; + CheckBox disableApiCheckBox = addLabelCheckBox(gridPane, ++rowIndex, + Res.get("filterWindow.disableApi")); Filter filter = filterManager.getDevFilter(); if (filter != null) { setupFieldFromList(offerIdsTF, filter.getBannedOfferIds()); - setupFieldFromList(nodesTF, filter.getBannedNodeAddress()); + setupFieldFromList(bannedFromTradingTF, filter.getNodeAddressesBannedFromTrading()); + setupFieldFromList(bannedFromNetworkTF, filter.getNodeAddressesBannedFromNetwork()); setupFieldFromPaymentAccountFiltersList(paymentAccountFilterTF, filter.getBannedPaymentAccounts()); setupFieldFromList(bannedCurrenciesTF, filter.getBannedCurrencies()); setupFieldFromList(bannedPaymentMethodsTF, filter.getBannedPaymentMethods()); @@ -189,6 +196,7 @@ public class FilterWindow extends Overlay { disableAutoConfCheckBox.setSelected(filter.isDisableAutoConf()); disableDaoBelowVersionTF.setText(filter.getDisableDaoBelowVersion()); disableTradeBelowVersionTF.setText(filter.getDisableTradeBelowVersion()); + disableApiCheckBox.setSelected(filter.isDisableApi()); } Button removeFilterMessageButton = new AutoTooltipButton(Res.get("filterWindow.remove")); @@ -201,7 +209,7 @@ public class FilterWindow extends Overlay { String signerPubKeyAsHex = filterManager.getSignerPubKeyAsHex(privKeyString); Filter newFilter = new Filter( readAsList(offerIdsTF), - readAsList(nodesTF), + readAsList(bannedFromTradingTF), readAsPaymentAccountFiltersList(paymentAccountFilterTF), readAsList(bannedCurrenciesTF), readAsList(bannedPaymentMethodsTF), @@ -221,7 +229,9 @@ public class FilterWindow extends Overlay { signerPubKeyAsHex, readAsList(bannedPrivilegedDevPubKeysTF), disableAutoConfCheckBox.isSelected(), - readAsList(autoConfExplorersTF) + readAsList(autoConfExplorersTF), + new HashSet<>(readAsList(bannedFromNetworkTF)), + disableApiCheckBox.isSelected() ); // We remove first the old filter @@ -270,7 +280,7 @@ public class FilterWindow extends Overlay { hide(); } - private void setupFieldFromList(InputTextField field, List values) { + private void setupFieldFromList(InputTextField field, Collection values) { if (values != null) field.setText(String.join(", ", values)); } diff --git a/desktop/src/main/java/bisq/desktop/main/overlays/windows/TradeDetailsWindow.java b/desktop/src/main/java/bisq/desktop/main/overlays/windows/TradeDetailsWindow.java index 3e51e9d77f..cf38de4333 100644 --- a/desktop/src/main/java/bisq/desktop/main/overlays/windows/TradeDetailsWindow.java +++ b/desktop/src/main/java/bisq/desktop/main/overlays/windows/TradeDetailsWindow.java @@ -32,6 +32,7 @@ import bisq.core.locale.CurrencyUtil; import bisq.core.locale.Res; import bisq.core.offer.Offer; import bisq.core.payment.payload.PaymentAccountPayload; +import bisq.core.support.dispute.agent.DisputeAgentLookupMap; import bisq.core.support.dispute.arbitration.ArbitrationManager; import bisq.core.trade.Contract; import bisq.core.trade.Trade; @@ -346,6 +347,7 @@ public class TradeDetailsWindow extends Overlay { textArea.setText(trade.getContractAsJson()); String data = "Contract as json:\n"; data += trade.getContractAsJson(); + data += "\n\nOther detail data:"; data += "\n\nBuyerMultiSigPubKeyHex: " + Utils.HEX.encode(contract.getBuyerMultiSigPubKey()); data += "\nSellerMultiSigPubKeyHex: " + Utils.HEX.encode(contract.getSellerMultiSigPubKey()); if (CurrencyUtil.isFiatCurrency(offer.getCurrencyCode())) { @@ -358,6 +360,9 @@ public class TradeDetailsWindow extends Overlay { data += "\n\nRaw deposit transaction as hex:\n" + depositTxAsHex; } + data += "\n\nSelected mediator: " + DisputeAgentLookupMap.getKeyBaseUserName(contract.getMediatorNodeAddress().getFullAddress()); + data += "\nSelected arbitrator (refund agent): " + DisputeAgentLookupMap.getKeyBaseUserName(contract.getRefundAgentNodeAddress().getFullAddress()); + textArea.setText(data); textArea.setPrefHeight(50); textArea.setEditable(false); diff --git a/desktop/src/main/java/bisq/desktop/main/portfolio/closedtrades/ClosedTradesView.java b/desktop/src/main/java/bisq/desktop/main/portfolio/closedtrades/ClosedTradesView.java index 8f3039688f..6c4ebcf0f9 100644 --- a/desktop/src/main/java/bisq/desktop/main/portfolio/closedtrades/ClosedTradesView.java +++ b/desktop/src/main/java/bisq/desktop/main/portfolio/closedtrades/ClosedTradesView.java @@ -254,7 +254,7 @@ public class ClosedTradesView extends ActivatableViewAndModel { final ObservableList> tableColumns = tableView.getColumns(); - CSVEntryConverter headerConverter = transactionsListItem -> { + CSVEntryConverter headerConverter = item -> { String[] columns = new String[ColumnNames.values().length]; for (ColumnNames m : ColumnNames.values()) { columns[m.ordinal()] = m.toString(); @@ -313,7 +313,6 @@ public class ClosedTradesView extends ActivatableViewAndModel 1200); tradeFeeColumn.setVisible(width > 1300); buyerSecurityDepositColumn.setVisible(width > 1400); diff --git a/desktop/src/main/java/bisq/desktop/main/portfolio/editoffer/EditOfferDataModel.java b/desktop/src/main/java/bisq/desktop/main/portfolio/editoffer/EditOfferDataModel.java index 6524e311d1..dc7d29c7c0 100644 --- a/desktop/src/main/java/bisq/desktop/main/portfolio/editoffer/EditOfferDataModel.java +++ b/desktop/src/main/java/bisq/desktop/main/portfolio/editoffer/EditOfferDataModel.java @@ -170,7 +170,10 @@ class EditOfferDataModel extends MutableOfferDataModel { setPrice(offer.getPrice()); setVolume(offer.getVolume()); setUseMarketBasedPrice(offer.isUseMarketBasedPrice()); - if (offer.isUseMarketBasedPrice()) setMarketPriceMargin(offer.getMarketPriceMargin()); + setTriggerPrice(openOffer.getTriggerPrice()); + if (offer.isUseMarketBasedPrice()) { + setMarketPriceMargin(offer.getMarketPriceMargin()); + } } public void onStartEditOffer(ErrorMessageHandler errorMessageHandler) { @@ -227,7 +230,7 @@ class EditOfferDataModel extends MutableOfferDataModel { editedOffer.setPriceFeedService(priceFeedService); editedOffer.setState(Offer.State.AVAILABLE); - openOfferManager.editOpenOfferPublish(editedOffer, initialState, () -> { + openOfferManager.editOpenOfferPublish(editedOffer, triggerPrice, initialState, () -> { openOffer = null; resultHandler.handleResult(); }, errorMessageHandler); diff --git a/desktop/src/main/java/bisq/desktop/main/portfolio/editoffer/EditOfferView.java b/desktop/src/main/java/bisq/desktop/main/portfolio/editoffer/EditOfferView.java index c78b180de6..c22e8b06b6 100644 --- a/desktop/src/main/java/bisq/desktop/main/portfolio/editoffer/EditOfferView.java +++ b/desktop/src/main/java/bisq/desktop/main/portfolio/editoffer/EditOfferView.java @@ -28,6 +28,7 @@ import bisq.desktop.main.overlays.windows.OfferDetailsWindow; import bisq.core.locale.CurrencyUtil; import bisq.core.locale.Res; import bisq.core.offer.OpenOffer; +import bisq.core.user.DontShowAgainLookup; import bisq.core.user.Preferences; import bisq.core.util.FormattingUtils; import bisq.core.util.coin.BsqFormatter; @@ -206,8 +207,13 @@ public class EditOfferView extends MutableOfferView { spinnerInfoLabel.setText(Res.get("editOffer.publishOffer")); //edit offer model.onPublishOffer(() -> { - log.debug("Edit offer was successful"); - new Popup().feedback(Res.get("editOffer.success")).show(); + String key = "editOfferSuccess"; + if (DontShowAgainLookup.showAgain(key)) { + new Popup() + .feedback(Res.get("editOffer.success")) + .dontShowAgainId(key) + .show(); + } spinnerInfoLabel.setText(""); busyAnimation.stop(); close(); diff --git a/desktop/src/main/java/bisq/desktop/main/portfolio/editoffer/EditOfferViewModel.java b/desktop/src/main/java/bisq/desktop/main/portfolio/editoffer/EditOfferViewModel.java index 73b3c83781..d4aab63268 100644 --- a/desktop/src/main/java/bisq/desktop/main/portfolio/editoffer/EditOfferViewModel.java +++ b/desktop/src/main/java/bisq/desktop/main/portfolio/editoffer/EditOfferViewModel.java @@ -18,6 +18,7 @@ package bisq.desktop.main.portfolio.editoffer; import bisq.desktop.Navigation; +import bisq.desktop.main.PriceUtil; import bisq.desktop.main.offer.MutableOfferViewModel; import bisq.desktop.util.validation.AltcoinValidator; import bisq.desktop.util.validation.BsqValidator; @@ -79,7 +80,17 @@ class EditOfferViewModel extends MutableOfferViewModel { @Override public void activate() { super.activate(); + dataModel.populateData(); + + long triggerPriceAsLong = dataModel.getTriggerPrice(); + dataModel.setTriggerPrice(triggerPriceAsLong); + if (triggerPriceAsLong > 0) { + triggerPrice.set(PriceUtil.formatMarketPrice(triggerPriceAsLong, dataModel.getCurrencyCode())); + } else { + triggerPrice.set(""); + } + onTriggerPriceTextFieldChanged(); } public void applyOpenOffer(OpenOffer openOffer) { diff --git a/desktop/src/main/java/bisq/desktop/main/portfolio/failedtrades/FailedTradesView.java b/desktop/src/main/java/bisq/desktop/main/portfolio/failedtrades/FailedTradesView.java index 85e11f5190..6297584d7f 100644 --- a/desktop/src/main/java/bisq/desktop/main/portfolio/failedtrades/FailedTradesView.java +++ b/desktop/src/main/java/bisq/desktop/main/portfolio/failedtrades/FailedTradesView.java @@ -201,7 +201,7 @@ public class FailedTradesView extends ActivatableViewAndModel { ObservableList> tableColumns = tableView.getColumns(); int reportColumns = tableColumns.size() - 1; // CSV report excludes the last column (an icon) - CSVEntryConverter headerConverter = transactionsListItem -> { + CSVEntryConverter headerConverter = item -> { String[] columns = new String[reportColumns]; for (int i = 0; i < columns.length; i++) columns[i] = ((AutoTooltipLabel) tableColumns.get(i).getGraphic()).getText(); diff --git a/desktop/src/main/java/bisq/desktop/main/portfolio/openoffer/OpenOffersDataModel.java b/desktop/src/main/java/bisq/desktop/main/portfolio/openoffer/OpenOffersDataModel.java index 26421413a5..8d71374f7d 100644 --- a/desktop/src/main/java/bisq/desktop/main/portfolio/openoffer/OpenOffersDataModel.java +++ b/desktop/src/main/java/bisq/desktop/main/portfolio/openoffer/OpenOffersDataModel.java @@ -23,6 +23,7 @@ import bisq.core.offer.Offer; import bisq.core.offer.OfferPayload; import bisq.core.offer.OpenOffer; import bisq.core.offer.OpenOfferManager; +import bisq.core.offer.TriggerPriceService; import bisq.core.provider.price.PriceFeedService; import bisq.common.handlers.ErrorMessageHandler; @@ -98,5 +99,7 @@ class OpenOffersDataModel extends ActivatableDataModel { list.sort((o1, o2) -> o2.getOffer().getDate().compareTo(o1.getOffer().getDate())); } - + boolean wasTriggered(OpenOffer openOffer) { + return TriggerPriceService.wasTriggered(priceFeedService.getMarketPrice(openOffer.getOffer().getCurrencyCode()), openOffer); + } } diff --git a/desktop/src/main/java/bisq/desktop/main/portfolio/openoffer/OpenOffersView.fxml b/desktop/src/main/java/bisq/desktop/main/portfolio/openoffer/OpenOffersView.fxml index 192aef505d..ac16ef582b 100644 --- a/desktop/src/main/java/bisq/desktop/main/portfolio/openoffer/OpenOffersView.fxml +++ b/desktop/src/main/java/bisq/desktop/main/portfolio/openoffer/OpenOffersView.fxml @@ -47,13 +47,15 @@ + - - + + + diff --git a/desktop/src/main/java/bisq/desktop/main/portfolio/openoffer/OpenOffersView.java b/desktop/src/main/java/bisq/desktop/main/portfolio/openoffer/OpenOffersView.java index a6bdd85897..873c73c0ca 100644 --- a/desktop/src/main/java/bisq/desktop/main/portfolio/openoffer/OpenOffersView.java +++ b/desktop/src/main/java/bisq/desktop/main/portfolio/openoffer/OpenOffersView.java @@ -79,7 +79,7 @@ import java.util.Comparator; import org.jetbrains.annotations.NotNull; -import static bisq.desktop.util.FormBuilder.getIconButton; +import static bisq.desktop.util.FormBuilder.getRegularIconButton; @FxmlView public class OpenOffersView extends ActivatableViewAndModel { @@ -89,7 +89,7 @@ public class OpenOffersView extends ActivatableViewAndModel priceColumn, deviationColumn, amountColumn, volumeColumn, marketColumn, directionColumn, dateColumn, offerIdColumn, deactivateItemColumn, - removeItemColumn, editItemColumn, paymentMethodColumn; + removeItemColumn, editItemColumn, triggerPriceColumn, triggerIconColumn, paymentMethodColumn; @FXML HBox searchBox; @FXML @@ -113,6 +113,7 @@ public class OpenOffersView extends ActivatableViewAndModel filteredList; private ChangeListener filterTextFieldListener; private PortfolioView.OpenOfferActionHandler openOfferActionHandler; + private ChangeListener widthListener; @Inject public OpenOffersView(OpenOffersViewModel model, Navigation navigation, OfferDetailsWindow offerDetailsWindow) { @@ -123,6 +124,7 @@ public class OpenOffersView extends ActivatableViewAndModel onWidthChange((double) newValue); paymentMethodColumn.setGraphic(new AutoTooltipLabel(Res.get("shared.paymentMethod"))); priceColumn.setGraphic(new AutoTooltipLabel(Res.get("shared.price"))); deviationColumn.setGraphic(new AutoTooltipTableColumn<>(Res.get("shared.deviation"), @@ -133,6 +135,7 @@ public class OpenOffersView extends ActivatableViewAndModel o.getOffer().getAmount())); priceColumn.setComparator(Comparator.comparing(o -> o.getOffer().getPrice(), Comparator.nullsFirst(Comparator.naturalOrder()))); - deviationColumn.setComparator(Comparator.comparing(o -> - o.getOffer().isUseMarketBasedPrice() ? o.getOffer().getMarketPriceMargin() : 1, + deviationColumn.setComparator(Comparator.comparing(model::getPriceDeviationAsDouble, Comparator.nullsFirst(Comparator.naturalOrder()))); + triggerPriceColumn.setComparator(Comparator.comparing(o -> o.getOpenOffer().getTriggerPrice(), Comparator.nullsFirst(Comparator.naturalOrder()))); volumeColumn.setComparator(Comparator.comparing(o -> o.getOffer().getVolume(), Comparator.nullsFirst(Comparator.naturalOrder()))); dateColumn.setComparator(Comparator.comparing(o -> o.getOffer().getDate())); @@ -205,8 +210,8 @@ public class OpenOffersView extends ActivatableViewAndModel { ObservableList> tableColumns = tableView.getColumns(); - int reportColumns = tableColumns.size() - 2; // CSV report excludes the last columns (icons) - CSVEntryConverter headerConverter = transactionsListItem -> { + int reportColumns = tableColumns.size() - 3; // CSV report excludes the last columns (icons) + CSVEntryConverter headerConverter = item -> { String[] columns = new String[reportColumns]; for (int i = 0; i < columns.length; i++) { Node graphic = tableColumns.get(i).getGraphic(); @@ -229,11 +234,12 @@ public class OpenOffersView extends ActivatableViewAndModel { if (filterString.isEmpty()) @@ -314,6 +324,10 @@ public class OpenOffersView extends ActivatableViewAndModel 1200); + } + private void onDeactivateOpenOffer(OpenOffer openOffer) { if (model.isBootstrappedOrShowPopup()) { model.onDeactivateOpenOffer(openOffer, @@ -327,7 +341,7 @@ public class OpenOffersView extends ActivatableViewAndModel log.debug("Activate offer was successful"), (message) -> { @@ -504,7 +518,33 @@ public class OpenOffersView extends ActivatableViewAndModel new ReadOnlyObjectWrapper<>(offerListItem.getValue())); + triggerPriceColumn.setCellFactory( + new Callback<>() { + @Override + public TableCell call( + TableColumn column) { + return new TableCell<>() { + @Override + public void updateItem(final OpenOfferListItem item, boolean empty) { + super.updateItem(item, empty); + getStyleClass().removeAll("offer-disabled"); + if (item != null) { + if (model.isDeactivated(item)) getStyleClass().add("offer-disabled"); + setGraphic(new AutoTooltipLabel(model.getTriggerPrice(item))); } else { setGraphic(null); } @@ -633,20 +673,23 @@ public class OpenOffersView extends ActivatableViewAndModel { - if (item.getOpenOffer().isDeactivated()) { - onActivateOpenOffer(item.getOpenOffer()); + if (openOffer.isDeactivated()) { + onActivateOpenOffer(openOffer); } else { - onDeactivateOpenOffer(item.getOpenOffer()); + onDeactivateOpenOffer(openOffer); } - updateState(item.getOpenOffer()); + updateState(openOffer); tableView.refresh(); }); - updateState(item.getOpenOffer()); + updateState(openOffer); setGraphic(checkBox); } else { setGraphic(null); @@ -677,7 +720,7 @@ public class OpenOffersView extends ActivatableViewAndModel new ReadOnlyObjectWrapper<>(offerListItem.getValue())); + triggerIconColumn.setCellFactory( + new Callback<>() { + @Override + public TableCell call(TableColumn column) { + return new TableCell<>() { + Button button; + + @Override + public void updateItem(final OpenOfferListItem item, boolean empty) { + super.updateItem(item, empty); + + if (item != null && !empty) { + if (button == null) { + button = getRegularIconButton(MaterialDesignIcon.SHIELD_HALF_FULL); + boolean triggerPriceSet = item.getOpenOffer().getTriggerPrice() > 0; + button.setVisible(triggerPriceSet); + + if (model.dataModel.wasTriggered(item.getOpenOffer())) { + button.getGraphic().getStyleClass().add("warning"); + button.setTooltip(new Tooltip(Res.get("openOffer.triggered"))); + } else { + button.getGraphic().getStyleClass().remove("warning"); + button.setTooltip(new Tooltip(Res.get("openOffer.triggerPrice", model.getTriggerPrice(item)))); + } + setGraphic(button); + } + button.setOnAction(event -> onEditOpenOffer(item.getOpenOffer())); + } else { + setGraphic(null); + if (button != null) { + button.setOnAction(null); + button = null; + } + } + } + }; + } + }); + } + private void setEditColumnCellFactory() { editItemColumn.setCellValueFactory((offerListItem) -> new ReadOnlyObjectWrapper<>(offerListItem.getValue())); editItemColumn.setCellFactory( @@ -710,7 +795,7 @@ public class OpenOffersView extends ActivatableViewAndModel implements ViewModel { private final P2PService p2PService; + private final PriceUtil priceUtil; private final CoinFormatter btcFormatter; private final BsqFormatter bsqFormatter; @@ -53,20 +55,31 @@ class OpenOffersViewModel extends ActivatableWithDataModel @Inject public OpenOffersViewModel(OpenOffersDataModel dataModel, P2PService p2PService, + PriceUtil priceUtil, @Named(FormattingUtils.BTC_FORMATTER_KEY) CoinFormatter btcFormatter, BsqFormatter bsqFormatter) { super(dataModel); this.p2PService = p2PService; + this.priceUtil = priceUtil; this.btcFormatter = btcFormatter; this.bsqFormatter = bsqFormatter; } - void onActivateOpenOffer(OpenOffer openOffer, ResultHandler resultHandler, ErrorMessageHandler errorMessageHandler) { + @Override + protected void activate() { + priceUtil.recalculateBsq30DayAveragePrice(); + } + + void onActivateOpenOffer(OpenOffer openOffer, + ResultHandler resultHandler, + ErrorMessageHandler errorMessageHandler) { dataModel.onActivateOpenOffer(openOffer, resultHandler, errorMessageHandler); } - void onDeactivateOpenOffer(OpenOffer openOffer, ResultHandler resultHandler, ErrorMessageHandler errorMessageHandler) { + void onDeactivateOpenOffer(OpenOffer openOffer, + ResultHandler resultHandler, + ErrorMessageHandler errorMessageHandler) { dataModel.onDeactivateOpenOffer(openOffer, resultHandler, errorMessageHandler); } @@ -100,14 +113,15 @@ class OpenOffersViewModel extends ActivatableWithDataModel } String getPriceDeviation(OpenOfferListItem item) { - if ((item == null)) - return ""; Offer offer = item.getOffer(); - if (offer.isUseMarketBasedPrice()) { - return FormattingUtils.formatPercentagePrice(offer.getMarketPriceMargin()); - } else { - return Res.get("shared.na"); - } + return priceUtil.getMarketBasedPrice(offer, offer.getMirroredDirection()) + .map(FormattingUtils::formatPercentagePrice) + .orElse(""); + } + + Double getPriceDeviationAsDouble(OpenOfferListItem item) { + Offer offer = item.getOffer(); + return priceUtil.getMarketBasedPrice(offer, offer.getMirroredDirection()).orElse(0d); } String getVolume(OpenOfferListItem item) { @@ -157,4 +171,18 @@ class OpenOffersViewModel extends ActivatableWithDataModel btcFormatter.formatCoinWithCode(offer.getMakerFee()) : bsqFormatter.formatCoinWithCode(offer.getMakerFee()); } + + String getTriggerPrice(OpenOfferListItem item) { + if ((item == null)) { + return ""; + } + + Offer offer = item.getOffer(); + long triggerPrice = item.getOpenOffer().getTriggerPrice(); + if (!offer.isUseMarketBasedPrice() || triggerPrice <= 0) { + return Res.get("shared.na"); + } else { + return PriceUtil.formatMarketPrice(triggerPrice, offer.getCurrencyCode()); + } + } } diff --git a/desktop/src/main/java/bisq/desktop/main/settings/preferences/PreferencesView.java b/desktop/src/main/java/bisq/desktop/main/settings/preferences/PreferencesView.java index 8d000b3139..19f4b73607 100644 --- a/desktop/src/main/java/bisq/desktop/main/settings/preferences/PreferencesView.java +++ b/desktop/src/main/java/bisq/desktop/main/settings/preferences/PreferencesView.java @@ -45,8 +45,11 @@ import bisq.core.locale.FiatCurrency; import bisq.core.locale.LanguageUtil; import bisq.core.locale.Res; import bisq.core.locale.TradeCurrency; +import bisq.core.payment.PaymentAccount; +import bisq.core.payment.payload.PaymentMethod; import bisq.core.provider.fee.FeeService; import bisq.core.user.Preferences; +import bisq.core.user.User; import bisq.core.util.FormattingUtils; import bisq.core.util.ParsingUtils; import bisq.core.util.coin.CoinFormatter; @@ -100,13 +103,16 @@ import java.io.File; import java.util.ArrayList; import java.util.Arrays; import java.util.List; +import java.util.Set; import java.util.concurrent.TimeUnit; +import java.util.stream.Collectors; import static bisq.desktop.util.FormBuilder.*; import static com.google.common.base.Preconditions.checkArgument; @FxmlView public class PreferencesView extends ActivatableViewAndModel { + private final User user; private final CoinFormatter formatter; private TextField btcExplorerTextField, bsqExplorerTextField; private ComboBox userLanguageComboBox; @@ -114,7 +120,7 @@ public class PreferencesView extends ActivatableViewAndModel preferredTradeCurrencyComboBox; private ToggleButton showOwnOffersInOfferBook, useAnimations, useDarkMode, sortMarketCurrenciesNumerically, - avoidStandbyMode, useCustomFee, autoConfirmXmrToggle; + avoidStandbyMode, useCustomFee, autoConfirmXmrToggle, hideNonAccountPaymentMethodsToggle, denyApiTakerToggle; private int gridRow = 0; private int displayCurrenciesGridRowIndex = 0; private InputTextField transactionFeeInputTextField, ignoreTradersListInputTextField, ignoreDustThresholdInputTextField, @@ -171,12 +177,14 @@ public class PreferencesView extends ActivatableViewAndModel preferences.setSortMarketCurrenciesNumerically(sortMarketCurrenciesNumerically.isSelected())); + boolean disableToggle = false; + if (user.getPaymentAccounts() != null) { + Set supportedPaymentMethods = user.getPaymentAccounts().stream() + .map(PaymentAccount::getPaymentMethod).collect(Collectors.toSet()); + disableToggle = supportedPaymentMethods.isEmpty(); + } + hideNonAccountPaymentMethodsToggle.setSelected(preferences.isHideNonAccountPaymentMethods() && !disableToggle); + hideNonAccountPaymentMethodsToggle.setOnAction(e -> preferences.setHideNonAccountPaymentMethods(hideNonAccountPaymentMethodsToggle.isSelected())); + hideNonAccountPaymentMethodsToggle.setDisable(disableToggle); + + denyApiTakerToggle.setSelected(preferences.isDenyApiTaker()); + denyApiTakerToggle.setOnAction(e -> preferences.setDenyApiTaker(denyApiTakerToggle.isSelected())); + resetDontShowAgainButton.setOnAction(e -> preferences.resetDontShowAgain()); editCustomBtcExplorer.setOnAction(e -> { @@ -1108,8 +1130,9 @@ public class PreferencesView extends ActivatableViewAndModel { TableColumn roleColumn = getRoleColumn(); tableView.getColumns().add(roleColumn); + maybeAddAgentColumn(); + stateColumn = getStateColumn(); tableView.getColumns().add(stateColumn); @@ -923,6 +926,15 @@ public abstract class DisputeView extends ActivatableView { tableView.getSortOrder().add(dateColumn); } + protected void maybeAddAgentColumn() { + // Only relevant client views will impl it + } + + // Relevant client views will override that + protected NodeAddress getAgentNodeAddress(Contract contract) { + return null; + } + private TableColumn getSelectColumn() { TableColumn column = new AutoTooltipTableColumn<>(Res.get("shared.select")); column.setMinWidth(80); @@ -1076,7 +1088,7 @@ public abstract class DisputeView extends ActivatableView { private TableColumn getBuyerOnionAddressColumn() { TableColumn column = new AutoTooltipTableColumn<>(Res.get("support.buyerAddress")) { { - setMinWidth(190); + setMinWidth(160); } }; column.setCellValueFactory((dispute) -> new ReadOnlyObjectWrapper<>(dispute.getValue())); @@ -1102,7 +1114,7 @@ public abstract class DisputeView extends ActivatableView { private TableColumn getSellerOnionAddressColumn() { TableColumn column = new AutoTooltipTableColumn<>(Res.get("support.sellerAddress")) { { - setMinWidth(190); + setMinWidth(160); } }; column.setCellValueFactory((dispute) -> new ReadOnlyObjectWrapper<>(dispute.getValue())); @@ -1216,6 +1228,40 @@ public abstract class DisputeView extends ActivatableView { return column; } + protected TableColumn getAgentColumn() { + TableColumn column = new AutoTooltipTableColumn<>(Res.get("support.agent")) { + { + setMinWidth(70); + } + }; + column.setCellValueFactory((dispute) -> new ReadOnlyObjectWrapper<>(dispute.getValue())); + column.setCellFactory( + new Callback<>() { + @Override + public TableCell call(TableColumn column) { + return new TableCell<>() { + @Override + public void updateItem(final Dispute item, boolean empty) { + super.updateItem(item, empty); + if (item != null && !empty) { + NodeAddress agentNodeAddress = getAgentNodeAddress(item.getContract()); + if (agentNodeAddress == null) { + setText(Res.get("shared.na")); + return; + } + + String keyBaseUserName = DisputeAgentLookupMap.getKeyBaseUserName(agentNodeAddress.getFullAddress()); + setText(keyBaseUserName); + } else { + setText(""); + } + } + }; + } + }); + return column; + } + private TableColumn getStateColumn() { TableColumn column = new AutoTooltipTableColumn<>(Res.get("support.state")) { { diff --git a/desktop/src/main/java/bisq/desktop/main/support/dispute/client/mediation/MediationClientView.java b/desktop/src/main/java/bisq/desktop/main/support/dispute/client/mediation/MediationClientView.java index 02170e3835..9c9a99b38e 100644 --- a/desktop/src/main/java/bisq/desktop/main/support/dispute/client/mediation/MediationClientView.java +++ b/desktop/src/main/java/bisq/desktop/main/support/dispute/client/mediation/MediationClientView.java @@ -35,16 +35,21 @@ import bisq.core.support.dispute.mediation.MediationManager; import bisq.core.support.dispute.mediation.MediationSession; import bisq.core.support.dispute.mediation.mediator.MediatorManager; import bisq.core.support.dispute.refund.refundagent.RefundAgentManager; +import bisq.core.trade.Contract; import bisq.core.trade.TradeManager; import bisq.core.util.FormattingUtils; import bisq.core.util.coin.CoinFormatter; +import bisq.network.p2p.NodeAddress; + import bisq.common.config.Config; import bisq.common.crypto.KeyRing; import javax.inject.Inject; import javax.inject.Named; +import javafx.scene.control.TableColumn; + @FxmlView public class MediationClientView extends DisputeClientView { @Inject @@ -103,4 +108,15 @@ public class MediationClientView extends DisputeClientView { .onAction(this::reOpenDispute) .show(); } + + @Override + protected NodeAddress getAgentNodeAddress(Contract contract) { + return contract.getMediatorNodeAddress(); + } + + @Override + protected void maybeAddAgentColumn() { + TableColumn agentColumn = getAgentColumn(); + tableView.getColumns().add(agentColumn); + } } diff --git a/desktop/src/main/java/bisq/desktop/main/support/dispute/client/refund/RefundClientView.java b/desktop/src/main/java/bisq/desktop/main/support/dispute/client/refund/RefundClientView.java index 94cde1f8fe..f1bd6d6da1 100644 --- a/desktop/src/main/java/bisq/desktop/main/support/dispute/client/refund/RefundClientView.java +++ b/desktop/src/main/java/bisq/desktop/main/support/dispute/client/refund/RefundClientView.java @@ -33,16 +33,21 @@ import bisq.core.support.dispute.mediation.mediator.MediatorManager; import bisq.core.support.dispute.refund.RefundManager; import bisq.core.support.dispute.refund.RefundSession; import bisq.core.support.dispute.refund.refundagent.RefundAgentManager; +import bisq.core.trade.Contract; import bisq.core.trade.TradeManager; import bisq.core.util.FormattingUtils; import bisq.core.util.coin.CoinFormatter; +import bisq.network.p2p.NodeAddress; + import bisq.common.config.Config; import bisq.common.crypto.KeyRing; import javax.inject.Inject; import javax.inject.Named; +import javafx.scene.control.TableColumn; + @FxmlView public class RefundClientView extends DisputeClientView { @Inject @@ -73,4 +78,15 @@ public class RefundClientView extends DisputeClientView { protected DisputeSession getConcreteDisputeChatSession(Dispute dispute) { return new RefundSession(dispute, disputeManager.isTrader(dispute)); } + + @Override + protected NodeAddress getAgentNodeAddress(Contract contract) { + return contract.getRefundAgentNodeAddress(); + } + + @Override + protected void maybeAddAgentColumn() { + TableColumn agentColumn = getAgentColumn(); + tableView.getColumns().add(agentColumn); + } } diff --git a/desktop/src/main/java/bisq/desktop/theme-dark.css b/desktop/src/main/java/bisq/desktop/theme-dark.css index 0bc812fdde..a811b47f0d 100644 --- a/desktop/src/main/java/bisq/desktop/theme-dark.css +++ b/desktop/src/main/java/bisq/desktop/theme-dark.css @@ -527,3 +527,7 @@ .jfx-date-picker .left-button, .jfx-date-picker .right-button{ -fx-background-color: derive(-bs-color-gray-0, -10%); } + +.progress-bar > .secondary-bar { + -fx-background-color: -bs-color-gray-0; +} diff --git a/desktop/src/main/java/bisq/desktop/theme-light.css b/desktop/src/main/java/bisq/desktop/theme-light.css index 910f7f4233..76c268cdf5 100644 --- a/desktop/src/main/java/bisq/desktop/theme-light.css +++ b/desktop/src/main/java/bisq/desktop/theme-light.css @@ -114,3 +114,7 @@ .warning-box { -fx-background-color: -bs-yellow-light; } + +.progress-bar > .secondary-bar { + -fx-background-color: -bs-color-gray-3; +} diff --git a/desktop/src/main/java/bisq/desktop/util/FormBuilder.java b/desktop/src/main/java/bisq/desktop/util/FormBuilder.java index f91a4c83ff..94013d6aca 100644 --- a/desktop/src/main/java/bisq/desktop/util/FormBuilder.java +++ b/desktop/src/main/java/bisq/desktop/util/FormBuilder.java @@ -901,20 +901,26 @@ public class FormBuilder { String buttonTitle, String checkBoxTitle, double top) { - Button button = new AutoTooltipButton(buttonTitle); - button.setDefaultButton(true); - CheckBox checkBox = new AutoTooltipCheckBox(checkBoxTitle); - HBox.setMargin(checkBox, new Insets(6, 0, 0, 0)); + final Tuple3 tuple = addButtonCheckBoxWithBox(gridPane, rowIndex, buttonTitle, checkBoxTitle, top); + return new Tuple2<>(tuple.first, tuple.second); + } - HBox hBox = new HBox(); - hBox.setSpacing(20); + public static Tuple3 addButtonCheckBoxWithBox(GridPane gridPane, + int rowIndex, + String buttonTitle, + String checkBoxTitle, + double top) { + Button button = new AutoTooltipButton(buttonTitle); + CheckBox checkBox = new AutoTooltipCheckBox(checkBoxTitle); + + HBox hBox = new HBox(20); + hBox.setAlignment(Pos.CENTER_LEFT); hBox.getChildren().addAll(button, checkBox); GridPane.setRowIndex(hBox, rowIndex); - GridPane.setColumnIndex(hBox, 1); hBox.setPadding(new Insets(top, 0, 0, 0)); gridPane.getChildren().add(hBox); - return new Tuple2<>(button, checkBox); + return new Tuple3<>(button, checkBox, hBox); } /////////////////////////////////////////////////////////////////////////////////////////// @@ -1221,8 +1227,7 @@ public class FormBuilder { int rowIndex, String titleTextfield, String titleCombobox - ) - { + ) { return addTopLabelTextFieldAutocompleteComboBox(gridPane, rowIndex, titleTextfield, titleCombobox, 0); } @@ -1232,8 +1237,7 @@ public class FormBuilder { String titleTextfield, String titleCombobox, double top - ) - { + ) { HBox hBox = new HBox(); hBox.setSpacing(10); @@ -2145,6 +2149,14 @@ public class FormBuilder { return getIconButton(icon, styleClass, "2em"); } + public static Button getRegularIconButton(GlyphIcons icon) { + return getIconButton(icon, "highlight", "1.6em"); + } + + public static Button getRegularIconButton(GlyphIcons icon, String styleClass) { + return getIconButton(icon, styleClass, "1.6em"); + } + public static Button getIconButton(GlyphIcons icon, String styleClass, String iconSize) { if (icon.fontFamily().equals(MATERIAL_DESIGN_ICONS)) { Button iconButton = MaterialDesignIconFactory.get().createIconButton(icon, diff --git a/desktop/src/main/java/bisq/desktop/util/GUIUtil.java b/desktop/src/main/java/bisq/desktop/util/GUIUtil.java index 6407cc2c76..ba1e174d7e 100644 --- a/desktop/src/main/java/bisq/desktop/util/GUIUtil.java +++ b/desktop/src/main/java/bisq/desktop/util/GUIUtil.java @@ -878,16 +878,8 @@ public class GUIUtil { accountAgeWitnessService.getSignState(myWitness); String info = StringUtils.capitalize(signState.getDisplayString()); - MaterialDesignIcon icon; + MaterialDesignIcon icon = getIconForSignState(signState); - switch (signState) { - case PEER_SIGNER: - case ARBITRATOR: - icon = MaterialDesignIcon.APPROVAL; - break; - default: - icon = MaterialDesignIcon.ALERT_CIRCLE_OUTLINE; - } label.setIcon(icon, info); } setGraphic(label); diff --git a/desktop/src/test/java/bisq/desktop/main/offer/offerbook/OfferBookViewModelTest.java b/desktop/src/test/java/bisq/desktop/main/offer/offerbook/OfferBookViewModelTest.java index 05a83cdfcc..dc48c8c545 100644 --- a/desktop/src/test/java/bisq/desktop/main/offer/offerbook/OfferBookViewModelTest.java +++ b/desktop/src/test/java/bisq/desktop/main/offer/offerbook/OfferBookViewModelTest.java @@ -17,6 +17,8 @@ package bisq.desktop.main.offer.offerbook; +import bisq.desktop.main.PriceUtil; + import bisq.core.locale.Country; import bisq.core.locale.CryptoCurrency; import bisq.core.locale.FiatCurrency; @@ -41,6 +43,7 @@ import bisq.core.payment.payload.SepaAccountPayload; import bisq.core.payment.payload.SpecificBanksAccountPayload; import bisq.core.provider.price.MarketPrice; import bisq.core.provider.price.PriceFeedService; +import bisq.core.trade.statistics.TradeStatisticsManager; import bisq.core.util.coin.BsqFormatter; import bisq.core.util.coin.CoinFormatter; import bisq.core.util.coin.ImmutableCoinFormatter; @@ -90,6 +93,13 @@ public class OfferBookViewModelTest { Res.setBaseCurrencyName(usd.getName()); } + private PriceUtil getPriceUtil() { + PriceFeedService priceFeedService = mock(PriceFeedService.class); + TradeStatisticsManager tradeStatisticsManager = mock(TradeStatisticsManager.class); + when(tradeStatisticsManager.getObservableTradeStatisticsSet()).thenReturn(FXCollections.observableSet()); + return new PriceUtil(priceFeedService, tradeStatisticsManager, empty); + } + @Ignore("PaymentAccountPayload needs to be set (has been changed with PB changes)") public void testIsAnyPaymentAccountValidForOffer() { Collection paymentAccounts; @@ -229,7 +239,7 @@ public class OfferBookViewModelTest { when(offerBook.getOfferBookListItems()).thenReturn(offerBookListItems); final OfferBookViewModel model = new OfferBookViewModel(null, null, offerBook, empty, null, null, null, - null, null, null, null, null, coinFormatter, new BsqFormatter()); + null, null, null, getPriceUtil(), null, coinFormatter, new BsqFormatter()); assertEquals(0, model.maxPlacesForAmount.intValue()); } @@ -243,7 +253,7 @@ public class OfferBookViewModelTest { when(offerBook.getOfferBookListItems()).thenReturn(offerBookListItems); final OfferBookViewModel model = new OfferBookViewModel(null, openOfferManager, offerBook, empty, null, null, null, - null, null, null, null, null, coinFormatter, new BsqFormatter()); + null, null, null, getPriceUtil(), null, coinFormatter, new BsqFormatter()); model.activate(); assertEquals(6, model.maxPlacesForAmount.intValue()); @@ -261,7 +271,7 @@ public class OfferBookViewModelTest { when(offerBook.getOfferBookListItems()).thenReturn(offerBookListItems); final OfferBookViewModel model = new OfferBookViewModel(null, openOfferManager, offerBook, empty, null, null, null, - null, null, null, null, null, coinFormatter, new BsqFormatter()); + null, null, null, getPriceUtil(), null, coinFormatter, new BsqFormatter()); model.activate(); assertEquals(15, model.maxPlacesForAmount.intValue()); @@ -280,7 +290,7 @@ public class OfferBookViewModelTest { when(offerBook.getOfferBookListItems()).thenReturn(offerBookListItems); final OfferBookViewModel model = new OfferBookViewModel(null, null, offerBook, empty, null, null, null, - null, null, null, null, null, coinFormatter, new BsqFormatter()); + null, null, null, getPriceUtil(), null, coinFormatter, new BsqFormatter()); assertEquals(0, model.maxPlacesForVolume.intValue()); } @@ -294,7 +304,7 @@ public class OfferBookViewModelTest { when(offerBook.getOfferBookListItems()).thenReturn(offerBookListItems); final OfferBookViewModel model = new OfferBookViewModel(null, openOfferManager, offerBook, empty, null, null, null, - null, null, null, null, null, coinFormatter, new BsqFormatter()); + null, null, null, getPriceUtil(), null, coinFormatter, new BsqFormatter()); model.activate(); assertEquals(5, model.maxPlacesForVolume.intValue()); @@ -312,7 +322,7 @@ public class OfferBookViewModelTest { when(offerBook.getOfferBookListItems()).thenReturn(offerBookListItems); final OfferBookViewModel model = new OfferBookViewModel(null, openOfferManager, offerBook, empty, null, null, null, - null, null, null, null, null, coinFormatter, new BsqFormatter()); + null, null, null, getPriceUtil(), null, coinFormatter, new BsqFormatter()); model.activate(); assertEquals(9, model.maxPlacesForVolume.intValue()); @@ -331,7 +341,7 @@ public class OfferBookViewModelTest { when(offerBook.getOfferBookListItems()).thenReturn(offerBookListItems); final OfferBookViewModel model = new OfferBookViewModel(null, null, offerBook, empty, null, null, null, - null, null, null, null, null, coinFormatter, new BsqFormatter()); + null, null, null, getPriceUtil(), null, coinFormatter, new BsqFormatter()); assertEquals(0, model.maxPlacesForPrice.intValue()); } @@ -345,7 +355,7 @@ public class OfferBookViewModelTest { when(offerBook.getOfferBookListItems()).thenReturn(offerBookListItems); final OfferBookViewModel model = new OfferBookViewModel(null, openOfferManager, offerBook, empty, null, null, null, - null, null, null, null, null, coinFormatter, new BsqFormatter()); + null, null, null, getPriceUtil(), null, coinFormatter, new BsqFormatter()); model.activate(); assertEquals(7, model.maxPlacesForPrice.intValue()); @@ -363,7 +373,7 @@ public class OfferBookViewModelTest { when(offerBook.getOfferBookListItems()).thenReturn(offerBookListItems); final OfferBookViewModel model = new OfferBookViewModel(null, null, offerBook, empty, null, null, null, - null, null, null, null, null, coinFormatter, new BsqFormatter()); + null, null, null, getPriceUtil(), null, coinFormatter, new BsqFormatter()); assertEquals(0, model.maxPlacesForMarketPriceMargin.intValue()); } @@ -391,7 +401,7 @@ public class OfferBookViewModelTest { offerBookListItems.addAll(item1, item2); final OfferBookViewModel model = new OfferBookViewModel(null, openOfferManager, offerBook, empty, null, null, priceFeedService, - null, null, null, null, null, coinFormatter, new BsqFormatter()); + null, null, null, getPriceUtil(), null, coinFormatter, new BsqFormatter()); model.activate(); assertEquals(8, model.maxPlacesForMarketPriceMargin.intValue()); //" (1.97%)" @@ -412,7 +422,7 @@ public class OfferBookViewModelTest { when(priceFeedService.getMarketPrice(anyString())).thenReturn(new MarketPrice("USD", 12684.0450, Instant.now().getEpochSecond(), true)); final OfferBookViewModel model = new OfferBookViewModel(null, openOfferManager, offerBook, empty, null, null, null, - null, null, null, null, null, coinFormatter, new BsqFormatter()); + null, null, null, getPriceUtil(), null, coinFormatter, new BsqFormatter()); final OfferBookListItem item = make(btcBuyItem.but( with(useMarketBasedPrice, true), diff --git a/gradle/witness/gradle-witness.gradle b/gradle/witness/gradle-witness.gradle index 0a49ef0065..9ab1e2d7ce 100644 --- a/gradle/witness/gradle-witness.gradle +++ b/gradle/witness/gradle-witness.gradle @@ -23,7 +23,7 @@ dependencyVerification { 'com.github.bisq-network.netlayer:tor.external:a3606a592d6b6caa6a2fb7db224eaf43c6874c6730da4815bd37ad686b283dcb', 'com.github.bisq-network.netlayer:tor.native:b15aba7fe987185037791c7ec7c529cb001b90d723d047d54aab87aceb3b3d45', 'com.github.bisq-network.netlayer:tor:a974190aa3a031067ccd1dda28a3ae58cad14060792299d86ea38a05fb21afc5', - 'com.github.bisq-network:bitcoinj:f6dd3c2c53f61d7f6aed49cfdcd012b4b9db882efd5e5813a45fc23b026c8d40', + 'com.github.bisq-network:bitcoinj:65ed08fa5777ea4a08599bdd575e7dc1f4ba2d4d5835472551439d6f6252e68a', 'com.github.cd2357.tor-binary:tor-binary-geoip:ae27b6aca1a3a50a046eb11e38202b6d21c2fcd2b8643bbeb5ea85e065fbc1be', 'com.github.cd2357.tor-binary:tor-binary-linux32:7b5d6770aa442ef6d235e8a9bfbaa7c62560690f9fe69ff03c7a752eae84f7dc', 'com.github.cd2357.tor-binary:tor-binary-linux64:24111fa35027599a750b0176392dc1e9417d919414396d1b221ac2e707eaba76', diff --git a/inventory/src/main/java/bisq/inventory/InventoryMonitor.java b/inventory/src/main/java/bisq/inventory/InventoryMonitor.java index 4eacd79991..f99d336d64 100644 --- a/inventory/src/main/java/bisq/inventory/InventoryMonitor.java +++ b/inventory/src/main/java/bisq/inventory/InventoryMonitor.java @@ -85,6 +85,9 @@ public class InventoryMonitor implements SetupListener { // We get more connectivity issues. Cleaning tor cache files helps usually for those problems. File torDir = new File(appDir, "tor"); + if (!torDir.exists()) { + torDir.mkdir(); + } TorSetup torSetup = new TorSetup(torDir); torSetup.cleanupTorFiles(() -> { networkNode = getNetworkNode(torDir); @@ -257,6 +260,7 @@ public class InventoryMonitor implements SetupListener { CoreNetworkProtoResolver networkProtoResolver = new CoreNetworkProtoResolver(Clock.systemDefaultZone()); return new NetworkNodeProvider(networkProtoResolver, ArrayList::new, + null, useLocalhostForP2P, 9999, torDir, diff --git a/inventory/src/main/java/bisq/inventory/InventoryMonitorMain.java b/inventory/src/main/java/bisq/inventory/InventoryMonitorMain.java index 9d954c8791..67925b6fc0 100644 --- a/inventory/src/main/java/bisq/inventory/InventoryMonitorMain.java +++ b/inventory/src/main/java/bisq/inventory/InventoryMonitorMain.java @@ -35,6 +35,7 @@ import java.io.File; import java.util.concurrent.Executors; import java.util.concurrent.ThreadFactory; +import java.util.concurrent.TimeUnit; import ch.qos.logback.classic.Level; @@ -79,13 +80,17 @@ public class InventoryMonitorMain { inventoryMonitor = new InventoryMonitor(appDir, useLocalhostForP2P, network, intervalSec, port); setup(network, appDir); + + // We shutdown after 5 days to avoid potential memory leak issue. + // The start script will restart the app. + UserThread.runAfter(InventoryMonitorMain::shutDown, TimeUnit.DAYS.toSeconds(5)); } private static void setup(BaseCurrencyNetwork network, File appDir) { - AsciiLogo.showAsciiLogo(); String logPath = Paths.get(appDir.getPath(), "bisq").toString(); Log.setup(logPath); Log.setLevel(Level.INFO); + AsciiLogo.showAsciiLogo(); Version.setBaseCryptoNetworkId(network.ordinal()); Res.setup(); // Used for some formatting in the webserver diff --git a/inventory/src/main/resources/inv_btc_mainnet.seednodes b/inventory/src/main/resources/inv_btc_mainnet.seednodes index 71d85b4247..484aac6fd7 100644 --- a/inventory/src/main/resources/inv_btc_mainnet.seednodes +++ b/inventory/src/main/resources/inv_btc_mainnet.seednodes @@ -11,7 +11,3 @@ sn4bsqpc7eb2ntvpsycxbzqt6fre72l4krp2fl5svphfh2eusrqtq3qd.onion:8000 (@miker) devinv3rhon24gqf5v6ondoqgyrbzyqihzyouzv7ptltsewhfmox2zqd.onion:8000 (@devinbileck) devinsn2teu33efff62bnvwbxmfgbfjlgqsu3ad4b4fudx3a725eqnyd.onion:8000 (@devinbileck) devinsn3xuzxhj6pmammrxpydhwwmwp75qkksedo5dn2tlmu7jggo7id.onion:8000 (@devinbileck) -723ljisnynbtdohi.onion:8000 (@emzy) -s67qglwhkgkyvr74.onion:8000 (@emzy) -5quyxpxheyvzmb2d.onion:8000 (@miker) -rm7b56wbrcczpjvl.onion:8000 (@miker) diff --git a/monitor/src/main/java/bisq/monitor/metric/P2PNetworkLoad.java b/monitor/src/main/java/bisq/monitor/metric/P2PNetworkLoad.java index 8c3eab2e63..48c6089776 100644 --- a/monitor/src/main/java/bisq/monitor/metric/P2PNetworkLoad.java +++ b/monitor/src/main/java/bisq/monitor/metric/P2PNetworkLoad.java @@ -116,7 +116,7 @@ public class P2PNetworkLoad extends Metric implements MessageListener, SetupList // start the network node networkNode = new TorNetworkNode(Integer.parseInt(configuration.getProperty(TOR_PROXY_PORT, "9053")), new CoreNetworkProtoResolver(Clock.systemDefaultZone()), false, - new AvailableTor(Monitor.TOR_WORKING_DIR, torHiddenServiceDir.getName())); + new AvailableTor(Monitor.TOR_WORKING_DIR, torHiddenServiceDir.getName()), null); networkNode.start(this); // wait for the HS to be published diff --git a/monitor/src/main/java/bisq/monitor/metric/P2PSeedNodeSnapshotBase.java b/monitor/src/main/java/bisq/monitor/metric/P2PSeedNodeSnapshotBase.java index fa37505fb5..9550b3dae9 100644 --- a/monitor/src/main/java/bisq/monitor/metric/P2PSeedNodeSnapshotBase.java +++ b/monitor/src/main/java/bisq/monitor/metric/P2PSeedNodeSnapshotBase.java @@ -155,7 +155,7 @@ public abstract class P2PSeedNodeSnapshotBase extends Metric implements MessageL // start the network node final NetworkNode networkNode = new TorNetworkNode(Integer.parseInt(configuration.getProperty(TOR_PROXY_PORT, "9054")), new CoreNetworkProtoResolver(Clock.systemDefaultZone()), false, - new AvailableTor(Monitor.TOR_WORKING_DIR, "unused")); + new AvailableTor(Monitor.TOR_WORKING_DIR, "unused"), null); // we do not need to start the networkNode, as we do not need the HS //networkNode.start(this); diff --git a/p2p/src/main/java/bisq/network/http/HttpClientImpl.java b/p2p/src/main/java/bisq/network/http/HttpClientImpl.java index e8e644830c..06a5a234a1 100644 --- a/p2p/src/main/java/bisq/network/http/HttpClientImpl.java +++ b/p2p/src/main/java/bisq/network/http/HttpClientImpl.java @@ -150,7 +150,7 @@ public class HttpClientImpl implements HttpClient { @Nullable String headerKey, @Nullable String headerValue) throws IOException { long ts = System.currentTimeMillis(); - log.info("requestWithoutProxy: URL={}, param={}, httpMethod={}", baseUrl, param, httpMethod); + log.debug("requestWithoutProxy: URL={}, param={}, httpMethod={}", baseUrl, param, httpMethod); try { String spec = httpMethod == HttpMethod.GET ? baseUrl + param : baseUrl; URL url = new URL(spec); @@ -171,7 +171,7 @@ public class HttpClientImpl implements HttpClient { int responseCode = connection.getResponseCode(); if (responseCode == 200) { String response = convertInputStreamToString(connection.getInputStream()); - log.info("Response from {} with param {} took {} ms. Data size:{}, response: {}", + log.debug("Response from {} with param {} took {} ms. Data size:{}, response: {}", baseUrl, param, System.currentTimeMillis() - ts, @@ -223,7 +223,7 @@ public class HttpClientImpl implements HttpClient { @Nullable String headerKey, @Nullable String headerValue) throws IOException { long ts = System.currentTimeMillis(); - log.info("requestWithoutProxy: baseUrl={}, param={}, httpMethod={}", baseUrl, param, httpMethod); + log.debug("doRequestWithProxy: baseUrl={}, param={}, httpMethod={}", baseUrl, param, httpMethod); // This code is adapted from: // http://stackoverflow.com/a/25203021/5616248 @@ -257,7 +257,7 @@ public class HttpClientImpl implements HttpClient { String response = convertInputStreamToString(httpResponse.getEntity().getContent()); int statusCode = httpResponse.getStatusLine().getStatusCode(); if (statusCode == 200) { - log.info("Response from {} took {} ms. Data size:{}, response: {}, param: {}", + log.debug("Response from {} took {} ms. Data size:{}, response: {}, param: {}", baseUrl, System.currentTimeMillis() - ts, Utilities.readableFileSize(response.getBytes().length), diff --git a/p2p/src/main/java/bisq/network/p2p/NetworkNodeProvider.java b/p2p/src/main/java/bisq/network/p2p/NetworkNodeProvider.java index 078db3b21e..e8cf8d9238 100644 --- a/p2p/src/main/java/bisq/network/p2p/NetworkNodeProvider.java +++ b/p2p/src/main/java/bisq/network/p2p/NetworkNodeProvider.java @@ -19,18 +19,19 @@ package bisq.network.p2p; import bisq.network.p2p.network.BridgeAddressProvider; import bisq.network.p2p.network.LocalhostNetworkNode; +import bisq.network.p2p.network.NetworkFilter; import bisq.network.p2p.network.NetworkNode; import bisq.network.p2p.network.NewTor; import bisq.network.p2p.network.RunningTor; +import bisq.network.p2p.network.TorMode; import bisq.network.p2p.network.TorNetworkNode; import bisq.common.config.Config; import bisq.common.proto.network.NetworkProtoResolver; -import javax.inject.Provider; -import javax.inject.Named; - import javax.inject.Inject; +import javax.inject.Named; +import javax.inject.Provider; import java.io.File; @@ -43,6 +44,7 @@ public class NetworkNodeProvider implements Provider { @Inject public NetworkNodeProvider(NetworkProtoResolver networkProtoResolver, BridgeAddressProvider bridgeAddressProvider, + @Nullable NetworkFilter networkFilter, @Named(Config.USE_LOCALHOST_FOR_P2P) boolean useLocalhostForP2P, @Named(Config.NODE_PORT) int port, @Named(Config.TOR_DIR) File torDir, @@ -52,13 +54,33 @@ public class NetworkNodeProvider implements Provider { @Named(Config.TOR_CONTROL_PASSWORD) String password, @Nullable @Named(Config.TOR_CONTROL_COOKIE_FILE) File cookieFile, @Named(Config.TOR_STREAM_ISOLATION) boolean streamIsolation, - @Named(Config.TOR_CONTROL_USE_SAFE_COOKIE_AUTH) boolean useSafeCookieAuthentication ) { - networkNode = useLocalhostForP2P ? - new LocalhostNetworkNode(port, networkProtoResolver) : - new TorNetworkNode(port, networkProtoResolver, streamIsolation, - controlPort != Config.UNSPECIFIED_PORT ? - new RunningTor(torDir, controlPort, password, cookieFile, useSafeCookieAuthentication) : - new NewTor(torDir, torrcFile, torrcOptions, bridgeAddressProvider.getBridgeAddresses())); + @Named(Config.TOR_CONTROL_USE_SAFE_COOKIE_AUTH) boolean useSafeCookieAuthentication) { + if (useLocalhostForP2P) { + networkNode = new LocalhostNetworkNode(port, networkProtoResolver, networkFilter); + } else { + TorMode torMode = getTorMode(bridgeAddressProvider, + torDir, + torrcFile, + torrcOptions, + controlPort, + password, + cookieFile, + useSafeCookieAuthentication); + networkNode = new TorNetworkNode(port, networkProtoResolver, streamIsolation, torMode, networkFilter); + } + } + + private TorMode getTorMode(BridgeAddressProvider bridgeAddressProvider, + File torDir, + @Nullable File torrcFile, + String torrcOptions, + int controlPort, + String password, + @Nullable File cookieFile, + boolean useSafeCookieAuthentication) { + return controlPort != Config.UNSPECIFIED_PORT ? + new RunningTor(torDir, controlPort, password, cookieFile, useSafeCookieAuthentication) : + new NewTor(torDir, torrcFile, torrcOptions, bridgeAddressProvider.getBridgeAddresses()); } @Override diff --git a/p2p/src/main/java/bisq/network/p2p/P2PModule.java b/p2p/src/main/java/bisq/network/p2p/P2PModule.java index 896fe8098c..e5df2c6e80 100644 --- a/p2p/src/main/java/bisq/network/p2p/P2PModule.java +++ b/p2p/src/main/java/bisq/network/p2p/P2PModule.java @@ -22,7 +22,6 @@ import bisq.network.http.HttpClient; import bisq.network.http.HttpClientImpl; import bisq.network.p2p.network.Connection; import bisq.network.p2p.network.NetworkNode; -import bisq.network.p2p.peers.BanList; import bisq.network.p2p.peers.Broadcaster; import bisq.network.p2p.peers.PeerManager; import bisq.network.p2p.peers.getdata.RequestDataManager; @@ -68,7 +67,6 @@ public class P2PModule extends AppModule { bind(PeerExchangeManager.class).in(Singleton.class); bind(KeepAliveManager.class).in(Singleton.class); bind(Broadcaster.class).in(Singleton.class); - bind(BanList.class).in(Singleton.class); bind(NetworkNode.class).toProvider(NetworkNodeProvider.class).in(Singleton.class); bind(Socks5ProxyProvider.class).in(Singleton.class); bind(HttpClient.class).to(HttpClientImpl.class); diff --git a/p2p/src/main/java/bisq/network/p2p/network/Connection.java b/p2p/src/main/java/bisq/network/p2p/network/Connection.java index 3a03fd0231..f6a1ed15e8 100644 --- a/p2p/src/main/java/bisq/network/p2p/network/Connection.java +++ b/p2p/src/main/java/bisq/network/p2p/network/Connection.java @@ -24,10 +24,10 @@ import bisq.network.p2p.NodeAddress; import bisq.network.p2p.PrefixedSealedAndSignedMessage; import bisq.network.p2p.SendersNodeAddressMessage; import bisq.network.p2p.SupportedCapabilitiesMessage; -import bisq.network.p2p.peers.BanList; import bisq.network.p2p.peers.getdata.messages.GetDataRequest; import bisq.network.p2p.peers.getdata.messages.GetDataResponse; import bisq.network.p2p.peers.keepalive.messages.KeepAliveMessage; +import bisq.network.p2p.storage.P2PDataStorage; import bisq.network.p2p.storage.messages.AddDataMessage; import bisq.network.p2p.storage.messages.AddPersistableNetworkPayloadMessage; import bisq.network.p2p.storage.payload.CapabilityRequiringPayload; @@ -68,9 +68,13 @@ import java.io.OptionalDataException; import java.io.StreamCorruptedException; import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; import java.util.List; +import java.util.Map; import java.util.Optional; import java.util.Queue; +import java.util.Set; import java.util.UUID; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentLinkedQueue; @@ -136,6 +140,8 @@ public class Connection implements HasCapabilities, Runnable, MessageListener { private final Socket socket; // private final MessageListener messageListener; private final ConnectionListener connectionListener; + @Nullable + private final NetworkFilter networkFilter; @Getter private final String uid; private final ExecutorService singleThreadExecutor = Executors.newSingleThreadExecutor(runnable -> new Thread(runnable, "Connection.java executor-service")); @@ -179,9 +185,11 @@ public class Connection implements HasCapabilities, Runnable, MessageListener { MessageListener messageListener, ConnectionListener connectionListener, @Nullable NodeAddress peersNodeAddress, - NetworkProtoResolver networkProtoResolver) { + NetworkProtoResolver networkProtoResolver, + @Nullable NetworkFilter networkFilter) { this.socket = socket; this.connectionListener = connectionListener; + this.networkFilter = networkFilter; uid = UUID.randomUUID().toString(); statistic = new Statistic(); @@ -204,9 +212,12 @@ public class Connection implements HasCapabilities, Runnable, MessageListener { // We create a thread for handling inputStream data singleThreadExecutor.submit(this); - if (peersNodeAddress != null) + if (peersNodeAddress != null) { setPeersNodeAddress(peersNodeAddress); - + if (networkFilter != null && networkFilter.isPeerBanned(peersNodeAddress)) { + reportInvalidRequest(RuleViolation.PEER_BANNED); + } + } UserThread.execute(() -> connectionListener.onConnection(this)); } catch (Throwable e) { handleException(e); @@ -230,88 +241,98 @@ public class Connection implements HasCapabilities, Runnable, MessageListener { public void sendMessage(NetworkEnvelope networkEnvelope) { log.debug(">> Send networkEnvelope of type: {}", networkEnvelope.getClass().getSimpleName()); - if (!stopped) { - if (noCapabilityRequiredOrCapabilityIsSupported(networkEnvelope)) { - try { - String peersNodeAddress = peersNodeAddressOptional.map(NodeAddress::toString).orElse("null"); + if (stopped) { + log.debug("called sendMessage but was already stopped"); + return; + } - if (networkEnvelope instanceof PrefixedSealedAndSignedMessage && peersNodeAddressOptional.isPresent()) { - setPeerType(Connection.PeerType.DIRECT_MSG_PEER); + if (networkFilter != null && + peersNodeAddressOptional.isPresent() && + networkFilter.isPeerBanned(peersNodeAddressOptional.get())) { + reportInvalidRequest(RuleViolation.PEER_BANNED); + return; + } - log.debug("\n\n>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n" + - "Sending direct message to peer" + - "Write object to outputStream to peer: {} (uid={})\ntruncated message={} / size={}" + - "\n>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n", - peersNodeAddress, uid, Utilities.toTruncatedString(networkEnvelope), -1); - } else if (networkEnvelope instanceof GetDataResponse && ((GetDataResponse) networkEnvelope).isGetUpdatedDataResponse()) { - setPeerType(Connection.PeerType.PEER); - } + if (!noCapabilityRequiredOrCapabilityIsSupported(networkEnvelope)) { + log.debug("Capability for networkEnvelope is required but not supported"); + return; + } - // Throttle outbound network_messages - long now = System.currentTimeMillis(); - long elapsed = now - lastSendTimeStamp; - if (elapsed < getSendMsgThrottleTrigger()) { - log.debug("We got 2 sendMessage requests in less than {} ms. We set the thread to sleep " + - "for {} ms to avoid flooding our peer. lastSendTimeStamp={}, now={}, elapsed={}, networkEnvelope={}", - getSendMsgThrottleTrigger(), getSendMsgThrottleSleep(), lastSendTimeStamp, now, elapsed, - networkEnvelope.getClass().getSimpleName()); + try { + if (networkEnvelope instanceof PrefixedSealedAndSignedMessage && peersNodeAddressOptional.isPresent()) { + setPeerType(Connection.PeerType.DIRECT_MSG_PEER); - // check if BundleOfEnvelopes is supported - if (getCapabilities().containsAll(new Capabilities(Capability.BUNDLE_OF_ENVELOPES))) { - synchronized (lock) { - // check if current envelope fits size - // - no? create new envelope - if (queueOfBundles.isEmpty() || queueOfBundles.element().toProtoNetworkEnvelope().getSerializedSize() + networkEnvelope.toProtoNetworkEnvelope().getSerializedSize() > MAX_PERMITTED_MESSAGE_SIZE * 0.9) { - // - no? create a bucket - queueOfBundles.add(new BundleOfEnvelopes()); + log.debug("\n\n>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n" + + "Sending direct message to peer" + + "Write object to outputStream to peer: {} (uid={})\ntruncated message={} / size={}" + + "\n>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n", + peersNodeAddressOptional.map(NodeAddress::toString).orElse("null"), + uid, Utilities.toTruncatedString(networkEnvelope), -1); + } else if (networkEnvelope instanceof GetDataResponse && ((GetDataResponse) networkEnvelope).isGetUpdatedDataResponse()) { + setPeerType(Connection.PeerType.PEER); + } - // - and schedule it for sending - lastSendTimeStamp += getSendMsgThrottleSleep(); + // Throttle outbound network_messages + long now = System.currentTimeMillis(); + long elapsed = now - lastSendTimeStamp; + if (elapsed < getSendMsgThrottleTrigger()) { + log.debug("We got 2 sendMessage requests in less than {} ms. We set the thread to sleep " + + "for {} ms to avoid flooding our peer. lastSendTimeStamp={}, now={}, elapsed={}, networkEnvelope={}", + getSendMsgThrottleTrigger(), getSendMsgThrottleSleep(), lastSendTimeStamp, now, elapsed, + networkEnvelope.getClass().getSimpleName()); - bundleSender.schedule(() -> { - if (!stopped) { - synchronized (lock) { - BundleOfEnvelopes bundle = queueOfBundles.poll(); - if (bundle != null && !stopped) { - NetworkEnvelope envelope = bundle.getEnvelopes().size() == 1 ? - bundle.getEnvelopes().get(0) : - bundle; - try { - protoOutputStream.writeEnvelope(envelope); - } catch (Throwable t) { - log.error("Sending envelope of class {} to address {} " + - "failed due {}", - envelope.getClass().getSimpleName(), - this.getPeersNodeAddressOptional(), - t.toString()); - log.error("envelope: {}", envelope); - } - } + // check if BundleOfEnvelopes is supported + if (getCapabilities().containsAll(new Capabilities(Capability.BUNDLE_OF_ENVELOPES))) { + synchronized (lock) { + // check if current envelope fits size + // - no? create new envelope + if (queueOfBundles.isEmpty() || queueOfBundles.element().toProtoNetworkEnvelope().getSerializedSize() + networkEnvelope.toProtoNetworkEnvelope().getSerializedSize() > MAX_PERMITTED_MESSAGE_SIZE * 0.9) { + // - no? create a bucket + queueOfBundles.add(new BundleOfEnvelopes()); + + // - and schedule it for sending + lastSendTimeStamp += getSendMsgThrottleSleep(); + + bundleSender.schedule(() -> { + if (!stopped) { + synchronized (lock) { + BundleOfEnvelopes bundle = queueOfBundles.poll(); + if (bundle != null && !stopped) { + NetworkEnvelope envelope = bundle.getEnvelopes().size() == 1 ? + bundle.getEnvelopes().get(0) : + bundle; + try { + protoOutputStream.writeEnvelope(envelope); + } catch (Throwable t) { + log.error("Sending envelope of class {} to address {} " + + "failed due {}", + envelope.getClass().getSimpleName(), + this.getPeersNodeAddressOptional(), + t.toString()); + log.error("envelope: {}", envelope); } } - }, lastSendTimeStamp - now, TimeUnit.MILLISECONDS); + } } - - // - yes? add to bucket - queueOfBundles.element().add(networkEnvelope); - } - return; + }, lastSendTimeStamp - now, TimeUnit.MILLISECONDS); } - Thread.sleep(getSendMsgThrottleSleep()); + // - yes? add to bucket + queueOfBundles.element().add(networkEnvelope); } - - lastSendTimeStamp = now; - - if (!stopped) { - protoOutputStream.writeEnvelope(networkEnvelope); - } - } catch (Throwable t) { - handleException(t); + return; } + + Thread.sleep(getSendMsgThrottleSleep()); } - } else { - log.debug("called sendMessage but was already stopped"); + + lastSendTimeStamp = now; + + if (!stopped) { + protoOutputStream.writeEnvelope(networkEnvelope); + } + } catch (Throwable t) { + handleException(t); } } @@ -421,16 +442,40 @@ public class Connection implements HasCapabilities, Runnable, MessageListener { @Override public void onMessage(NetworkEnvelope networkEnvelope, Connection connection) { checkArgument(connection.equals(this)); - if (networkEnvelope instanceof BundleOfEnvelopes) { - for (NetworkEnvelope current : ((BundleOfEnvelopes) networkEnvelope).getEnvelopes()) { - UserThread.execute(() -> messageListeners.forEach(e -> e.onMessage(current, connection))); - } + onBundleOfEnvelopes((BundleOfEnvelopes) networkEnvelope, connection); } else { UserThread.execute(() -> messageListeners.forEach(e -> e.onMessage(networkEnvelope, connection))); } } + private void onBundleOfEnvelopes(BundleOfEnvelopes networkEnvelope, Connection connection) { + Map> itemsByHash = new HashMap<>(); + Set envelopesToProcess = new HashSet<>(); + List networkEnvelopes = networkEnvelope.getEnvelopes(); + for (NetworkEnvelope current : networkEnvelopes) { + if (current instanceof AddPersistableNetworkPayloadMessage) { + PersistableNetworkPayload persistableNetworkPayload = ((AddPersistableNetworkPayloadMessage) current).getPersistableNetworkPayload(); + byte[] hash = persistableNetworkPayload.getHash(); + String itemName = persistableNetworkPayload.getClass().getSimpleName(); + P2PDataStorage.ByteArray byteArray = new P2PDataStorage.ByteArray(hash); + itemsByHash.putIfAbsent(byteArray, new HashSet<>()); + Set envelopesByHash = itemsByHash.get(byteArray); + if (!envelopesByHash.contains(current)) { + envelopesByHash.add(current); + envelopesToProcess.add(current); + } else { + log.debug("We got duplicated items for {}. We ignore the duplicates. Hash: {}", + itemName, Utilities.encodeToHex(hash)); + } + } else { + envelopesToProcess.add(current); + } + } + envelopesToProcess.forEach(envelope -> UserThread.execute(() -> + messageListeners.forEach(listener -> listener.onMessage(envelope, connection)))); + } + /////////////////////////////////////////////////////////////////////////////////////////// // Setters @@ -455,13 +500,9 @@ public class Connection implements HasCapabilities, Runnable, MessageListener { } peersNodeAddressProperty.set(peerNodeAddress); - - if (BanList.isBanned(peerNodeAddress)) { - log.warn("We detected a connection to a banned peer. We will close that connection. (setPeersNodeAddress)"); - reportInvalidRequest(RuleViolation.PEER_BANNED); - } } + /////////////////////////////////////////////////////////////////////////////////////////// // Getters /////////////////////////////////////////////////////////////////////////////////////////// @@ -709,6 +750,13 @@ public class Connection implements HasCapabilities, Runnable, MessageListener { return; } + if (networkFilter != null && + peersNodeAddressOptional.isPresent() && + networkFilter.isPeerBanned(peersNodeAddressOptional.get())) { + reportInvalidRequest(RuleViolation.PEER_BANNED); + return; + } + // Throttle inbound network_messages long now = System.currentTimeMillis(); long elapsed = now - lastReadTimeStamp; @@ -718,7 +766,6 @@ public class Connection implements HasCapabilities, Runnable, MessageListener { lastReadTimeStamp, now, elapsed); Thread.sleep(20); } - // Reading the protobuffer message from the inputStream protobuf.NetworkEnvelope proto = protobuf.NetworkEnvelope.parseDelimitedFrom(protoInputStream); @@ -813,11 +860,10 @@ public class Connection implements HasCapabilities, Runnable, MessageListener { "connection={}", proto.getCloseConnectionMessage().getReason(), this); if (CloseConnectionReason.PEER_BANNED.name().equals(proto.getCloseConnectionMessage().getReason())) { - log.warn("We got shut down because we are banned by the other peer. (InputHandler.run CloseConnectionMessage)"); - shutDown(CloseConnectionReason.PEER_BANNED); - } else { - shutDown(CloseConnectionReason.CLOSE_REQUESTED_BY_PEER); + log.warn("We got shut down because we are banned by the other peer. " + + "(InputHandler.run CloseConnectionMessage). Peer: {}", getPeersNodeAddressOptional()); } + shutDown(CloseConnectionReason.CLOSE_REQUESTED_BY_PEER); return; } else if (!stopped) { // We don't want to get the activity ts updated by ping/pong msg @@ -855,6 +901,11 @@ public class Connection implements HasCapabilities, Runnable, MessageListener { // We check for a banned peer inside setPeersNodeAddress() and shut down if banned. setPeersNodeAddress(senderNodeAddress); } + + if (networkFilter != null && networkFilter.isPeerBanned(senderNodeAddress)) { + reportInvalidRequest(RuleViolation.PEER_BANNED); + return; + } } } diff --git a/p2p/src/main/java/bisq/network/p2p/network/InboundConnection.java b/p2p/src/main/java/bisq/network/p2p/network/InboundConnection.java index 1e6948fab1..b691d906d2 100644 --- a/p2p/src/main/java/bisq/network/p2p/network/InboundConnection.java +++ b/p2p/src/main/java/bisq/network/p2p/network/InboundConnection.java @@ -21,11 +21,14 @@ import bisq.common.proto.network.NetworkProtoResolver; import java.net.Socket; +import org.jetbrains.annotations.Nullable; + public class InboundConnection extends Connection { public InboundConnection(Socket socket, MessageListener messageListener, ConnectionListener connectionListener, - NetworkProtoResolver networkProtoResolver) { - super(socket, messageListener, connectionListener, null, networkProtoResolver); + NetworkProtoResolver networkProtoResolver, + @Nullable NetworkFilter networkFilter) { + super(socket, messageListener, connectionListener, null, networkProtoResolver, networkFilter); } } diff --git a/p2p/src/main/java/bisq/network/p2p/network/LocalhostNetworkNode.java b/p2p/src/main/java/bisq/network/p2p/network/LocalhostNetworkNode.java index b49bff1e73..97fce6e14f 100644 --- a/p2p/src/main/java/bisq/network/p2p/network/LocalhostNetworkNode.java +++ b/p2p/src/main/java/bisq/network/p2p/network/LocalhostNetworkNode.java @@ -54,8 +54,10 @@ public class LocalhostNetworkNode extends NetworkNode { // Constructor /////////////////////////////////////////////////////////////////////////////////////////// - public LocalhostNetworkNode(int port, NetworkProtoResolver networkProtoResolver) { - super(port, networkProtoResolver); + public LocalhostNetworkNode(int port, + NetworkProtoResolver networkProtoResolver, + @Nullable NetworkFilter networkFilter) { + super(port, networkProtoResolver, networkFilter); } @Override diff --git a/p2p/src/main/java/bisq/network/p2p/network/NetworkFilter.java b/p2p/src/main/java/bisq/network/p2p/network/NetworkFilter.java new file mode 100644 index 0000000000..3dcf040e21 --- /dev/null +++ b/p2p/src/main/java/bisq/network/p2p/network/NetworkFilter.java @@ -0,0 +1,28 @@ +/* + * This file is part of Bisq. + * + * Bisq is free software: you can redistribute it and/or modify it + * under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or (at + * your option) any later version. + * + * Bisq is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public + * License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with Bisq. If not, see . + */ + +package bisq.network.p2p.network; + +import bisq.network.p2p.NodeAddress; + +import java.util.function.Function; + +public interface NetworkFilter { + boolean isPeerBanned(NodeAddress nodeAddress); + + void setBannedNodeFunction(Function isNodeAddressBanned); +} diff --git a/p2p/src/main/java/bisq/network/p2p/network/NetworkNode.java b/p2p/src/main/java/bisq/network/p2p/network/NetworkNode.java index c2695833f7..ae32233bc1 100644 --- a/p2p/src/main/java/bisq/network/p2p/network/NetworkNode.java +++ b/p2p/src/main/java/bisq/network/p2p/network/NetworkNode.java @@ -69,6 +69,8 @@ public abstract class NetworkNode implements MessageListener { final int servicePort; private final NetworkProtoResolver networkProtoResolver; + @Nullable + private final NetworkFilter networkFilter; private final CopyOnWriteArraySet inBoundConnections = new CopyOnWriteArraySet<>(); private final CopyOnWriteArraySet messageListeners = new CopyOnWriteArraySet<>(); @@ -87,9 +89,12 @@ public abstract class NetworkNode implements MessageListener { // Constructor /////////////////////////////////////////////////////////////////////////////////////////// - NetworkNode(int servicePort, NetworkProtoResolver networkProtoResolver) { + NetworkNode(int servicePort, + NetworkProtoResolver networkProtoResolver, + @Nullable NetworkFilter networkFilter) { this.servicePort = servicePort; this.networkProtoResolver = networkProtoResolver; + this.networkFilter = networkFilter; } /////////////////////////////////////////////////////////////////////////////////////////// @@ -190,7 +195,8 @@ public abstract class NetworkNode implements MessageListener { NetworkNode.this, connectionListener, peersNodeAddress, - networkProtoResolver); + networkProtoResolver, + networkFilter); if (log.isDebugEnabled()) { log.debug("\n\n%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n" + @@ -457,7 +463,8 @@ public abstract class NetworkNode implements MessageListener { server = new Server(serverSocket, NetworkNode.this, connectionListener, - networkProtoResolver); + networkProtoResolver, + networkFilter); executorService.submit(server); } diff --git a/p2p/src/main/java/bisq/network/p2p/network/OutboundConnection.java b/p2p/src/main/java/bisq/network/p2p/network/OutboundConnection.java index 5b27d02e2d..6c6c6d341a 100644 --- a/p2p/src/main/java/bisq/network/p2p/network/OutboundConnection.java +++ b/p2p/src/main/java/bisq/network/p2p/network/OutboundConnection.java @@ -23,12 +23,15 @@ import bisq.common.proto.network.NetworkProtoResolver; import java.net.Socket; +import org.jetbrains.annotations.Nullable; + public class OutboundConnection extends Connection { public OutboundConnection(Socket socket, MessageListener messageListener, ConnectionListener connectionListener, NodeAddress peersNodeAddress, - NetworkProtoResolver networkProtoResolver) { - super(socket, messageListener, connectionListener, peersNodeAddress, networkProtoResolver); + NetworkProtoResolver networkProtoResolver, + @Nullable NetworkFilter networkFilter) { + super(socket, messageListener, connectionListener, peersNodeAddress, networkProtoResolver, networkFilter); } } diff --git a/p2p/src/main/java/bisq/network/p2p/network/Server.java b/p2p/src/main/java/bisq/network/p2p/network/Server.java index 8f8db624eb..f44622e602 100644 --- a/p2p/src/main/java/bisq/network/p2p/network/Server.java +++ b/p2p/src/main/java/bisq/network/p2p/network/Server.java @@ -31,12 +31,16 @@ import java.util.concurrent.CopyOnWriteArraySet; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.jetbrains.annotations.Nullable; + // Runs in UserThread class Server implements Runnable { private static final Logger log = LoggerFactory.getLogger(Server.class); private final MessageListener messageListener; private final ConnectionListener connectionListener; + @Nullable + private final NetworkFilter networkFilter; // accessed from different threads private final ServerSocket serverSocket; @@ -48,11 +52,13 @@ class Server implements Runnable { public Server(ServerSocket serverSocket, MessageListener messageListener, ConnectionListener connectionListener, - NetworkProtoResolver networkProtoResolver) { + NetworkProtoResolver networkProtoResolver, + @Nullable NetworkFilter networkFilter) { this.networkProtoResolver = networkProtoResolver; this.serverSocket = serverSocket; this.messageListener = messageListener; this.connectionListener = connectionListener; + this.networkFilter = networkFilter; } @Override @@ -69,7 +75,8 @@ class Server implements Runnable { InboundConnection connection = new InboundConnection(socket, messageListener, connectionListener, - networkProtoResolver); + networkProtoResolver, + networkFilter); log.debug("\n\n%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n" + "Server created new inbound connection:" diff --git a/p2p/src/main/java/bisq/network/p2p/network/Statistic.java b/p2p/src/main/java/bisq/network/p2p/network/Statistic.java index a7544238d9..a6c1ba8950 100644 --- a/p2p/src/main/java/bisq/network/p2p/network/Statistic.java +++ b/p2p/src/main/java/bisq/network/p2p/network/Statistic.java @@ -30,6 +30,7 @@ import javafx.beans.property.SimpleLongProperty; import java.util.Date; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.TimeUnit; import lombok.extern.slf4j.Slf4j; @@ -85,7 +86,7 @@ public class Statistic { totalReceivedBytes.get() / 1024d, numTotalReceivedMessages.get(), totalReceivedMessages, numTotalReceivedMessagesPerSec.get()); - }, 60); + }, TimeUnit.MINUTES.toSeconds(5)); } public static LongProperty totalSentBytesProperty() { diff --git a/p2p/src/main/java/bisq/network/p2p/network/TorNetworkNode.java b/p2p/src/main/java/bisq/network/p2p/network/TorNetworkNode.java index a1aae19bab..a57e5404bc 100644 --- a/p2p/src/main/java/bisq/network/p2p/network/TorNetworkNode.java +++ b/p2p/src/main/java/bisq/network/p2p/network/TorNetworkNode.java @@ -87,9 +87,12 @@ public class TorNetworkNode extends NetworkNode { // Constructor /////////////////////////////////////////////////////////////////////////////////////////// - public TorNetworkNode(int servicePort, NetworkProtoResolver networkProtoResolver, boolean useStreamIsolation, - TorMode torMode) { - super(servicePort, networkProtoResolver); + public TorNetworkNode(int servicePort, + NetworkProtoResolver networkProtoResolver, + boolean useStreamIsolation, + TorMode torMode, + @Nullable NetworkFilter networkFilter) { + super(servicePort, networkProtoResolver, networkFilter); this.torMode = torMode; this.streamIsolation = useStreamIsolation; createExecutorService(); @@ -184,7 +187,9 @@ public class TorNetworkNode extends NetworkNode { log.info("Tor shut down completed"); } else { log.info("Tor has not been created yet. We cancel the torStartupFuture."); - torStartupFuture.cancel(true); + if (torStartupFuture != null) { + torStartupFuture.cancel(true); + } log.info("torStartupFuture cancelled"); } } catch (Throwable e) { @@ -278,7 +283,6 @@ public class TorNetworkNode extends NetworkNode { } return null; }); - log.info("It will take some time for the HS to be reachable (~40 seconds). You will be notified about this"); } catch (TorCtlException e) { String msg = e.getCause() != null ? e.getCause().toString() : e.toString(); log.error("Tor node creation failed: {}", msg); diff --git a/p2p/src/main/java/bisq/network/p2p/peers/BanList.java b/p2p/src/main/java/bisq/network/p2p/peers/BanList.java deleted file mode 100644 index 212a715a95..0000000000 --- a/p2p/src/main/java/bisq/network/p2p/peers/BanList.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * This file is part of Bisq. - * - * Bisq is free software: you can redistribute it and/or modify it - * under the terms of the GNU Affero General Public License as published by - * the Free Software Foundation, either version 3 of the License, or (at - * your option) any later version. - * - * Bisq is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public - * License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with Bisq. If not, see . - */ - -package bisq.network.p2p.peers; - -import bisq.network.p2p.NodeAddress; - -import bisq.common.config.Config; - -import javax.inject.Named; - -import javax.inject.Inject; - -import org.apache.commons.lang3.StringUtils; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; -import java.util.stream.Collectors; - -public class BanList { - private static List list = new ArrayList<>(); - - public static void add(NodeAddress onionAddress) { - list.add(onionAddress); - } - - public static boolean isBanned(NodeAddress nodeAddress) { - return list.contains(nodeAddress); - } - - @Inject - public BanList(@Named(Config.BAN_LIST) List banList) { - if (!banList.isEmpty()) - BanList.list = banList.stream().map(NodeAddress::new).collect(Collectors.toList()); - } -} diff --git a/p2p/src/main/java/bisq/network/p2p/peers/Broadcaster.java b/p2p/src/main/java/bisq/network/p2p/peers/Broadcaster.java index cdfdde5c46..e48b867571 100644 --- a/p2p/src/main/java/bisq/network/p2p/peers/Broadcaster.java +++ b/p2p/src/main/java/bisq/network/p2p/peers/Broadcaster.java @@ -73,6 +73,10 @@ public class Broadcaster implements BroadcastHandler.ResultHandler { } } + public void flush() { + maybeBroadcastBundle(); + } + private void doShutDown() { broadcastHandlers.forEach(BroadcastHandler::cancel); if (timer != null) { diff --git a/p2p/src/main/java/bisq/network/p2p/peers/getdata/RequestDataHandler.java b/p2p/src/main/java/bisq/network/p2p/peers/getdata/RequestDataHandler.java index e00fdd67bf..999c750c17 100644 --- a/p2p/src/main/java/bisq/network/p2p/peers/getdata/RequestDataHandler.java +++ b/p2p/src/main/java/bisq/network/p2p/peers/getdata/RequestDataHandler.java @@ -28,12 +28,13 @@ import bisq.network.p2p.peers.getdata.messages.GetDataResponse; import bisq.network.p2p.storage.P2PDataStorage; import bisq.network.p2p.storage.payload.PersistableNetworkPayload; import bisq.network.p2p.storage.payload.ProtectedStorageEntry; -import bisq.network.p2p.storage.payload.ProtectedStoragePayload; import bisq.common.Timer; import bisq.common.UserThread; import bisq.common.proto.network.NetworkEnvelope; import bisq.common.proto.network.NetworkPayload; +import bisq.common.util.Tuple2; +import bisq.common.util.Utilities; import com.google.common.util.concurrent.FutureCallback; import com.google.common.util.concurrent.Futures; @@ -41,10 +42,10 @@ import com.google.common.util.concurrent.MoreExecutors; import com.google.common.util.concurrent.SettableFuture; import java.util.HashMap; -import java.util.HashSet; import java.util.Map; import java.util.Random; import java.util.Set; +import java.util.concurrent.atomic.AtomicInteger; import lombok.extern.slf4j.Slf4j; @@ -134,7 +135,7 @@ class RequestDataHandler implements MessageListener { handleFault(errorMessage, nodeAddress, CloseConnectionReason.SEND_MSG_TIMEOUT); } else { log.trace("We have stopped already. We ignore that timeoutTimer.run call. " + - "Might be caused by an previous networkNode.sendMessage.onFailure."); + "Might be caused by a previous networkNode.sendMessage.onFailure."); } }, TIMEOUT); @@ -152,7 +153,7 @@ class RequestDataHandler implements MessageListener { log.trace("Send {} to {} succeeded.", getDataRequest, nodeAddress); } else { log.trace("We have stopped already. We ignore that networkNode.sendMessage.onSuccess call." + - "Might be caused by an previous timeout."); + "Might be caused by a previous timeout."); } } @@ -166,7 +167,7 @@ class RequestDataHandler implements MessageListener { handleFault(errorMessage, nodeAddress, CloseConnectionReason.SEND_MSG_FAILURE); } else { log.trace("We have stopped already. We ignore that networkNode.sendMessage.onFailure call. " + - "Might be caused by an previous timeout."); + "Might be caused by a previous timeout."); } } }, MoreExecutors.directExecutor()); @@ -187,10 +188,7 @@ class RequestDataHandler implements MessageListener { if (!stopped) { long ts1 = System.currentTimeMillis(); GetDataResponse getDataResponse = (GetDataResponse) networkEnvelope; - final Set dataSet = getDataResponse.getDataSet(); - Set persistableNetworkPayloadSet = getDataResponse.getPersistableNetworkPayloadSet(); - logContents(networkEnvelope, dataSet, persistableNetworkPayloadSet); - + logContents(getDataResponse); if (getDataResponse.getRequestNonce() == nonce) { stopTimeoutTimer(); if (!connection.getPeersNodeAddressOptional().isPresent()) { @@ -230,35 +228,18 @@ class RequestDataHandler implements MessageListener { // Private /////////////////////////////////////////////////////////////////////////////////////////// - private void logContents(NetworkEnvelope networkEnvelope, - Set dataSet, - Set persistableNetworkPayloadSet) { - Map> payloadByClassName = new HashMap<>(); - dataSet.forEach(e -> { - ProtectedStoragePayload protectedStoragePayload = e.getProtectedStoragePayload(); - if (protectedStoragePayload == null) { - log.warn("StoragePayload was null: {}", networkEnvelope.toString()); - return; - } - - // For logging different data types - String className = protectedStoragePayload.getClass().getSimpleName(); - if (!payloadByClassName.containsKey(className)) - payloadByClassName.put(className, new HashSet<>()); - - payloadByClassName.get(className).add(protectedStoragePayload); + private void logContents(GetDataResponse getDataResponse) { + Set dataSet = getDataResponse.getDataSet(); + Set persistableNetworkPayloadSet = getDataResponse.getPersistableNetworkPayloadSet(); + Map> numPayloadsByClassName = new HashMap<>(); + dataSet.forEach(protectedStorageEntry -> { + String className = protectedStorageEntry.getProtectedStoragePayload().getClass().getSimpleName(); + addDetails(numPayloadsByClassName, protectedStorageEntry, className); }); - persistableNetworkPayloadSet.forEach(persistableNetworkPayload -> { - // For logging different data types String className = persistableNetworkPayload.getClass().getSimpleName(); - if (!payloadByClassName.containsKey(className)) - payloadByClassName.put(className, new HashSet<>()); - - payloadByClassName.get(className).add(persistableNetworkPayload); + addDetails(numPayloadsByClassName, persistableNetworkPayload, className); }); - - // Log different data types StringBuilder sb = new StringBuilder(); String sep = System.lineSeparator(); sb.append(sep).append("#################################################################").append(sep); @@ -266,14 +247,27 @@ class RequestDataHandler implements MessageListener { int items = dataSet.size() + persistableNetworkPayloadSet.size(); sb.append("Received ").append(items).append(" instances from a ") .append(getDataRequestType).append(sep); - payloadByClassName.forEach((key, value) -> sb.append(key) + numPayloadsByClassName.forEach((key, value) -> sb.append(key) .append(": ") - .append(value.size()) + .append(value.first.get()) + .append(" / ") + .append(Utilities.readableFileSize(value.second.get())) .append(sep)); sb.append("#################################################################"); log.info(sb.toString()); } + private void addDetails(Map> numPayloadsByClassName, + NetworkPayload networkPayload, String className) { + numPayloadsByClassName.putIfAbsent(className, new Tuple2<>(new AtomicInteger(0), + new AtomicInteger(0))); + numPayloadsByClassName.get(className).first.getAndIncrement(); + // toProtoMessage().getSerializedSize() is not very cheap. For about 1500 objects it takes about 20 ms + // I think its justified to get accurate metrics but if it turns out to be a performance issue we might need + // to remove it and use some more rough estimation by taking only the size of one data type and multiply it. + numPayloadsByClassName.get(className).second.getAndAdd(networkPayload.toProtoMessage().getSerializedSize()); + } + @SuppressWarnings("UnusedParameters") private void handleFault(String errorMessage, NodeAddress nodeAddress, diff --git a/p2p/src/main/java/bisq/network/p2p/peers/getdata/RequestDataManager.java b/p2p/src/main/java/bisq/network/p2p/peers/getdata/RequestDataManager.java index 38d2bd3ca4..5860e84045 100644 --- a/p2p/src/main/java/bisq/network/p2p/peers/getdata/RequestDataManager.java +++ b/p2p/src/main/java/bisq/network/p2p/peers/getdata/RequestDataManager.java @@ -31,6 +31,7 @@ import bisq.network.p2p.storage.P2PDataStorage; import bisq.common.Timer; import bisq.common.UserThread; +import bisq.common.app.Version; import bisq.common.proto.network.NetworkEnvelope; import javax.inject.Inject; @@ -261,6 +262,11 @@ public class RequestDataManager implements MessageListener, ConnectionListener, if (peerManager.isSeedNode(connection)) connection.setPeerType(Connection.PeerType.SEED_NODE); + GetDataRequest getDataRequest = (GetDataRequest) networkEnvelope; + if (getDataRequest.getVersion() == null || !Version.isNewVersion(getDataRequest.getVersion(), "1.5.0")) { + connection.shutDown(CloseConnectionReason.MANDATORY_CAPABILITIES_NOT_SUPPORTED); + return; + } final String uid = connection.getUid(); if (!getDataRequestHandlers.containsKey(uid)) { GetDataRequestHandler getDataRequestHandler = new GetDataRequestHandler(networkNode, dataStorage, @@ -284,7 +290,7 @@ public class RequestDataManager implements MessageListener, ConnectionListener, } }); getDataRequestHandlers.put(uid, getDataRequestHandler); - getDataRequestHandler.handle((GetDataRequest) networkEnvelope, connection); + getDataRequestHandler.handle(getDataRequest, connection); } else { log.warn("We have already a GetDataRequestHandler for that connection started. " + "We start a cleanup timer if the handler has not closed by itself in between 2 minutes."); @@ -369,7 +375,7 @@ public class RequestDataManager implements MessageListener, ConnectionListener, listener.onNoPeersAvailable(); } - restart(); + requestFromNonSeedNodePeers(); } else { log.info("We could not connect to seed node {} but we have other connection attempts open.", nodeAddress.getFullAddress()); } @@ -399,6 +405,18 @@ public class RequestDataManager implements MessageListener, ConnectionListener, // Utils /////////////////////////////////////////////////////////////////////////////////////////// + private void requestFromNonSeedNodePeers() { + List list = getFilteredNonSeedNodeList(getSortedNodeAddresses(peerManager.getReportedPeers()), new ArrayList<>()); + List filteredPersistedPeers = getFilteredNonSeedNodeList(getSortedNodeAddresses(peerManager.getPersistedPeers()), list); + list.addAll(filteredPersistedPeers); + + if (!list.isEmpty()) { + NodeAddress nextCandidate = list.get(0); + list.remove(nextCandidate); + requestData(nextCandidate, list); + } + } + private void restart() { if (retryTimer == null) { retryTimer = UserThread.runAfter(() -> { diff --git a/p2p/src/main/java/bisq/network/p2p/peers/getdata/messages/GetDataResponse.java b/p2p/src/main/java/bisq/network/p2p/peers/getdata/messages/GetDataResponse.java index a86d6f2783..255c8c1347 100644 --- a/p2p/src/main/java/bisq/network/p2p/peers/getdata/messages/GetDataResponse.java +++ b/p2p/src/main/java/bisq/network/p2p/peers/getdata/messages/GetDataResponse.java @@ -27,8 +27,8 @@ import bisq.common.app.Capabilities; import bisq.common.app.Version; import bisq.common.proto.network.NetworkEnvelope; import bisq.common.proto.network.NetworkProtoResolver; +import bisq.common.util.Utilities; -import java.util.HashSet; import java.util.Set; import java.util.stream.Collectors; @@ -107,24 +107,18 @@ public final class GetDataResponse extends NetworkEnvelope implements SupportedC protobuf.NetworkEnvelope proto = getNetworkEnvelopeBuilder() .setGetDataResponse(builder) .build(); - log.info("Sending a GetDataResponse with {} kB", proto.getSerializedSize() / 1000d); + log.info("Sending a GetDataResponse with {}", Utilities.readableFileSize(proto.getSerializedSize())); return proto; } public static GetDataResponse fromProto(protobuf.GetDataResponse proto, NetworkProtoResolver resolver, int messageVersion) { - log.info("Received a GetDataResponse with {} kB", proto.getSerializedSize() / 1000d); - Set dataSet = new HashSet<>( - proto.getDataSetList().stream() - .map(entry -> (ProtectedStorageEntry) resolver.fromProto(entry)) - .collect(Collectors.toSet())); - - Set persistableNetworkPayloadSet = new HashSet<>( - proto.getPersistableNetworkPayloadItemsList().stream() - .map(e -> (PersistableNetworkPayload) resolver.fromProto(e)) - .collect(Collectors.toSet())); - + log.info("Received a GetDataResponse with {}", Utilities.readableFileSize(proto.getSerializedSize())); + Set dataSet = proto.getDataSetList().stream() + .map(entry -> (ProtectedStorageEntry) resolver.fromProto(entry)).collect(Collectors.toSet()); + Set persistableNetworkPayloadSet = proto.getPersistableNetworkPayloadItemsList().stream() + .map(e -> (PersistableNetworkPayload) resolver.fromProto(e)).collect(Collectors.toSet()); return new GetDataResponse(dataSet, persistableNetworkPayloadSet, proto.getRequestNonce(), diff --git a/p2p/src/main/java/bisq/network/p2p/storage/P2PDataStorage.java b/p2p/src/main/java/bisq/network/p2p/storage/P2PDataStorage.java index 2cd0ad0405..1ed4cc30b4 100644 --- a/p2p/src/main/java/bisq/network/p2p/storage/P2PDataStorage.java +++ b/p2p/src/main/java/bisq/network/p2p/storage/P2PDataStorage.java @@ -534,7 +534,10 @@ public class P2PDataStorage implements MessageListener, ConnectionListener, Pers removeExpiredEntriesTimer = UserThread.runPeriodically(this::removeExpiredEntries, CHECK_TTL_INTERVAL_SEC); } - public Map getAppendOnlyDataStoreMap() { + // Domain access should use the concrete appendOnlyDataStoreService if available. The Historical data store require + // care which data should be accessed (live data or all data). + @VisibleForTesting + Map getAppendOnlyDataStoreMap() { return appendOnlyDataStoreService.getMap(); } @@ -642,7 +645,7 @@ public class P2PDataStorage implements MessageListener, ConnectionListener, Pers } ByteArray hashAsByteArray = new ByteArray(payload.getHash()); - boolean payloadHashAlreadyInStore = getAppendOnlyDataStoreMap().containsKey(hashAsByteArray); + boolean payloadHashAlreadyInStore = appendOnlyDataStoreService.getMap().containsKey(hashAsByteArray); // Store already knows about this payload. Ignore it unless the caller specifically requests a republish. if (payloadHashAlreadyInStore && !reBroadcast) { @@ -944,7 +947,7 @@ public class P2PDataStorage implements MessageListener, ConnectionListener, Pers if (entriesToRemoveWithPayloadHash.isEmpty()) return; - log.info("Remove {} expired data entries", entriesToRemoveWithPayloadHash.size()); + log.debug("Remove {} expired data entries", entriesToRemoveWithPayloadHash.size()); ArrayList entriesForSignal = new ArrayList<>(entriesToRemoveWithPayloadHash.size()); entriesToRemoveWithPayloadHash.forEach(entryToRemoveWithPayloadHash -> { diff --git a/p2p/src/main/java/bisq/network/p2p/storage/persistence/AppendOnlyDataStoreService.java b/p2p/src/main/java/bisq/network/p2p/storage/persistence/AppendOnlyDataStoreService.java index 927d81db57..25ce17f0e9 100644 --- a/p2p/src/main/java/bisq/network/p2p/storage/persistence/AppendOnlyDataStoreService.java +++ b/p2p/src/main/java/bisq/network/p2p/storage/persistence/AppendOnlyDataStoreService.java @@ -78,7 +78,12 @@ public class AppendOnlyDataStoreService { public Map getMap() { return services.stream() - .flatMap(service -> service.getMap().entrySet().stream()) + .flatMap(service -> { + Map map = service instanceof HistoricalDataStoreService ? + ((HistoricalDataStoreService) service).getMapOfAllData() : + service.getMap(); + return map.entrySet().stream(); + }) .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)); } diff --git a/p2p/src/main/java/bisq/network/p2p/storage/persistence/HistoricalDataStoreService.java b/p2p/src/main/java/bisq/network/p2p/storage/persistence/HistoricalDataStoreService.java index 45c744d0b6..1510092654 100644 --- a/p2p/src/main/java/bisq/network/p2p/storage/persistence/HistoricalDataStoreService.java +++ b/p2p/src/main/java/bisq/network/p2p/storage/persistence/HistoricalDataStoreService.java @@ -20,6 +20,7 @@ package bisq.network.p2p.storage.persistence; import bisq.network.p2p.storage.P2PDataStorage; import bisq.network.p2p.storage.payload.PersistableNetworkPayload; +import bisq.common.app.DevEnv; import bisq.common.app.Version; import bisq.common.persistence.PersistenceManager; @@ -109,15 +110,11 @@ public abstract class HistoricalDataStoreService getMap() { - return store.getMap(); + DevEnv.logErrorAndThrowIfDevMode("HistoricalDataStoreService.getMap should not be used by domain " + + "clients but rather the custom methods getMapOfAllData, getMapOfLiveData or getMapSinceVersion"); + return getMapOfAllData(); } @Override diff --git a/p2p/src/main/resources/AccountAgeWitnessStore_1.5.2_BTC_MAINNET b/p2p/src/main/resources/AccountAgeWitnessStore_1.5.2_BTC_MAINNET new file mode 100644 index 0000000000..52194824ac --- /dev/null +++ b/p2p/src/main/resources/AccountAgeWitnessStore_1.5.2_BTC_MAINNET @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:ed73dc1b5c847ea08ca61c9903887525f155817aeef7cf7f7bb0db7d00be07a8 +size 2178782 diff --git a/p2p/src/main/resources/AccountAgeWitnessStore_BTC_MAINNET b/p2p/src/main/resources/AccountAgeWitnessStore_BTC_MAINNET deleted file mode 100644 index a9ad8621cc..0000000000 --- a/p2p/src/main/resources/AccountAgeWitnessStore_BTC_MAINNET +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:86921ed15d886ece795f6400e2835eb7bdb392d87be314f99c122505a6c7bf7e -size 2088756 diff --git a/p2p/src/main/resources/DaoStateStore_BTC_MAINNET b/p2p/src/main/resources/DaoStateStore_BTC_MAINNET index fe7ba0d56e..7870991d89 100644 --- a/p2p/src/main/resources/DaoStateStore_BTC_MAINNET +++ b/p2p/src/main/resources/DaoStateStore_BTC_MAINNET @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:0417e59cc6a9674956c06cde8c3691926c2277b42ad91510aaaae71256b60ea2 -size 96464108 +oid sha256:689a1b07b04c369a9b32dd05a8714f26128f7ca350f3e1cf6bfb0cc8c159677e +size 100617580 diff --git a/p2p/src/main/resources/SignedWitnessStore_BTC_MAINNET b/p2p/src/main/resources/SignedWitnessStore_BTC_MAINNET index 7e6c877894..91ac6f702b 100644 --- a/p2p/src/main/resources/SignedWitnessStore_BTC_MAINNET +++ b/p2p/src/main/resources/SignedWitnessStore_BTC_MAINNET @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:6c5b7d98da6da5f50dd01e902a7ee1ba578f3e8661206c2576c477ec0c3e169b -size 4564514 +oid sha256:b26bee55f35f78f43da40f5a3baf7ad9cf3a29be47c7145eefc2e66a3b0a0cda +size 5001045 diff --git a/p2p/src/main/resources/TradeStatistics3Store_1.5.2_BTC_MAINNET b/p2p/src/main/resources/TradeStatistics3Store_1.5.2_BTC_MAINNET new file mode 100644 index 0000000000..ee799a6ee3 --- /dev/null +++ b/p2p/src/main/resources/TradeStatistics3Store_1.5.2_BTC_MAINNET @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:ae7c198cde0661203db82a2c77356075c26415fa1c5ced1f21cfeb78aa9abce6 +size 255823 diff --git a/p2p/src/test/java/bisq/network/p2p/DummySeedNode.java b/p2p/src/test/java/bisq/network/p2p/DummySeedNode.java index 3fe5205c66..6bd65596c6 100644 --- a/p2p/src/test/java/bisq/network/p2p/DummySeedNode.java +++ b/p2p/src/test/java/bisq/network/p2p/DummySeedNode.java @@ -17,8 +17,6 @@ package bisq.network.p2p; -import bisq.network.p2p.peers.BanList; - import bisq.common.UserThread; import bisq.common.app.Log; import bisq.common.app.Version; @@ -140,7 +138,6 @@ public class DummySeedNode { list.forEach(e -> { checkArgument(e.contains(":") && e.split(":").length == 2 && e.split(":")[1].length() == 4, "Wrong program argument " + e); - BanList.add(new NodeAddress(e)); }); log.debug("From processArgs: ignoreList=" + list); } else if (arg.startsWith(HELP)) { diff --git a/p2p/src/test/java/bisq/network/p2p/network/LocalhostNetworkNodeTest.java b/p2p/src/test/java/bisq/network/p2p/network/LocalhostNetworkNodeTest.java index 1a09281e0d..8315332c34 100644 --- a/p2p/src/test/java/bisq/network/p2p/network/LocalhostNetworkNodeTest.java +++ b/p2p/src/test/java/bisq/network/p2p/network/LocalhostNetworkNodeTest.java @@ -38,13 +38,10 @@ import org.junit.Test; public class LocalhostNetworkNodeTest { private static final Logger log = LoggerFactory.getLogger(LocalhostNetworkNodeTest.class); - - - @Test public void testMessage() throws InterruptedException, IOException { CountDownLatch msgLatch = new CountDownLatch(2); - LocalhostNetworkNode node1 = new LocalhostNetworkNode(9001, TestUtils.getNetworkProtoResolver()); + LocalhostNetworkNode node1 = new LocalhostNetworkNode(9001, TestUtils.getNetworkProtoResolver(), null); node1.addMessageListener((message, connection) -> { log.debug("onMessage node1 " + message); msgLatch.countDown(); @@ -72,7 +69,7 @@ public class LocalhostNetworkNodeTest { } }); - LocalhostNetworkNode node2 = new LocalhostNetworkNode(9002, TestUtils.getNetworkProtoResolver()); + LocalhostNetworkNode node2 = new LocalhostNetworkNode(9002, TestUtils.getNetworkProtoResolver(), null); node2.addMessageListener((message, connection) -> { log.debug("onMessage node2 " + message); msgLatch.countDown(); diff --git a/p2p/src/test/java/bisq/network/p2p/network/TorNetworkNodeTest.java b/p2p/src/test/java/bisq/network/p2p/network/TorNetworkNodeTest.java index b050fdf659..3b544da4e5 100644 --- a/p2p/src/test/java/bisq/network/p2p/network/TorNetworkNodeTest.java +++ b/p2p/src/test/java/bisq/network/p2p/network/TorNetworkNodeTest.java @@ -27,6 +27,7 @@ import com.google.common.util.concurrent.SettableFuture; import java.io.File; import java.io.IOException; + import java.util.ArrayList; import java.util.concurrent.CountDownLatch; @@ -49,13 +50,12 @@ public class TorNetworkNodeTest { private CountDownLatch latch; - @Test public void testTorNodeBeforeSecondReady() throws InterruptedException, IOException { latch = new CountDownLatch(1); int port = 9001; TorNetworkNode node1 = new TorNetworkNode(port, TestUtils.getNetworkProtoResolver(), false, - new NewTor(new File("torNode_" + port), null, "", new ArrayList())); + new NewTor(new File("torNode_" + port), null, "", new ArrayList()), null); node1.start(new SetupListener() { @Override public void onTorNodeReady() { @@ -82,7 +82,7 @@ public class TorNetworkNodeTest { latch = new CountDownLatch(1); int port2 = 9002; TorNetworkNode node2 = new TorNetworkNode(port2, TestUtils.getNetworkProtoResolver(), false, - new NewTor(new File("torNode_" + port), null, "", new ArrayList())); + new NewTor(new File("torNode_" + port), null, "", new ArrayList()), null); node2.start(new SetupListener() { @Override public void onTorNodeReady() { @@ -140,7 +140,7 @@ public class TorNetworkNodeTest { latch = new CountDownLatch(2); int port = 9001; TorNetworkNode node1 = new TorNetworkNode(port, TestUtils.getNetworkProtoResolver(), false, - new NewTor(new File("torNode_" + port), null, "", new ArrayList())); + new NewTor(new File("torNode_" + port), null, "", new ArrayList()), null); node1.start(new SetupListener() { @Override public void onTorNodeReady() { @@ -166,7 +166,7 @@ public class TorNetworkNodeTest { int port2 = 9002; TorNetworkNode node2 = new TorNetworkNode(port2, TestUtils.getNetworkProtoResolver(), false, - new NewTor(new File("torNode_" + port), null, "", new ArrayList())); + new NewTor(new File("torNode_" + port), null, "", new ArrayList()), null); node2.start(new SetupListener() { @Override public void onTorNodeReady() { diff --git a/proto/src/main/proto/grpc.proto b/proto/src/main/proto/grpc.proto index df37f08fd8..b2532d8b48 100644 --- a/proto/src/main/proto/grpc.proto +++ b/proto/src/main/proto/grpc.proto @@ -47,8 +47,12 @@ message RegisterDisputeAgentReply { service Offers { rpc GetOffer (GetOfferRequest) returns (GetOfferReply) { } + rpc GetMyOffer (GetMyOfferRequest) returns (GetMyOfferReply) { + } rpc GetOffers (GetOffersRequest) returns (GetOffersReply) { } + rpc GetMyOffers (GetMyOffersRequest) returns (GetMyOffersReply) { + } rpc CreateOffer (CreateOfferRequest) returns (CreateOfferReply) { } rpc CancelOffer (CancelOfferRequest) returns (CancelOfferReply) { @@ -62,6 +66,15 @@ message GetOfferRequest { message GetOfferReply { OfferInfo offer = 1; } + +message GetMyOfferRequest { + string id = 1; +} + +message GetMyOfferReply { + OfferInfo offer = 1; +} + message GetOffersRequest { string direction = 1; string currencyCode = 2; @@ -71,6 +84,15 @@ message GetOffersReply { repeated OfferInfo offers = 1; } +message GetMyOffersRequest { + string direction = 1; + string currencyCode = 2; +} + +message GetMyOffersReply { + repeated OfferInfo offers = 1; +} + message CreateOfferRequest { string currencyCode = 1; string direction = 2; diff --git a/proto/src/main/proto/pb.proto b/proto/src/main/proto/pb.proto index 22d81d40de..49681858e1 100644 --- a/proto/src/main/proto/pb.proto +++ b/proto/src/main/proto/pb.proto @@ -158,6 +158,7 @@ message OfferAvailabilityRequest { int64 takers_trade_price = 3; repeated int32 supported_capabilities = 4; string uid = 5; + bool is_taker_api_user = 6; } message OfferAvailabilityResponse { @@ -652,7 +653,7 @@ message RefundAgent { } message Filter { - repeated string banned_node_address = 1; + repeated string node_addresses_banned_from_trading = 1; repeated string banned_offer_ids = 2; repeated PaymentAccountFilter banned_payment_accounts = 3; string signature_as_base64 = 4; @@ -677,6 +678,8 @@ message Filter { repeated string bannedPrivilegedDevPubKeys = 23; bool disable_auto_conf = 24; repeated string banned_auto_conf_explorers = 25; + repeated string node_addresses_banned_from_network = 26; + bool disable_api = 27; } // Deprecated @@ -912,6 +915,8 @@ enum AvailabilityResult { USER_IGNORED = 8; MISSING_MANDATORY_CAPABILITY = 9; NO_REFUND_AGENTS = 10; + UNCONF_TX_LIMIT_HIT = 11; + MAKER_DENIED_API_USER = 12; } /////////////////////////////////////////////////////////////////////////////////////////// @@ -1331,6 +1336,7 @@ message OpenOffer { NodeAddress arbitrator_node_address = 3; NodeAddress mediator_node_address = 4; NodeAddress refund_agent_node_address = 5; + int64 trigger_price = 6; } message Tradable { @@ -1612,6 +1618,9 @@ message PreferencesPayload { bool tac_accepted_v120 = 55; repeated AutoConfirmSettings auto_confirm_settings = 56; double bsq_average_trim_threshold = 57; + bool hide_non_account_payment_methods = 58; + bool show_offers_matching_my_accounts = 59; + bool deny_api_taker = 60; } message AutoConfirmSettings { @@ -1642,6 +1651,7 @@ message UserPayload { repeated MarketAlertFilter market_alert_filters = 13; repeated RefundAgent accepted_refund_agents = 14; RefundAgent registered_refund_agent = 15; + map cookie = 16; } /////////////////////////////////////////////////////////////////////////////////////////// diff --git a/relay/src/main/resources/version.txt b/relay/src/main/resources/version.txt index f825f7c7f1..80e940f2e6 100644 --- a/relay/src/main/resources/version.txt +++ b/relay/src/main/resources/version.txt @@ -1 +1 @@ -1.5.1-SNAPSHOT +1.5.4-SNAPSHOT diff --git a/scripts/install_java.sh b/scripts/install_java.sh index 2ab9e21df9..cc0d60654f 100755 --- a/scripts/install_java.sh +++ b/scripts/install_java.sh @@ -10,11 +10,11 @@ # echo 'export JAVA_HOME=/Library/Java/JavaVirtualMachines//Contents/Home' >>~/.bash_profile # echo 'export PATH=$JAVA_HOME/bin:$PATH' >>~/.bash_profile # source ~/.bash_profile - +set -e unameOut="$(uname -s)" case "${unameOut}" in - Linux*) + Linux*) JAVA_HOME=/usr/lib/jvm/openjdk-10.0.2 JDK_FILENAME=openjdk-10.0.2_linux-x64_bin.tar.gz JDK_URL=https://download.java.net/java/GA/jdk10/10.0.2/19aef61b38124481863b1413dce1855f/13/openjdk-10.0.2_linux-x64_bin.tar.gz @@ -27,7 +27,7 @@ case "${unameOut}" in osInfo[/etc/SuSE-release]=zypp osInfo[/etc/debian_version]=apt-get - for f in ${!osInfo[@]} + for f in "${!osInfo[@]}" do if [[ -f $f ]]; then PACKAGE_MANAGER=${osInfo[$f]} @@ -74,9 +74,10 @@ case "${unameOut}" in fi echo export JAVA_HOME=$JAVA_HOME >>~/.bash_profile - echo export PATH=$JAVA_HOME/bin:$PATH >>~/.bash_profile - source ~/.bash_profile + echo export PATH=$JAVA_HOME/bin:"$PATH" >>~/.bash_profile + source "$HOME/.bash_profile" ;; - *) machine="UNKNOWN:${unameOut}" + *) esac java -version + diff --git a/seednode/src/main/java/bisq/seednode/SeedNodeMain.java b/seednode/src/main/java/bisq/seednode/SeedNodeMain.java index e81f03813a..25f9a334f9 100644 --- a/seednode/src/main/java/bisq/seednode/SeedNodeMain.java +++ b/seednode/src/main/java/bisq/seednode/SeedNodeMain.java @@ -36,12 +36,15 @@ import bisq.common.config.BaseCurrencyNetwork; import bisq.common.config.Config; import bisq.common.handlers.ResultHandler; +import com.google.inject.Key; +import com.google.inject.name.Names; + import lombok.extern.slf4j.Slf4j; @Slf4j public class SeedNodeMain extends ExecutableForAppWithP2p { private static final long CHECK_CONNECTION_LOSS_SEC = 30; - private static final String VERSION = "1.5.1"; + private static final String VERSION = "1.5.4"; private SeedNode seedNode; private Timer checkConnectionLossTime; @@ -139,7 +142,11 @@ public class SeedNodeMain extends ExecutableForAppWithP2p { @Override public void onHiddenServicePublished() { - startShutDownInterval(SeedNodeMain.this); + boolean preventPeriodicShutdownAtSeedNode = injector.getInstance(Key.get(boolean.class, + Names.named(Config.PREVENT_PERIODIC_SHUTDOWN_AT_SEED_NODE))); + if (!preventPeriodicShutdownAtSeedNode) { + startShutDownInterval(SeedNodeMain.this); + } UserThread.runAfter(() -> setupConnectionLossCheck(), 60); }