Browse Source

Merge pull request #767 from LN-Zap/crowdin

Multiple languages
renovate/lint-staged-8.x
JimmyMow 6 years ago
committed by GitHub
parent
commit
f6fd4f9171
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 5
      .babelrc
  2. 1
      .eslintrc
  3. 21
      app/components/Activity/Activity.js
  4. 21
      app/components/Activity/Activity.scss
  5. 7
      app/components/Activity/Countdown/Countdown.js
  6. 6
      app/components/Activity/Countdown/messages.js
  7. 42
      app/components/Activity/Invoice/Invoice.js
  8. 10
      app/components/Activity/Invoice/messages.js
  9. 47
      app/components/Activity/InvoiceModal/InvoiceModal.js
  10. 12
      app/components/Activity/InvoiceModal/messages.js
  11. 38
      app/components/Activity/Payment/Payment.js
  12. 8
      app/components/Activity/Payment/messages.js
  13. 24
      app/components/Activity/PaymentModal/PaymentModal.js
  14. 8
      app/components/Activity/PaymentModal/messages.js
  15. 44
      app/components/Activity/Transaction/Transaction.js
  16. 10
      app/components/Activity/Transaction/messages.js
  17. 30
      app/components/Activity/TransactionModal/TransactionModal.js
  18. 9
      app/components/Activity/TransactionModal/messages.js
  19. 13
      app/components/Activity/messages.js
  20. 6
      app/components/App/App.js
  21. 25
      app/components/Contacts/AddChannel/AddChannel.js
  22. 11
      app/components/Contacts/AddChannel/messages.js
  23. 21
      app/components/Contacts/ConnectManually/ConnectManually.js
  24. 9
      app/components/Contacts/ConnectManually/messages.js
  25. 139
      app/components/Contacts/ContactModal/ContactModal.js
  26. 151
      app/components/Contacts/ContactModal/ContactModal.scss
  27. 3
      app/components/Contacts/ContactModal/index.js
  28. 275
      app/components/Contacts/ContactsForm/ContactsForm.js
  29. 253
      app/components/Contacts/ContactsForm/ContactsForm.scss
  30. 3
      app/components/Contacts/ContactsForm/index.js
  31. 52
      app/components/Contacts/Network/Network.js
  32. 16
      app/components/Contacts/Network/messages.js
  33. 40
      app/components/Contacts/SubmitChannelForm/SubmitChannelForm.js
  34. 11
      app/components/Contacts/SubmitChannelForm/messages.js
  35. 11
      app/components/Contacts/SuggestedNodes/SuggestedNodes.js
  36. 8
      app/components/Contacts/SuggestedNodes/messages.js
  37. 37
      app/components/Form/Pay/Pay.js
  38. 11
      app/components/Form/Pay/messages.js
  39. 36
      app/components/Form/Request/Request.js
  40. 9
      app/components/Form/Request/messages.js
  41. 7
      app/components/LoadingBolt/LoadingBolt.js
  42. 6
      app/components/LoadingBolt/messages.js
  43. 10
      app/components/Onboarding/Autopilot/Autopilot.js
  44. 7
      app/components/Onboarding/Autopilot/messages.js
  45. 21
      app/components/Onboarding/BtcPayServer/BtcPayServer.js
  46. 10
      app/components/Onboarding/BtcPayServer/messages.js
  47. 8
      app/components/Onboarding/ConnectionConfirm/ConnectionConfirm.js
  48. 7
      app/components/Onboarding/ConnectionConfirm/messages.js
  49. 18
      app/components/Onboarding/ConnectionDetails/ConnectionDetails.js
  50. 10
      app/components/Onboarding/ConnectionDetails/messages.js
  51. 18
      app/components/Onboarding/ConnectionType/ConnectionType.js
  52. 14
      app/components/Onboarding/ConnectionType/messages.js
  53. 14
      app/components/Onboarding/FormContainer/FormContainer.js
  54. 8
      app/components/Onboarding/FormContainer/messages.js
  55. 21
      app/components/Onboarding/Login/Login.js
  56. 7
      app/components/Onboarding/Login/messages.js
  57. 20
      app/components/Onboarding/NewWalletPassword/NewWalletPassword.js
  58. 10
      app/components/Onboarding/NewWalletPassword/messages.js
  59. 87
      app/components/Onboarding/Onboarding.js
  60. 11
      app/components/Onboarding/RecoverForm/RecoverForm.js
  61. 6
      app/components/Onboarding/RecoverForm/messages.js
  62. 10
      app/components/Onboarding/Signup/Signup.js
  63. 7
      app/components/Onboarding/Signup/messages.js
  64. 52
      app/components/Onboarding/Syncing/Syncing.js
  65. 17
      app/components/Onboarding/Syncing/messages.js
  66. 35
      app/components/Onboarding/messages.js
  67. 6
      app/components/Settings/Fiat/Fiat.js
  68. 6
      app/components/Settings/Fiat/messages.js
  69. 49
      app/components/Settings/Locale/Locale.js
  70. 42
      app/components/Settings/Locale/Locale.scss
  71. 3
      app/components/Settings/Locale/index.js
  72. 6
      app/components/Settings/Locale/messages.js
  73. 10
      app/components/Settings/Menu/Menu.js
  74. 7
      app/components/Settings/Menu/messages.js
  75. 8
      app/components/Settings/Settings.js
  76. 23
      app/components/Wallet/ReceiveModal/ReceiveModal.js
  77. 9
      app/components/Wallet/ReceiveModal/messages.js
  78. 35
      app/components/Wallet/Wallet.js
  79. 10
      app/components/Wallet/messages.js
  80. 11
      app/containers/Activity.js
  81. 14
      app/containers/App.js
  82. 28
      app/containers/Root.js
  83. 38
      app/index.js
  84. 211
      app/lib/utils/i18n.js
  85. 39
      app/lib/zap/menuBuilder.js
  86. 8
      app/reducers/activity.js
  87. 28
      app/reducers/channels.js
  88. 4
      app/reducers/index.js
  89. 2
      app/reducers/ipc.js
  90. 40
      app/reducers/locale.js
  91. 28
      app/reducers/ticker.js
  92. 157
      app/translations/af-ZA.json
  93. 157
      app/translations/ar-SA.json
  94. 157
      app/translations/bg-BG.json
  95. 157
      app/translations/ca-ES.json
  96. 157
      app/translations/cs-CZ.json
  97. 157
      app/translations/da-DK.json
  98. 157
      app/translations/de-DE.json
  99. 157
      app/translations/el-GR.json
  100. 157
      app/translations/en.json

5
.babelrc

@ -10,7 +10,10 @@
"stage-0",
"react"
],
"plugins": ["add-module-exports", "dynamic-import-webpack"],
"plugins": ["add-module-exports", "dynamic-import-webpack", ["react-intl-auto", {
"removePrefix": "app/",
"filebase": false
}]],
"env": {
"production": {
"presets": ["react-optimize"],

1
.eslintrc

@ -50,6 +50,7 @@
"camelcase": 0,
"curly": ["error", "all"],
"react/require-default-props": 0,
"react/style-prop-object": 0,
"max-len": ["error", { "code": 120, "ignoreUrls": true }],
"import/no-extraneous-dependencies": 0,
"no-cond-assign": ["error", "except-parens"],

21
app/components/Activity/Activity.js

@ -5,6 +5,8 @@ import searchIcon from 'icons/search.svg'
import xIcon from 'icons/x.svg'
import FaRepeat from 'react-icons/lib/fa/repeat'
import { FormattedMessage, injectIntl } from 'react-intl'
import Wallet from 'components/Wallet'
import LoadingBolt from 'components/LoadingBolt'
import Invoice from './Invoice'
@ -13,6 +15,8 @@ import Transaction from './Transaction'
import styles from './Activity.scss'
import messages from './messages'
class Activity extends Component {
constructor(props, context) {
super(props, context)
@ -87,7 +91,8 @@ class Activity extends Component {
updateSearchActive,
updateSearchText,
walletProps
walletProps,
intl
} = this.props
if (balance.channelBalance === null || balance.walletBalance === null) {
@ -134,7 +139,7 @@ class Activity extends Component {
<header className={`${styles.header} ${styles.search}`}>
<section>
<input
placeholder="Search"
placeholder={intl.formatMessage({ ...messages.search })}
value={searchText}
onChange={event => updateSearchText(event.target.value)}
/>
@ -160,7 +165,7 @@ class Activity extends Component {
className={f.key === filter.key ? styles.activeFilter : undefined}
onClick={() => changeFilter(f)}
>
<span>{f.name}</span>
<FormattedMessage {...messages[f.name]} />
<div className={f.key === filter.key ? styles.activeBorder : undefined} />
</li>
@ -176,7 +181,7 @@ class Activity extends Component {
this.repeat = ref
}}
>
{refreshing ? <FaRepeat /> : 'Refresh'}
{refreshing ? <FaRepeat /> : <FormattedMessage {...messages.refresh} />}
</span>
</li>
<li className={styles.activeFilter} onClick={() => updateSearchActive(true)}>
@ -204,7 +209,11 @@ class Activity extends Component {
{showExpiredToggle && (
<li>
<div className={styles.toggleExpired} onClick={toggleExpiredRequests}>
{showExpiredRequests ? 'Hide Expired Requests' : 'Show Expired Requests'}
{showExpiredRequests ? (
<FormattedMessage {...messages.hide_expired} />
) : (
<FormattedMessage {...messages.show_expired} />
)}
</div>
</li>
)}
@ -240,4 +249,4 @@ Activity.propTypes = {
currencyName: PropTypes.string.isRequired
}
export default Activity
export default injectIntl(Activity)

21
app/components/Activity/Activity.scss

@ -284,23 +284,15 @@
font-size: 10px;
}
.icon,
h3,
span {
vertical-align: middle;
}
h3,
span {
font-size: 14px;
font-weight: bold;
letter-spacing: 1.2px;
.date {
font-size: 12px;
}
.icon {
display: inline-block;
flex: none;
position: relative;
vertical-align: middle;
width: 20px;
height: 20px;
background: #31343f;
@ -321,6 +313,9 @@
h3 {
display: inline-block;
font-size: 14px;
font-weight: bold;
letter-spacing: 1.2px;
&::after {
content: ' ';
@ -328,10 +323,6 @@
width: 3px;
}
}
span {
text-transform: uppercase;
}
}
.amount {

7
app/components/Activity/Countdown/Countdown.js

@ -1,6 +1,9 @@
import React from 'react'
import PropTypes from 'prop-types'
import { FormattedMessage } from 'react-intl'
import messages from './messages'
import styles from './Countdown.scss'
class Countdown extends React.Component {
@ -73,7 +76,9 @@ class Countdown extends React.Component {
return (
<span className={styles.container}>
<i className={styles.caption}>Expires in</i>
<i className={styles.caption}>
<FormattedMessage {...messages.expires} />
</i>
<i>{days > 0 && `${days}:`}</i>
<i>{hours > 0 && `${hours}:`}</i>
<i>{minutes > 0 && `${minutes}:`}</i>

6
app/components/Activity/Countdown/messages.js

@ -0,0 +1,6 @@
import { defineMessages } from 'react-intl'
/* eslint-disable max-len */
export default defineMessages({
expires: 'Expires in'
})

42
app/components/Activity/Invoice/Invoice.js

@ -1,14 +1,17 @@
import React from 'react'
import PropTypes from 'prop-types'
import Moment from 'react-moment'
import { btc } from 'lib/utils'
import Isvg from 'react-inlinesvg'
import Value from 'components/Value'
import checkmarkIcon from 'icons/check_circle.svg'
import { FormattedNumber, FormattedTime, FormattedMessage, injectIntl } from 'react-intl'
import messages from './messages'
import styles from '../Activity.scss'
const Invoice = ({ invoice, ticker, currentTicker, showActivityModal, currencyName }) => (
const Invoice = ({ invoice, ticker, currentTicker, showActivityModal, currencyName, intl }) => (
<div
className={`${styles.container} ${!invoice.settled ? styles.unpaid : undefined}`}
onClick={() => showActivityModal('INVOICE', invoice.payment_request)}
@ -16,7 +19,11 @@ const Invoice = ({ invoice, ticker, currentTicker, showActivityModal, currencyNa
<div className={styles.activityTypeIcon}>
<section
className="hint--bottom"
data-hint={`Lightning invoice (${invoice.settled ? 'paid)' : 'unpaid'})`}
data-hint={
invoice.settled
? intl.formatMessage({ ...messages.type_paid })
: intl.formatMessage({ ...messages.type_unpaid })
}
>
<Isvg src={checkmarkIcon} />
</section>
@ -24,19 +31,25 @@ const Invoice = ({ invoice, ticker, currentTicker, showActivityModal, currencyNa
<div className={styles.data}>
<div className={styles.title}>
<h3>{invoice.settled ? 'Received payment' : 'Requested payment'}</h3>
<h3>
{invoice.settled ? (
<FormattedMessage {...messages.received} />
) : (
<FormattedMessage {...messages.requested} />
)}
</h3>
</div>
<div className={styles.subtitle}>
<Moment format="h:mm a">
{invoice.settled ? invoice.settle_date * 1000 : invoice.creation_date * 1000}
</Moment>
<FormattedTime
value={invoice.settled ? invoice.settle_date * 1000 : invoice.creation_date * 1000}
/>
</div>
</div>
<div
className={`hint--top-left ${styles.amount} ${
invoice.settled ? styles.positive : styles.negative
}`}
data-hint="Invoice amount"
data-hint={intl.formatMessage({ ...messages.amount })}
>
<span>
<i className={styles.plus}>+</i>
@ -48,12 +61,11 @@ const Invoice = ({ invoice, ticker, currentTicker, showActivityModal, currencyNa
/>
<i> {currencyName}</i>
</span>
<span>
<span>
{currentTicker[ticker.fiatTicker].symbol}
{btc.convert('sats', 'fiat', invoice.value, currentTicker[ticker.fiatTicker].last)}
</span>
</span>
<FormattedNumber
currency={ticker.fiatTicker}
style="currency"
value={btc.convert('sats', 'fiat', invoice.value, currentTicker[ticker.fiatTicker].last)}
/>
</div>
</div>
)
@ -66,4 +78,4 @@ Invoice.propTypes = {
currencyName: PropTypes.string.isRequired
}
export default Invoice
export default injectIntl(Invoice)

10
app/components/Activity/Invoice/messages.js

@ -0,0 +1,10 @@
import { defineMessages } from 'react-intl'
/* eslint-disable max-len */
export default defineMessages({
received: 'Received payment',
requested: 'Requested payment',
type_paid: 'Lightning invoice (paid)',
type_unpaid: 'Lightning invoice (unpaid)',
amount: 'Invoice amount'
})

47
app/components/Activity/InvoiceModal/InvoiceModal.js

@ -1,8 +1,6 @@
import React from 'react'
import PropTypes from 'prop-types'
import Moment from 'react-moment'
import QRCode from 'qrcode.react'
import copy from 'copy-to-clipboard'
import { showNotification } from 'lib/utils/notifications'
@ -10,8 +8,11 @@ import { showNotification } from 'lib/utils/notifications'
import FaAngleDown from 'react-icons/lib/fa/angle-down'
import Value from 'components/Value'
import { FormattedDate, FormattedTime, FormattedMessage } from 'react-intl'
import Countdown from '../Countdown'
import messages from './messages'
import styles from './InvoiceModal.scss'
const InvoiceModal = ({
@ -29,7 +30,7 @@ const InvoiceModal = ({
}) => {
const copyPaymentRequest = () => {
copy(invoice.payment_request)
showNotification('Noice', 'Successfully copied to clipboard')
showNotification('Noice', <FormattedMessage {...messages.copied} />)
}
const countDownDate = parseInt(invoice.creation_date, 10) + parseInt(invoice.expiry, 10)
@ -38,7 +39,9 @@ const InvoiceModal = ({
<div className={styles.container}>
<div className={styles.content}>
<section className={styles.left}>
<h2>Payment Request</h2>
<h2>
<FormattedMessage {...messages.pay_req} />
</h2>
<QRCode
value={invoice.payment_request}
renderAs="svg"
@ -80,28 +83,50 @@ const InvoiceModal = ({
</section>
<section className={styles.date}>
<p>
<Moment format="MM/DD/YYYY">{invoice.creation_date * 1000}</Moment>
<FormattedDate
value={invoice.creation_date * 1000}
year="numeric"
month="long"
day="2-digit"
/>{' '}
<FormattedTime value={new Date(invoice.creation_date * 1000)} />
</p>
{!invoice.settled && <p className={styles.notPaid}>Not Paid</p>}
{invoice.settled && <p className={styles.paid}>Paid</p>}
{!invoice.settled && (
<p className={styles.notPaid}>
<FormattedMessage {...messages.not_paid} />
</p>
)}
{invoice.settled && (
<p className={styles.paid}>
<FormattedMessage {...messages.paid} />
</p>
)}
</section>
</div>
<div className={styles.memo}>
<h4>Memo</h4>
<h4>
<FormattedMessage {...messages.memo} />
</h4>
<p>{invoice.memo}</p>
</div>
<div className={styles.request}>
<h4>Request</h4>
<h4>
<FormattedMessage {...messages.request} />
</h4>
<p>{invoice.payment_request}</p>
</div>
</section>
</div>
<div className={styles.actions}>
<div>Save as image</div>
<div onClick={copyPaymentRequest}>Copy Request</div>
<div>
<FormattedMessage {...messages.save} />
</div>
<div onClick={copyPaymentRequest}>
<FormattedMessage {...messages.copy} />
</div>
</div>
</div>
)

12
app/components/Activity/InvoiceModal/messages.js

@ -0,0 +1,12 @@
import { defineMessages } from 'react-intl'
/* eslint-disable max-len */
export default defineMessages({
copy: 'Copy Request',
pay_req: 'Payment Request',
memo: 'Memo',
request: 'Request',
save: 'Save as image',
not_paid: 'Not Paid',
paid: 'Paid'
})

38
app/components/Activity/Payment/Payment.js

@ -1,14 +1,25 @@
import React from 'react'
import PropTypes from 'prop-types'
import Moment from 'react-moment'
import Isvg from 'react-inlinesvg'
import zap from 'icons/zap.svg'
import { btc } from 'lib/utils'
import Value from 'components/Value'
import { FormattedNumber, FormattedTime, injectIntl } from 'react-intl'
import messages from './messages'
import styles from '../Activity.scss'
const Payment = ({ payment, ticker, currentTicker, showActivityModal, nodes, currencyName }) => {
const Payment = ({
payment,
ticker,
currentTicker,
showActivityModal,
nodes,
currencyName,
intl
}) => {
const displayNodeName = pubkey => {
const node = nodes.find(n => pubkey === n.pub_key)
@ -25,7 +36,7 @@ const Payment = ({ payment, ticker, currentTicker, showActivityModal, nodes, cur
onClick={() => showActivityModal('PAYMENT', payment.payment_hash)}
>
<div className={styles.activityTypeIcon}>
<section className="hint--bottom" data-hint="Lightning payment">
<section className="hint--bottom" data-hint={intl.formatMessage({ ...messages.type })}>
<Isvg src={zap} />
</section>
</div>
@ -35,10 +46,13 @@ const Payment = ({ payment, ticker, currentTicker, showActivityModal, nodes, cur
<h3>{displayNodeName(payment.path[payment.path.length - 1])}</h3>
</div>
<div className={styles.subtitle}>
<Moment format="h:mm a">{payment.creation_date * 1000}</Moment>
<FormattedTime value={payment.creation_date * 1000} />
</div>
</div>
<div className={`hint--top-left ${styles.amount}`} data-hint="Payment amount">
<div
className={`hint--top-left ${styles.amount}`}
data-hint={intl.formatMessage({ ...messages.amount })}
>
<span>
<i className={styles.minus}>-</i>
<Value
@ -49,10 +63,11 @@ const Payment = ({ payment, ticker, currentTicker, showActivityModal, nodes, cur
/>
<i> {currencyName}</i>
</span>
<span className="hint--bottom" data-hint="Payment fee">
{currentTicker[ticker.fiatTicker].symbol}
{btc.convert('sats', 'fiat', payment.value, currentTicker[ticker.fiatTicker].last)}
</span>
<FormattedNumber
currency={ticker.fiatTicker}
style="currency"
value={btc.convert('sats', 'fiat', payment.value, currentTicker[ticker.fiatTicker].last)}
/>
</div>
</div>
)
@ -64,7 +79,8 @@ Payment.propTypes = {
ticker: PropTypes.object.isRequired,
currentTicker: PropTypes.object.isRequired,
nodes: PropTypes.array.isRequired,
showActivityModal: PropTypes.func.isRequired
showActivityModal: PropTypes.func.isRequired,
intl: PropTypes.object.isRequired
}
export default Payment
export default injectIntl(Payment)

8
app/components/Activity/Payment/messages.js

@ -0,0 +1,8 @@
import { defineMessages } from 'react-intl'
/* eslint-disable max-len */
export default defineMessages({
amount: 'Payment amount',
fee: 'Payment fee',
type: 'Lightning payment'
})

24
app/components/Activity/PaymentModal/PaymentModal.js

@ -1,8 +1,6 @@
import React from 'react'
import PropTypes from 'prop-types'
import Moment from 'react-moment'
import FaAngleDown from 'react-icons/lib/fa/angle-down'
import Isvg from 'react-inlinesvg'
@ -11,6 +9,9 @@ import zap from 'icons/zap.svg'
import Value from 'components/Value'
import { FormattedDate, FormattedTime, FormattedMessage } from 'react-intl'
import messages from './messages'
import styles from './PaymentModal.scss'
const PaymentModal = ({
@ -30,12 +31,14 @@ const PaymentModal = ({
<header className={styles.header}>
<section>
<Isvg src={paperPlane} />
<span>Sent</span>
<FormattedMessage {...messages.sent} />
</section>
<section className={styles.details}>
<div>
<Isvg src={zap} />
<span className={styles.zap}>Lightning Network</span>
<span className={styles.zap}>
<FormattedMessage {...messages.lightning} />
</span>
</div>
<div>
<Value
@ -44,7 +47,10 @@ const PaymentModal = ({
currentTicker={currentTicker}
fiatTicker={ticker.fiatTicker}
/>
<span> {currencyName} fee</span>
<span>
{' '}
{currencyName} <FormattedMessage {...messages.fee} />
</span>
</div>
</section>
</header>
@ -78,7 +84,13 @@ const PaymentModal = ({
</div>
<div className={styles.date}>
<Moment format="LLL">{payment.creation_date * 1000}</Moment>
<FormattedDate
value={new Date(payment.creation_date * 1000)}
year="numeric"
month="long"
day="2-digit"
/>{' '}
<FormattedTime value={new Date(payment.creation_date * 1000)} />
</div>
<footer className={styles.footer}>

8
app/components/Activity/PaymentModal/messages.js

@ -0,0 +1,8 @@
import { defineMessages } from 'react-intl'
/* eslint-disable max-len */
export default defineMessages({
sent: 'Sent',
fee: 'Fee',
lightning: 'Lightning Network'
})

44
app/components/Activity/Transaction/Transaction.js

@ -1,37 +1,53 @@
import React from 'react'
import PropTypes from 'prop-types'
import Moment from 'react-moment'
import Isvg from 'react-inlinesvg'
import link from 'icons/link.svg'
import { btc } from 'lib/utils'
import Value from 'components/Value'
import { FormattedNumber, FormattedTime, FormattedMessage, injectIntl } from 'react-intl'
import messages from './messages'
import styles from '../Activity.scss'
const Transaction = ({ transaction, ticker, currentTicker, showActivityModal, currencyName }) => (
const Transaction = ({
transaction,
ticker,
currentTicker,
showActivityModal,
currencyName,
intl
}) => (
<div
className={styles.container}
onClick={() => showActivityModal('TRANSACTION', transaction.tx_hash)}
>
<div className={styles.activityTypeIcon}>
<section className="hint--bottom" data-hint="On-chain transaction">
<section className="hint--bottom" data-hint={intl.formatMessage({ ...messages.type })}>
<Isvg src={link} />
</section>
</div>
<div className={styles.data}>
<div className={styles.title}>
<h3>{transaction.received ? 'Received' : 'Sent'}</h3>
<h3>
{transaction.received ? (
<FormattedMessage {...messages.received} />
) : (
<FormattedMessage {...messages.sent} />
)}
</h3>
</div>
<div className={styles.subtitle}>
<Moment format="h:mm a">{transaction.time_stamp * 1000}</Moment>
<FormattedTime value={transaction.time_stamp * 1000} />
</div>
</div>
<div
className={`hint--top-left ${styles.amount} ${
transaction.received ? styles.positive : styles.negative
}`}
data-hint="Transaction amount"
data-hint={intl.formatMessage({ ...messages.amount })}
>
<span>
<i className={transaction.received ? styles.plus : styles.minus}>
@ -45,10 +61,16 @@ const Transaction = ({ transaction, ticker, currentTicker, showActivityModal, cu
/>
<i> {currencyName}</i>
</span>
<span className="hint--bottom" data-hint="Transaction fee">
{currentTicker[ticker.fiatTicker].symbol}
{btc.convert('sats', 'fiat', transaction.amount, currentTicker[ticker.fiatTicker].last)}
</span>
<FormattedNumber
currency={ticker.fiatTicker}
style="currency"
value={btc.convert(
'sats',
'fiat',
transaction.amount,
currentTicker[ticker.fiatTicker].last
)}
/>
</div>
</div>
)
@ -61,4 +83,4 @@ Transaction.propTypes = {
currencyName: PropTypes.string.isRequired
}
export default Transaction
export default injectIntl(Transaction)

10
app/components/Activity/Transaction/messages.js

@ -0,0 +1,10 @@
import { defineMessages } from 'react-intl'
/* eslint-disable max-len */
export default defineMessages({
received: 'Received',
sent: 'Sent',
amount: 'Transaction amount',
fee: 'Transaction fee',
type: 'On-chain transaction'
})

30
app/components/Activity/TransactionModal/TransactionModal.js

@ -1,10 +1,6 @@
import React from 'react'
import PropTypes from 'prop-types'
import Moment from 'react-moment'
import FaAngleDown from 'react-icons/lib/fa/angle-down'
import Isvg from 'react-inlinesvg'
import paperPlane from 'icons/paper_plane.svg'
import hand from 'icons/hand.svg'
@ -13,6 +9,9 @@ import { blockExplorer } from 'lib/utils'
import Value from 'components/Value'
import { FormattedDate, FormattedTime, FormattedMessage } from 'react-intl'
import messages from './messages'
import styles from './TransactionModal.scss'
const TransactionModal = ({
@ -34,12 +33,16 @@ const TransactionModal = ({
{transaction.received ? (
<section>
<Isvg src={hand} />
<span>Received</span>
<span>
<FormattedMessage {...messages.received} />
</span>
</section>
) : (
<section>
<Isvg src={paperPlane} />
<span>Sent</span>
<span>
<FormattedMessage {...messages.sent} />
</span>
</section>
)}
<section className={styles.details}>
@ -49,7 +52,7 @@ const TransactionModal = ({
className={styles.link}
onClick={() => blockExplorer.showTransaction(network, transaction.tx_hash)}
>
On-Chain
<FormattedMessage {...messages.on_chain} />
</span>
</div>
<div>
@ -59,7 +62,10 @@ const TransactionModal = ({
currentTicker={currentTicker}
fiatTicker={ticker.fiatTicker}
/>
<span> {currencyName} fee</span>
<span>
{' '}
{currencyName} <FormattedMessage {...messages.fee} />
</span>
</div>
</section>
</header>
@ -95,7 +101,13 @@ const TransactionModal = ({
</div>
<div className={styles.date}>
<Moment format="LLL">{transaction.time_stamp * 1000}</Moment>
<FormattedDate
value={new Date(transaction.time_stamp * 1000)}
year="numeric"
month="long"
day="2-digit"
/>{' '}
<FormattedTime value={new Date(transaction.time_stamp * 1000)} />
</div>
<footer className={styles.footer}>

9
app/components/Activity/TransactionModal/messages.js

@ -0,0 +1,9 @@
import { defineMessages } from 'react-intl'
/* eslint-disable max-len */
export default defineMessages({
fee: 'Fee',
on_chain: 'On-Chain',
received: 'Received',
sent: 'Sent'
})

13
app/components/Activity/messages.js

@ -0,0 +1,13 @@
import { defineMessages } from 'react-intl'
/* eslint-disable max-len */
export default defineMessages({
all: 'All',
sent: 'Sent',
requested: 'Requested',
pending: 'Pending',
refresh: 'Refresh',
search: 'Search',
hide_expired: 'Hide Expired Requests',
show_expired: 'Show Expired Requests'
})

6
app/components/App/App.js

@ -9,8 +9,6 @@ import ChannelForm from 'components/Contacts/ChannelForm'
import Network from 'components/Contacts/Network'
import AddChannel from 'components/Contacts/AddChannel'
import ContactModal from 'components/Contacts/ContactModal'
import ReceiveModal from 'components/Wallet/ReceiveModal'
import ActivityModal from 'components/Activity/ActivityModal'
@ -52,7 +50,6 @@ class App extends Component {
error: { error },
clearError,
contactModalProps,
contactsFormProps,
networkTabProps,
receiveModalProps,
@ -71,8 +68,6 @@ class App extends Component {
<div className={styles.titleBar} />
<GlobalError error={error} clearError={clearError} />
<ContactModal {...contactModalProps} />
<ChannelForm {...channelFormProps} />
<ReceiveModal {...receiveModalProps} />
@ -98,7 +93,6 @@ App.propTypes = {
closeForm: PropTypes.func.isRequired,
error: PropTypes.object.isRequired,
currentTicker: PropTypes.object,
contactModalProps: PropTypes.object,
contactsFormProps: PropTypes.object,
networkTabProps: PropTypes.object,
activityModalProps: PropTypes.object,

25
app/components/Contacts/AddChannel/AddChannel.js

@ -4,6 +4,9 @@ import Isvg from 'react-inlinesvg'
import x from 'icons/x.svg'
import { FormattedMessage } from 'react-intl'
import messages from './messages'
import styles from './AddChannel.scss'
const AddChannel = ({
@ -35,7 +38,9 @@ const AddChannel = ({
if (activeChannelPubkeys.includes(node.pub_key)) {
return (
<span className={`${styles.online} ${styles.inactive}`}>
<span>Online</span>
<span>
<FormattedMessage {...messages.online} />
</span>
</span>
)
}
@ -43,7 +48,9 @@ const AddChannel = ({
if (nonActiveChannelPubkeys.includes(node.pub_key)) {
return (
<span className={`${styles.offline} ${styles.inactive}`}>
<span>Offline</span>
<span>
<FormattedMessage {...messages.offline} />
</span>
</span>
)
}
@ -51,13 +58,19 @@ const AddChannel = ({
if (pendingOpenChannelPubkeys.includes(node.pub_key)) {
return (
<span className={`${styles.pending} ${styles.inactive}`}>
<span>Pending</span>
<span>
<FormattedMessage {...messages.pending} />
</span>
</span>
)
}
if (!node.addresses.length) {
return <span className={`${styles.private} ${styles.inactive}`}>Private</span>
return (
<span className={`${styles.private} ${styles.inactive}`}>
<FormattedMessage {...messages.private} />
</span>
)
}
return (
@ -128,10 +141,10 @@ const AddChannel = ({
{showManualForm && (
<section className={styles.manualForm}>
<p>
Hm, looks like we can&apos;t see that node from here, wanna try to manually connect?
<FormattedMessage {...messages.manual_description} />
</p>
<div className={styles.manualConnectButton} onClick={openManualForm}>
Connect Manually
<FormattedMessage {...messages.manual_button} />
</div>
</section>
)}

11
app/components/Contacts/AddChannel/messages.js

@ -0,0 +1,11 @@
import { defineMessages } from 'react-intl'
export default defineMessages({
online: 'Online',
offline: 'Offline',
pending: 'Pending',
private: 'Private',
manual_button: 'Connect Manually',
manual_description:
"Hm, looks like we can't see that node from here, wanna try to manually connect?"
})

21
app/components/Contacts/ConnectManually/ConnectManually.js

@ -1,5 +1,9 @@
import React from 'react'
import PropTypes from 'prop-types'
import { FormattedMessage, injectIntl } from 'react-intl'
import messages from './messages'
import styles from './ConnectManually.scss'
class ConnectManually extends React.Component {
@ -15,7 +19,8 @@ class ConnectManually extends React.Component {
setNode,
showErrors
showErrors,
intl
} = this.props
const formSubmitted = () => {
@ -48,15 +53,19 @@ class ConnectManually extends React.Component {
return (
<div className={styles.content}>
<header className={styles.header}>
<h1>Connect Manually</h1>
<p>Please enter the peer&apos;s pubkey@host</p>
<h1>
<FormattedMessage {...messages.title} />
</h1>
<p>
<FormattedMessage {...messages.description} />
</p>
</header>
<section className={styles.peer}>
<div className={styles.input}>
<input
type="text"
placeholder="pubkey@host"
placeholder={intl.formatMessage({ ...messages.placeholder })}
value={manualSearchQuery}
onChange={event => updateManualFormSearchQuery(event.target.value)}
/>
@ -76,7 +85,7 @@ class ConnectManually extends React.Component {
className={`${styles.button} ${manualFormIsValid.isValid ? styles.active : undefined}`}
onClick={formSubmitted}
>
Submit
<FormattedMessage {...messages.submit} />
</div>
</section>
</div>
@ -98,4 +107,4 @@ ConnectManually.propTypes = {
showErrors: PropTypes.object.isRequired
}
export default ConnectManually
export default injectIntl(ConnectManually)

9
app/components/Contacts/ConnectManually/messages.js

@ -0,0 +1,9 @@
import { defineMessages } from 'react-intl'
/* eslint-disable max-len */
export default defineMessages({
title: 'Connect Manually',
description: 'Please enter the peer’s pubkey@host',
placeholder: 'pubkey@host',
submit: 'Submit'
})

139
app/components/Contacts/ContactModal/ContactModal.js

@ -1,139 +0,0 @@
import React from 'react'
import PropTypes from 'prop-types'
import ReactModal from 'react-modal'
import FaCircle from 'react-icons/lib/fa/circle'
import MdClose from 'react-icons/lib/md/close'
import { btc } from 'lib/utils'
import styles from './ContactModal.scss'
const ContactModal = ({
isOpen,
channel,
closeContactModal,
channelNodes,
closeChannel,
closingChannelIds
}) => {
if (!channel) {
return <span />
}
const customStyles = {
overlay: {
cursor: 'pointer',
overflowY: 'auto'
},
content: {
top: 'auto',
left: '0',
right: '0',
bottom: 'auto',
width: '40%',
margin: '50px auto',
borderRadius: 'none',
padding: '0'
}
}
const removeClicked = () => {
closeChannel({
channel_point: channel.channel_point,
chan_id: channel.chan_id,
force: !channel.active
})
}
// the remote node for the channel
const node = channelNodes.find(node => node.pub_key === channel.remote_pubkey)
return (
<ReactModal
isOpen={isOpen}
contentLabel="No Overlay Click Modal"
ariaHideApp
shouldCloseOnOverlayClick
onRequestClose={closeContactModal}
parentSelector={() => document.body}
style={customStyles}
>
{channel && (
<div className={styles.container}>
<header className={styles.header}>
<div className={`${styles.status} ${channel.active ? styles.online : undefined}`}>
<FaCircle style={{ verticalAlign: 'top' }} />
<span>{channel.active ? 'Online' : 'Offline'}</span>
</div>
<div className={styles.closeContainer}>
<span onClick={closeContactModal}>
<MdClose />
</span>
</div>
</header>
<section className={styles.title}>
{node && <h1>{node.alias}</h1>}
<h2>{channel.remote_pubkey}</h2>
</section>
<section className={styles.stats}>
<div className={styles.pay}>
<h4>Can Pay</h4>
<div className={styles.meter}>
<div
className={styles.amount}
style={{ width: `${(channel.local_balance / channel.capacity) * 100}%` }}
/>
</div>
<span>{btc.satoshisToBtc(channel.local_balance)} BTC</span>
</div>
<div className={styles.pay}>
<h4>Can Receive</h4>
<div className={styles.meter}>
<div
className={styles.amount}
style={{ width: `${(channel.remote_balance / channel.capacity) * 100}%` }}
/>
</div>
<span>{btc.satoshisToBtc(channel.remote_balance)} BTC</span>
</div>
<div className={styles.sent}>
<h4>Total Bitcoin Sent</h4>
<p>{btc.satoshisToBtc(channel.total_satoshis_sent)} BTC</p>
</div>
<div className={styles.received}>
<h4>Total Bitcoin Received</h4>
<p>{btc.satoshisToBtc(channel.total_satoshis_received)} BTC</p>
</div>
</section>
<footer>
{closingChannelIds.includes(channel.chan_id) ? (
<span className={styles.inactive}>
<div className={styles.loading}>
<div className={styles.spinner} />
</div>
</span>
) : (
<div onClick={removeClicked}>Remove</div>
)}
</footer>
</div>
)}
</ReactModal>
)
}
ContactModal.propTypes = {
channel: PropTypes.object,
isOpen: PropTypes.bool.isRequired,
closeContactModal: PropTypes.func.isRequired,
channelNodes: PropTypes.array.isRequired,
closeChannel: PropTypes.func.isRequired,
closingChannelIds: PropTypes.array.isRequired
}
export default ContactModal

151
app/components/Contacts/ContactModal/ContactModal.scss

@ -1,151 +0,0 @@
@import 'styles/variables.scss';
.header {
display: flex;
flex-direction: row;
justify-content: space-between;
align-items: flex-end;
background: $lightgrey;
padding: 20px;
.status {
font-size: 12px;
color: $darkestgrey;
&.online {
color: $green;
}
span {
margin-left: 5px;
}
}
.closeContainer {
background: $lightgrey;
line-height: 12px;
span {
color: $darkestgrey;
cursor: pointer;
}
}
}
.container section {
margin-bottom: 30px;
padding: 0 20px;
.pay,
.receive,
.sent,
.received {
margin: 40px 0;
}
}
.container .title {
margin: 0;
padding: 30px 20px;
background: $lightgrey;
h1 {
color: $secondary;
font-weight: bold;
font-size: 16px;
letter-spacing: 1.1px;
margin-bottom: 10px;
}
h2 {
font-size: 12px;
color: $darkestgrey;
font-weight: 100;
}
}
.stats {
h4 {
color: $secondary;
font-weight: bold;
font-size: 12px;
}
span {
font-size: 14px;
}
p {
margin-top: 10px;
color: $darkestgrey;
}
.meter,
.amount {
height: 10px;
border-radius: 10px;
}
.meter {
background: $darkgrey;
width: 100%;
margin: 10px 0;
}
.amount {
background: $darkestgrey;
}
}
.container footer {
padding: 20px;
text-align: center;
div {
color: $red;
font-size: 18px;
&:hover {
color: lighten($red, 10%);
}
}
}
@-webkit-keyframes animation-rotate {
100% {
-webkit-transform: rotate(360deg);
}
}
@-moz-keyframes animation-rotate {
100% {
-moz-transform: rotate(360deg);
}
}
@-o-keyframes animation-rotate {
100% {
-o-transform: rotate(360deg);
}
}
@keyframes animation-rotate {
100% {
transform: rotate(360deg);
}
}
.spinner {
border: 1px solid rgba(0, 0, 0, 0.1);
border-left-color: rgba(0, 0, 0, 0.4);
-webkit-border-radius: 999px;
-moz-border-radius: 999px;
border-radius: 999px;
margin: 0 auto;
height: 20px;
width: 20px;
-webkit-animation: animation-rotate 1000ms linear infinite;
-moz-animation: animation-rotate 1000ms linear infinite;
-o-animation: animation-rotate 1000ms linear infinite;
animation: animation-rotate 1000ms linear infinite;
}

3
app/components/Contacts/ContactModal/index.js

@ -1,3 +0,0 @@
import ContactModal from './ContactModal'
export default ContactModal

275
app/components/Contacts/ContactsForm/ContactsForm.js

@ -1,275 +0,0 @@
import React from 'react'
import PropTypes from 'prop-types'
import ReactModal from 'react-modal'
import MdClose from 'react-icons/lib/md/close'
import FaCircle from 'react-icons/lib/fa/circle'
import FaQuestionCircle from 'react-icons/lib/fa/question-circle'
import styles from './ContactsForm.scss'
class ContactsForm extends React.Component {
constructor(props) {
super(props)
this.state = {
editing: false
}
}
render() {
const {
contactsform,
contactsform: { showErrors },
closeContactsForm,
updateContactFormSearchQuery,
updateManualFormSearchQuery,
updateContactCapacity,
openChannel,
updateManualFormErrors,
activeChannelPubkeys,
nonActiveChannelPubkeys,
pendingOpenChannelPubkeys,
filteredNetworkNodes,
loadingChannelPubkeys,
showManualForm,
manualFormIsValid
} = this.props
const { editing } = this.state
const renderRightSide = node => {
if (loadingChannelPubkeys.includes(node.pub_key)) {
return (
<span className={styles.inactive}>
<div className={styles.loading}>
<div className={styles.spinner} />
</div>
</span>
)
}
if (activeChannelPubkeys.includes(node.pub_key)) {
return (
<span className={`${styles.online} ${styles.inactive}`}>
<FaCircle style={{ verticalAlign: 'top' }} /> <span>Online</span>
</span>
)
}
if (nonActiveChannelPubkeys.includes(node.pub_key)) {
return (
<span className={`${styles.offline} ${styles.inactive}`}>
<FaCircle style={{ verticalAlign: 'top' }} /> <span>Offline</span>
</span>
)
}
if (pendingOpenChannelPubkeys.includes(node.pub_key)) {
return (
<span className={`${styles.pending} ${styles.inactive}`}>
<FaCircle style={{ verticalAlign: 'top' }} /> <span>Pending</span>
</span>
)
}
if (!node.addresses.length) {
return <span className={`${styles.private} ${styles.inactive}`}>Private</span>
}
return (
<span
className={`${styles.connect} hint--left`}
data-hint={`Connect with ${contactsform.contactCapacity} BTC`}
onClick={() =>
openChannel({
pubkey: node.pub_key,
host: node.addresses[0].addr,
local_amt: contactsform.contactCapacity
})
}
>
Connect
</span>
)
}
const inputClicked = () => {
if (editing) {
return
}
this.setState({ editing: true })
}
const manualFormSubmit = () => {
if (!manualFormIsValid.isValid) {
updateManualFormErrors(manualFormIsValid.errors)
updateManualFormSearchQuery('')
return
}
// clear any existing errors
updateManualFormErrors({ manualInput: null })
const [pubkey, host] =
contactsform.manualSearchQuery && contactsform.manualSearchQuery.split('@')
openChannel({ pubkey, host, local_amt: contactsform.contactCapacity })
updateManualFormSearchQuery('')
}
const searchUpdated = search => {
updateContactFormSearchQuery(search)
if (search.includes('@') && search.split('@')[0].length === 66) {
updateManualFormSearchQuery(search)
}
}
return (
<div>
<ReactModal
isOpen={contactsform.isOpen}
contentLabel="No Overlay Click Modal"
ariaHideApp
shouldCloseOnOverlayClick
onRequestClose={() => closeContactsForm}
parentSelector={() => document.body}
className={styles.modal}
>
<header>
<div>
<h1>Add Contact</h1>
</div>
<div onClick={closeContactsForm} className={styles.modalClose}>
<MdClose />
</div>
</header>
<div className={styles.form}>
<div className={styles.search}>
<input
type="text"
placeholder="Find contact by alias or pubkey"
className={styles.searchInput}
value={contactsform.searchQuery}
onChange={event => searchUpdated(event.target.value)}
/>
</div>
<ul className={styles.networkResults}>
{filteredNetworkNodes.map(node => (
<li key={node.pub_key}>
<section>
{node.alias.length > 0 ? (
<h2>
<span>{node.alias.trim()}</span>
<span>
({node.pub_key.substr(0, 10)}
...
{node.pub_key.substr(node.pub_key.length - 10)})
</span>
</h2>
) : (
<h2>
<span>{node.pub_key}</span>
</h2>
)}
</section>
<section>{renderRightSide(node)}</section>
</li>
))}
</ul>
</div>
{showManualForm && (
<div className={styles.manualForm}>
<h2>
Hm, looks like we cant see that contact from here. Want to try and manually
connect?
</h2>
<section>
<input
type="text"
placeholder="pubkey@host"
value={contactsform.manualSearchQuery}
onChange={event => updateManualFormSearchQuery(event.target.value)}
/>
<div className={styles.submit} onClick={manualFormSubmit}>
Submit
</div>
{loadingChannelPubkeys.length > 0 && (
<div className={styles.manualFormSpinner}>
<div className={styles.loading}>
<div className={styles.spinner} />
</div>
</div>
)}
</section>
<section
className={`${styles.errorMessage} ${
showErrors.manualInput ? styles.active : undefined
}`}
>
{showErrors.manualInput && (
<span>{manualFormIsValid && manualFormIsValid.errors.manualInput}</span>
)}
</section>
</div>
)}
<footer className={styles.footer}>
<div>
<span>Use</span>
<span className={styles.amount}>
<input
type="text"
value={contactsform.contactCapacity}
onChange={event => updateContactCapacity(event.target.value)}
onClick={inputClicked}
onKeyPress={event => event.charCode === 13 && this.setState({ editing: false })}
readOnly={!editing}
style={{
width: `${editing ? 20 : contactsform.contactCapacity.toString().length + 1}%`
}}
/>
</span>
<span className={styles.caption}>
BTC per contact
<i
data-hint="You aren't spending anything, just moving money onto the Lightning Network"
className="hint--top"
>
<FaQuestionCircle style={{ verticalAlign: 'top' }} />
</i>
</span>
</div>
</footer>
</ReactModal>
</div>
)
}
}
ContactsForm.propTypes = {
contactsform: PropTypes.object.isRequired,
closeContactsForm: PropTypes.func.isRequired,
updateContactFormSearchQuery: PropTypes.func.isRequired,
updateManualFormSearchQuery: PropTypes.func.isRequired,
manualFormIsValid: PropTypes.shape({
errors: PropTypes.object,
isValid: PropTypes.bool
}).isRequired,
updateContactCapacity: PropTypes.func.isRequired,
updateManualFormErrors: PropTypes.func.isRequired,
openChannel: PropTypes.func.isRequired,
activeChannelPubkeys: PropTypes.array.isRequired,
nonActiveChannelPubkeys: PropTypes.array.isRequired,
pendingOpenChannelPubkeys: PropTypes.array.isRequired,
filteredNetworkNodes: PropTypes.array.isRequired,
loadingChannelPubkeys: PropTypes.array.isRequired,
showManualForm: PropTypes.bool.isRequired
}
export default ContactsForm

253
app/components/Contacts/ContactsForm/ContactsForm.scss

@ -1,253 +0,0 @@
@import 'styles/variables.scss';
.modal {
position: absolute;
width: 50%;
margin: 50px auto;
top: auto;
left: 0;
right: 0;
bottom: auto;
background: $white;
outline: none;
z-index: -2;
border: 1px solid $darkgrey;
header {
display: flex;
flex-direction: row;
justify-content: space-between;
padding: 15px;
border-bottom: 1px solid $darkgrey;
h1,
svg {
font-size: 22px;
}
svg {
cursor: pointer;
}
}
}
.form {
padding: 30px 15px;
.search {
.searchInput {
width: calc(100% - 30px);
padding: 10px 15px;
outline: 0;
border: 0;
background: $lightgrey;
color: $darkestgrey;
border-radius: 5px;
font-size: 16px;
}
}
.networkResults {
overflow-y: auto;
height: 250px;
margin-top: 30px;
padding: 20px 0;
li {
display: flex;
flex-direction: row;
justify-content: space-between;
padding: 10px 0;
h2 {
font-size: 16px;
font-weight: bold;
letter-spacing: 1.3px;
span {
display: inline-block;
vertical-align: middle;
&:nth-child(1) {
font-size: 14px;
font-weight: bold;
letter-spacing: 1.3px;
}
&:nth-child(2) {
color: $darkestgrey;
font-size: 12px;
line-height: 14px;
}
}
}
.connect {
cursor: pointer;
color: $darkestgrey;
transition: all 0.25s;
font-size: 12px;
&:hover {
color: $main;
}
}
.inactive {
font-size: 12px;
display: inline-block;
vertical-align: top;
&.online {
color: $green;
}
&.offline {
color: $darkestgrey;
}
&.pending {
color: $orange;
}
&.private {
color: darken($darkestgrey, 50%);
}
}
}
}
}
.manualForm {
position: relative;
background: $lightgrey;
color: $darkestgrey;
padding: 30px 15px;
h2 {
font-size: 16px;
margin-bottom: 10px;
}
input {
border: 0;
outline: 0;
background: transparent;
color: $darkestgrey;
border-bottom: 1px solid $darkestgrey;
padding: 10px 5px;
width: 80%;
}
.submit {
display: inline-block;
vertical-align: middle;
width: 15%;
margin-left: 2.5%;
font-size: 12px;
&:hover {
cursor: pointer;
color: $main;
}
}
.manualFormSpinner {
position: absolute;
right: 0;
top: 40%;
padding: 0 10px;
}
}
.errorMessage {
margin: 10px 0;
min-height: 20px;
color: $red;
opacity: 0;
transition: all 0.25s ease;
&.active {
opacity: 1;
}
}
.footer {
padding: 10px 15px;
border-top: 1px solid $darkgrey;
font-size: 14px;
span {
&.amount {
&:hover {
input {
border: 1px solid $darkgrey;
cursor: text;
}
}
input {
border: 1px solid transparent;
padding: 0;
outline: 0;
font-weight: bold;
font-size: 14px;
line-height: 14px;
transition: all 0.25s;
&.isEditing {
width: 100%;
border-bottom: 1px solid $darkgrey;
}
}
}
&:nth-child(2) {
margin-left: 2px;
}
}
.caption svg {
font-size: 10px;
color: $darkestgrey;
}
}
@-webkit-keyframes animation-rotate {
100% {
-webkit-transform: rotate(360deg);
}
}
@-moz-keyframes animation-rotate {
100% {
-moz-transform: rotate(360deg);
}
}
@-o-keyframes animation-rotate {
100% {
-o-transform: rotate(360deg);
}
}
@keyframes animation-rotate {
100% {
transform: rotate(360deg);
}
}
.spinner {
border: 1px solid rgba(0, 0, 0, 0.1);
border-left-color: rgba(0, 0, 0, 0.4);
-webkit-border-radius: 999px;
-moz-border-radius: 999px;
border-radius: 999px;
margin: 0 auto;
height: 20px;
width: 20px;
-webkit-animation: animation-rotate 1000ms linear infinite;
-moz-animation: animation-rotate 1000ms linear infinite;
-o-animation: animation-rotate 1000ms linear infinite;
animation: animation-rotate 1000ms linear infinite;
}

3
app/components/Contacts/ContactsForm/index.js

@ -1,3 +0,0 @@
import ContactsForm from './ContactsForm'
export default ContactsForm

52
app/components/Contacts/Network/Network.js

@ -10,6 +10,10 @@ import plus from 'icons/plus.svg'
import search from 'icons/search.svg'
import Value from 'components/Value'
import { FormattedNumber, FormattedMessage, injectIntl } from 'react-intl'
import messages from './messages'
import SuggestedNodes from '../SuggestedNodes'
import styles from './Network.scss'
@ -59,7 +63,8 @@ class Network extends Component {
network,
currencyName
currencyName,
intl
} = this.props
const refreshClicked = () => {
@ -164,7 +169,9 @@ class Network extends Component {
<div className={styles.network}>
<header className={styles.header}>
<section>
<h2>My Network</h2>
<h2>
<FormattedMessage {...messages.title} />
</h2>
<span className={styles.channelAmount}>
<Value
value={balance.channelBalance}
@ -172,15 +179,22 @@ class Network extends Component {
currentTicker={currentTicker}
fiatTicker={ticker.fiatTicker}
/>
{`${currentTicker[ticker.fiatTicker].symbol}${
fiatAmount ? fiatAmount.toLocaleString() : ''
}`}
{Boolean(fiatAmount) && (
<span>
{'≈ '}
<FormattedNumber
currency={ticker.fiatTicker}
style="currency"
value={fiatAmount}
/>
</span>
)}
</span>
</section>
<section
className={`${styles.addChannel} hint--bottom-left`}
onClick={openContactsForm}
data-hint="Open a channel"
data-hint={intl.formatMessage({ ...messages.open_channel })}
>
<span className={styles.plusContainer}>
<Isvg src={plus} />
@ -214,7 +228,7 @@ class Network extends Component {
this.repeat = ref
}}
>
{refreshing ? <FaRepeat /> : 'Refresh'}
{refreshing ? <FaRepeat /> : <FormattedMessage {...messages.refresh} />}
</span>
</section>
</header>
@ -238,7 +252,10 @@ class Network extends Component {
return (
<li key={loadingPubkey} className={styles.channel}>
<section className={styles.channelTitle}>
<span className={`${styles.loading} hint--right`} data-hint="loading">
<span
className={`${styles.loading} hint--right`}
data-hint={intl.formatMessage({ ...messages.loading })}
>
<i className={styles.spinner} />
</span>
<span>{nodeDisplay()}</span>
@ -264,7 +281,7 @@ class Network extends Component {
<section className={styles.channelTitle}>
<span
className={`${styles[channelStatus(channelObj)]} hint--right`}
data-hint={channelStatus(channelObj)}
data-hint={intl.formatMessage({ ...messages[channelStatus(channelObj)] })}
>
{closingChannelIds.includes(channel.chan_id) ? (
<span className={styles.loading}>
@ -296,7 +313,9 @@ class Network extends Component {
<div className={styles.limits}>
<section>
<h5>Pay Limit</h5>
<h5>
<FormattedMessage {...messages.pay_limit} />
</h5>
<p>
<Value
value={channel.local_balance}
@ -308,7 +327,9 @@ class Network extends Component {
</p>
</section>
<section>
<h5>Request Limit</h5>
<h5>
<FormattedMessage {...messages.req_limit} />
</h5>
<p>
<Value
value={channel.remote_balance}
@ -323,7 +344,10 @@ class Network extends Component {
<div className={styles.actions}>
{closingChannelIds.includes(channel.chan_id) && (
<section>
<span className={`${styles.loading} hint--right`} data-hint="closing">
<span
className={`${styles.loading} hint--right`}
data-hint={intl.formatMessage({ ...messages.closing })}
>
<i>Closing</i> <i className={`${styles.spinner} ${styles.closing}`} />
</span>
</section>
@ -350,7 +374,7 @@ class Network extends Component {
id="search"
type="text"
className={`${styles.text} ${styles.input}`}
placeholder="search by alias or pubkey"
placeholder={intl.formatMessage({ ...messages.search_placeholder })}
value={searchQuery}
onChange={event => updateChannelSearchQuery(event.target.value)}
/>
@ -385,4 +409,4 @@ Network.propTypes = {
currencyName: PropTypes.string.isRequired
}
export default Network
export default injectIntl(Network)

16
app/components/Contacts/Network/messages.js

@ -0,0 +1,16 @@
import { defineMessages } from 'react-intl'
/* eslint-disable max-len */
export default defineMessages({
title: 'My Network',
loading: 'loading',
pending: 'pending',
closing: 'closing',
offline: 'offline',
online: 'online',
refresh: 'Refresh',
open_channel: 'Open a channel',
pay_limit: 'Pay Limit',
req_limit: 'Request Limit',
search_placeholder: 'search by alias or pubkey'
})

40
app/components/Contacts/SubmitChannelForm/SubmitChannelForm.js

@ -5,6 +5,10 @@ import FaAngleDown from 'react-icons/lib/fa/angle-down'
import FaExclamationCircle from 'react-icons/lib/fa/exclamation-circle'
import AmountInput from 'components/AmountInput'
import { FormattedNumber, FormattedMessage } from 'react-intl'
import messages from './messages'
import styles from './SubmitChannelForm.scss'
class SubmitChannelForm extends React.Component {
@ -55,16 +59,18 @@ class SubmitChannelForm extends React.Component {
const renderWarning = dupeChanInfo => {
const { alias, activeChannels, capacity, currencyName } = dupeChanInfo
const chansMsg =
activeChannels === 1 ? ' an active channel ' : ` ${activeChannels} active channels `
const aliasMsg = alias ? <span className={styles.alias}>{alias}</span> : ' this node '
const aliasMsg = alias ? <span className={styles.alias}>{alias}</span> : 'this_node'
return (
<p>
{`You currently have ${chansMsg} open to `}
{aliasMsg}
{` with a capacity of ${capacity} ${currencyName}.`}
<FormattedMessage
{...messages.duplicate_warnig}
values={{
activeChannels,
aliasMsg
}}
/>{' '}
{capacity} {currencyName}.
</p>
)
}
@ -92,11 +98,11 @@ class SubmitChannelForm extends React.Component {
return (
<div className={styles.content}>
<header className={styles.header}>
<h1>Add Funds to Network</h1>
<h1>
<FormattedMessage {...messages.title} />
</h1>
<p>
Opening a channel will help you send and receive money on the Lightning Network. You
aren&apos;t spending any money, rather moving the money you plan to use onto the
network.
<FormattedMessage {...messages.description} />
</p>
</header>
@ -139,8 +145,14 @@ class SubmitChannelForm extends React.Component {
</ul>
</div>
</div>
<div className={styles.fiatAmount}>{`${contactFormFiatAmount || 0} ${fiatTicker}`}</div>
<div className={styles.fiatAmount}>
{'≈ '}
<FormattedNumber
currency={fiatTicker}
style="currency"
value={contactFormFiatAmount || 0}
/>
</div>
</section>
<section className={styles.submit}>
@ -148,7 +160,7 @@ class SubmitChannelForm extends React.Component {
className={`${styles.button} ${contactCapacity > 0 ? styles.active : undefined}`}
onClick={formSubmitted}
>
Submit
<FormattedMessage {...messages.submit} />
</div>
</section>
</div>

11
app/components/Contacts/SubmitChannelForm/messages.js

@ -0,0 +1,11 @@
import { defineMessages } from 'react-intl'
/* eslint-disable max-len */
export default defineMessages({
title: 'Add Funds to Network',
description:
"Opening a channel will help you send and receive money on the Lightning Network. You aren't spending any money, rather moving the money you plan to use onto the network.",
submit: 'Submit',
duplicate_warnig:
'You currently have {activeChannels, plural, zero {no active channels} one {1 active channel} other {{activeChannels} active channels}} open to {aliasMsg, select, this_node {this node} other {{aliasMsg}}} with a capacity of'
})

11
app/components/Contacts/SuggestedNodes/SuggestedNodes.js

@ -1,5 +1,9 @@
import React from 'react'
import PropTypes from 'prop-types'
import { FormattedMessage } from 'react-intl'
import messages from './messages'
import styles from './SuggestedNodes.scss'
const SuggestedNodes = ({
@ -27,8 +31,7 @@ const SuggestedNodes = ({
return (
<div className={styles.container}>
<header>
Hmmm, looks like you don&apos;t have any channels yet. Here are some suggested nodes to open
a channel with to get started
<FormattedMessage {...messages.empty_description} />
</header>
<ul className={styles.suggestedNodes}>
@ -39,7 +42,9 @@ const SuggestedNodes = ({
<span>{`${node.pubkey.substring(0, 30)}...`}</span>
</section>
<section>
<span onClick={() => nodeClicked(node)}>Connect</span>
<span onClick={() => nodeClicked(node)}>
<FormattedMessage {...messages.connect} />
</span>
</section>
</li>
))}

8
app/components/Contacts/SuggestedNodes/messages.js

@ -0,0 +1,8 @@
import { defineMessages } from 'react-intl'
/* eslint-disable max-len */
export default defineMessages({
connect: 'Connect',
empty_description:
"Hmmm, looks like you don't have any channels yet. Here are some suggested nodes to open a channel with to get started"
})

37
app/components/Form/Pay/Pay.js

@ -9,6 +9,9 @@ import FaAngleDown from 'react-icons/lib/fa/angle-down'
import { btc } from 'lib/utils'
import AmountInput from 'components/AmountInput'
import { FormattedNumber, FormattedMessage, injectIntl } from 'react-intl'
import messages from './messages'
import styles from './Pay.scss'
class Pay extends Component {
@ -65,7 +68,8 @@ class Pay extends Component {
onPaySubmit,
setCurrency
setCurrency,
intl
} = this.props
const displayNodeName = pubkey => {
@ -92,20 +96,26 @@ class Pay extends Component {
<div className={styles.container}>
<header className={styles.header}>
<Isvg src={paperPlane} />
<h1>Make Payment</h1>
<h1>
<FormattedMessage {...messages.title} />
</h1>
</header>
<div className={styles.content}>
<section className={styles.destination}>
<div className={styles.top}>
<label htmlFor="paymentRequest">Destination</label>
<label htmlFor="paymentRequest">
<FormattedMessage {...messages.destination} />
</label>
<span
className={`${styles.description} ${isOnchain || isLn ? styles.active : undefined}`}
>
{isOnchain && (
<i>
<Isvg src={link} />
<span>On-Chain (~10 minutes)</span>
<span>
<FormattedMessage {...messages.onchain_description} />
</span>
</i>
)}
{isLn && (
@ -120,7 +130,7 @@ class Pay extends Component {
<div className={styles.bottom}>
<textarea
type="text"
placeholder="Paste payment request or bitcoin address here"
placeholder={intl.formatMessage({ ...messages.request_placeholder })}
value={payInput}
onChange={event => setPayInput(event.target.value)}
onBlur={onPayInputBlur}
@ -140,7 +150,9 @@ class Pay extends Component {
<section className={styles.amount}>
<div className={styles.top}>
<label htmlFor="amount">Amount</label>
<label htmlFor="amount">
<FormattedMessage {...messages.amount} />
</label>
<span />
</div>
<div className={styles.bottom}>
@ -172,7 +184,14 @@ class Pay extends Component {
</div>
</div>
<div className={styles.fiatAmount}>{`${fiatAmount || 0} ${ticker.fiatTicker}`}</div>
<div className={styles.fiatAmount}>
{'≈ '}
<FormattedNumber
currency={ticker.fiatTicker}
style="currency"
value={fiatAmount || 0}
/>
</div>
<section
className={`${styles.errorMessage} ${styles.amount} ${
@ -188,7 +207,7 @@ class Pay extends Component {
className={`${styles.button} ${isValid ? styles.active : undefined}`}
onClick={onPaySubmit}
>
Pay
<FormattedMessage {...messages.pay} />
</div>
</section>
</div>
@ -231,4 +250,4 @@ Pay.propTypes = {
currentCurrencyFilters: PropTypes.array.isRequired
}
export default Pay
export default injectIntl(Pay)

11
app/components/Form/Pay/messages.js

@ -0,0 +1,11 @@
import { defineMessages } from 'react-intl'
/* eslint-disable max-len */
export default defineMessages({
title: 'Make Payment',
destination: 'Destination',
amount: 'Amount',
request_placeholder: 'Paste payment request or bitcoin address here',
pay: 'Pay',
onchain_description: 'On-Chain (~10 minutes)'
})

36
app/components/Form/Request/Request.js

@ -7,6 +7,10 @@ import FaAngleDown from 'react-icons/lib/fa/angle-down'
import { btc } from 'lib/utils'
import AmountInput from 'components/AmountInput'
import { FormattedNumber, FormattedMessage, injectIntl } from 'react-intl'
import messages from './messages'
import styles from './Request.scss'
const Request = ({
@ -22,7 +26,8 @@ const Request = ({
currentCurrencyFilters,
onRequestSubmit
onRequestSubmit,
intl
}) => {
const onCurrencyFilterClick = currency => {
// change the input amount
@ -36,13 +41,17 @@ const Request = ({
<div className={styles.container}>
<header className={styles.header}>
<Isvg src={hand} />
<h1>Request Payment</h1>
<h1>
<FormattedMessage {...messages.title} />
</h1>
</header>
<div className={styles.content}>
<section className={styles.amount}>
<div className={styles.top}>
<label htmlFor="amount">Amount</label>
<label htmlFor="amount">
<FormattedMessage {...messages.amount} />
</label>
<span />
</div>
<div className={styles.bottom}>
@ -72,19 +81,26 @@ const Request = ({
</div>
</div>
<div className={styles.fiatAmount}>{`${requestFiatAmount || 0} ${
ticker.fiatTicker
}`}</div>
<div className={styles.fiatAmount}>
{'≈ '}
<FormattedNumber
currency={ticker.fiatTicker}
style="currency"
value={requestFiatAmount}
/>
</div>
</section>
<section className={styles.memo}>
<div className={styles.top}>
<label htmlFor="memo">Memo</label>
<label htmlFor="memo">
<FormattedMessage {...messages.memo} />
</label>
</div>
<div className={styles.bottom}>
<input
type="text"
placeholder="Details about the request"
placeholder={intl.formatMessage({ ...messages.details })}
value={memo}
onChange={event => setRequestMemo(event.target.value)}
id="memo"
@ -97,7 +113,7 @@ const Request = ({
className={`${styles.button} ${amount > 0 ? styles.active : undefined}`}
onClick={onRequestSubmit}
>
Request
<FormattedMessage {...messages.request} />
</div>
</section>
</div>
@ -125,4 +141,4 @@ Request.propTypes = {
ticker: PropTypes.object.isRequired
}
export default Request
export default injectIntl(Request)

9
app/components/Form/Request/messages.js

@ -0,0 +1,9 @@
import { defineMessages } from 'react-intl'
export default defineMessages({
title: 'Request Payment',
amount: 'Amount',
memo: 'Memo',
details: 'Details about the request',
request: 'Request'
})

7
app/components/LoadingBolt/LoadingBolt.js

@ -3,13 +3,18 @@ import Isvg from 'react-inlinesvg'
import cloudboltIcon from 'icons/cloudbolt.svg'
import { FormattedMessage } from 'react-intl'
import messages from './messages'
import styles from './LoadingBolt.scss'
const LoadingBolt = () => (
<div className={styles.container}>
<div className={styles.content}>
<Isvg className={styles.bolt} src={cloudboltIcon} />
<h1>loading</h1>
<h1>
<FormattedMessage {...messages.loading} />
</h1>
</div>
</div>
)

6
app/components/LoadingBolt/messages.js

@ -0,0 +1,6 @@
import { defineMessages } from 'react-intl'
/* eslint-disable max-len */
export default defineMessages({
loading: 'loading'
})

10
app/components/Onboarding/Autopilot/Autopilot.js

@ -2,6 +2,8 @@ import React from 'react'
import PropTypes from 'prop-types'
import FaCircle from 'react-icons/lib/fa/circle'
import FaCircleThin from 'react-icons/lib/fa/circle-thin'
import { FormattedMessage } from 'react-intl'
import messages from './messages'
import styles from './Autopilot.scss'
const Autopilot = ({ autopilot, setAutopilot }) => (
@ -9,7 +11,9 @@ const Autopilot = ({ autopilot, setAutopilot }) => (
<section className={`${styles.enable} ${autopilot ? styles.active : undefined}`}>
<div onClick={() => setAutopilot(true)}>
{autopilot ? <FaCircle /> : <FaCircleThin />}
<span className={styles.label}>Enable Autopilot</span>
<span className={styles.label}>
<FormattedMessage {...messages.enable} /> Autopilot
</span>
</div>
</section>
<section
@ -19,7 +23,9 @@ const Autopilot = ({ autopilot, setAutopilot }) => (
>
<div onClick={() => setAutopilot(false)}>
{!autopilot && autopilot !== null ? <FaCircle /> : <FaCircleThin />}
<span className={styles.label}>Disable Autopilot</span>
<span className={styles.label}>
<FormattedMessage {...messages.disable} /> Autopilot
</span>
</div>
</section>
</div>

7
app/components/Onboarding/Autopilot/messages.js

@ -0,0 +1,7 @@
import { defineMessages } from 'react-intl'
/* eslint-disable max-len */
export default defineMessages({
enable: 'Enable',
disable: 'Disable'
})

21
app/components/Onboarding/BtcPayServer/BtcPayServer.js

@ -1,21 +1,28 @@
import React from 'react'
import PropTypes from 'prop-types'
import { FormattedMessage, injectIntl } from 'react-intl'
import messages from './messages'
import styles from './BtcPayServer.scss'
const BtcPayServer = ({
connectionString,
connectionStringIsValid,
setConnectionString,
startLndHostError
startLndHostError,
intl
}) => (
<div className={styles.container}>
<section className={styles.input}>
<label htmlFor="connectionString">Connection String:</label>
<label htmlFor="connectionString">
<FormattedMessage {...messages.connection_string_label} />:
</label>
<textarea
type="text"
id="connectionString"
rows="10"
placeholder="BTCPay Server Connection String"
placeholder={intl.formatMessage({ ...messages.connection_string_placeholder })}
className={
connectionString && (startLndHostError || !connectionStringIsValid)
? styles.error
@ -26,16 +33,14 @@ const BtcPayServer = ({
onChange={event => setConnectionString(event.target.value)}
/>
<p className={styles.description}>
Paste the full content of your BTCPay Server connection config file. This can be found by
clicking the link entitled &quot;Click here to open the configuration file.&quot; in your
BTCPay Server gRPC settings.
<FormattedMessage {...messages.btcpay_description} />
</p>
<p
className={`${styles.errorMessage} ${
connectionString && !connectionStringIsValid ? styles.visible : undefined
}`}
>
Invalid connection string.
<FormattedMessage {...messages.btcpay_error} />
</p>
<p
className={`${styles.errorMessage} ${
@ -55,4 +60,4 @@ BtcPayServer.propTypes = {
startLndHostError: PropTypes.string
}
export default BtcPayServer
export default injectIntl(BtcPayServer)

10
app/components/Onboarding/BtcPayServer/messages.js

@ -0,0 +1,10 @@
import { defineMessages } from 'react-intl'
/* eslint-disable max-len */
export default defineMessages({
btcpay_description:
"Paste the full content of your BTCPay Server connection config file. This can be found by clicking the link entitled 'Click here to open the configuration file' in your BTCPay Server gRPC settings.",
btcpay_error: 'Invalid connection string.',
connection_string_label: 'Connection String',
connection_string_placeholder: 'BTCPay Server Connection String'
})

8
app/components/Onboarding/ConnectionConfirm/ConnectionConfirm.js

@ -1,15 +1,19 @@
import React from 'react'
import PropTypes from 'prop-types'
import { FormattedMessage } from 'react-intl'
import messages from './messages'
import styles from './ConnectionConfirm.scss'
const ConnectionConfirm = ({ connectionHost }) => (
<div className={styles.container}>
<p>
Are you sure you want to connect to{' '}
<FormattedMessage {...messages.verify_host_title} />{' '}
<span className={styles.host}>{connectionHost.split(':')[0]}</span>?{' '}
</p>
<p>
<strong>Please check the hostname carefully.</strong>
<strong>
<FormattedMessage {...messages.verify_host_description} />
</strong>
</p>
</div>
)

7
app/components/Onboarding/ConnectionConfirm/messages.js

@ -0,0 +1,7 @@
import { defineMessages } from 'react-intl'
/* eslint-disable max-len */
export default defineMessages({
verify_host_title: 'Are you sure you want to connect to',
verify_host_description: 'Please check the hostname carefully.'
})

18
app/components/Onboarding/ConnectionDetails/ConnectionDetails.js

@ -1,5 +1,7 @@
import React from 'react'
import PropTypes from 'prop-types'
import { FormattedMessage } from 'react-intl'
import messages from './messages'
import styles from './ConnectionDetails.scss'
const ConnectionDetails = ({
@ -15,7 +17,9 @@ const ConnectionDetails = ({
}) => (
<div className={styles.container}>
<section className={styles.input}>
<label htmlFor="connectionHost">Host:</label>
<label htmlFor="connectionHost">
<FormattedMessage {...messages.hostname_title} />:
</label>
<input
type="text"
id="connectionHost"
@ -25,14 +29,16 @@ const ConnectionDetails = ({
onChange={event => setConnectionHost(event.target.value)}
/>
<p className={styles.description}>
Hostname and port of the Lnd gRPC interface. Example: localhost:10009
<FormattedMessage {...messages.hostname_description} />
</p>
<p className={`${startLndHostError ? styles.visible : undefined} ${styles.errorMessage}`}>
{startLndHostError}
</p>
</section>
<section className={styles.input}>
<label htmlFor="connectionCert">TLS Certificate:</label>
<label htmlFor="connectionCert">
<FormattedMessage {...messages.cert_title} />:
</label>
<input
type="text"
id="connectionCert"
@ -41,7 +47,9 @@ const ConnectionDetails = ({
value={connectionCert}
onChange={event => setConnectionCert(event.target.value)}
/>
<p className={styles.description}>Path to the lnd tls cert. Example: /path/to/tls.cert</p>
<p className={styles.description}>
<FormattedMessage {...messages.cert_description} />
</p>
<p className={`${startLndCertError ? styles.visible : undefined} ${styles.errorMessage}`}>
{startLndCertError}
</p>
@ -57,7 +65,7 @@ const ConnectionDetails = ({
onChange={event => setConnectionMacaroon(event.target.value)}
/>
<p className={styles.description}>
Path to the lnd macaroon file. Example: /path/to/admin.macaroon
<FormattedMessage {...messages.macaroon_description} />
</p>
<p className={`${startLndMacaroonError ? styles.visible : undefined} ${styles.errorMessage}`}>
{startLndMacaroonError}

10
app/components/Onboarding/ConnectionDetails/messages.js

@ -0,0 +1,10 @@
import { defineMessages } from 'react-intl'
/* eslint-disable max-len */
export default defineMessages({
hostname_title: 'Host',
hostname_description: 'Hostname and port of the Lnd gRPC interface. Example: localhost:10009',
cert_title: 'TLS Certificate',
cert_description: 'Path to the lnd tls cert. Example: /path/to/tls.cert',
macaroon_description: 'Path to the lnd macaroon file. Example: /path/to/admin.macaroon'
})

18
app/components/Onboarding/ConnectionType/ConnectionType.js

@ -2,6 +2,8 @@ import React from 'react'
import PropTypes from 'prop-types'
import FaCircle from 'react-icons/lib/fa/circle'
import FaCircleThin from 'react-icons/lib/fa/circle-thin'
import { FormattedMessage } from 'react-intl'
import messages from './messages'
import styles from './ConnectionType.scss'
const ConnectionType = ({ connectionType, setConnectionType }) => (
@ -12,13 +14,14 @@ const ConnectionType = ({ connectionType, setConnectionType }) => (
<div className={`${styles.button}`} onClick={() => setConnectionType('local')}>
{connectionType === 'local' ? <FaCircle /> : <FaCircleThin />}
<span className={styles.label}>
Default <span className={styles.superscript}>testnet</span>
<FormattedMessage {...messages.default} />{' '}
<span className={styles.superscript}>testnet</span>
</span>
</div>
<div className={`${styles.description}`}>
By selecting the defualt mode we will do everything for you. Just click and go!
<FormattedMessage {...messages.default_description} />
<br />
(testnet only)
(testnet <FormattedMessage {...messages.only} />)
</div>
</section>
<section
@ -26,11 +29,12 @@ const ConnectionType = ({ connectionType, setConnectionType }) => (
>
<div className={`${styles.button}`} onClick={() => setConnectionType('custom')}>
{connectionType === 'custom' ? <FaCircle /> : <FaCircleThin />}
<span className={styles.label}>Custom</span>
<span className={styles.label}>
<FormattedMessage {...messages.custom} />
</span>
</div>
<div className={`${styles.description}`}>
Connect to your own node. You will need to provide your own connection settings so this is
for advanced users only.
<FormattedMessage {...messages.custom_description} />
</div>
</section>
<section className={`${styles.option} ${connectionType === 'btcpayserver' && styles.active}`}>
@ -39,7 +43,7 @@ const ConnectionType = ({ connectionType, setConnectionType }) => (
<span className={styles.label}>BTCPay Server</span>
</div>
<div className={`${styles.description}`}>
Connect to your own BTCPay Server instance to access your BTCPay Server wallet.
<FormattedMessage {...messages.btcpay_description} />
</div>
</section>
</div>

14
app/components/Onboarding/ConnectionType/messages.js

@ -0,0 +1,14 @@
import { defineMessages } from 'react-intl'
/* eslint-disable max-len */
export default defineMessages({
default: 'Default',
default_description:
'By selecting the defualt mode we will do everything for you. Just click and go!',
only: 'only',
custom: 'Custom',
custom_description:
'Connect to your own node. You will need to provide your own connection settings so this is for advanced users only.',
btcpay_description:
'Connect to your own BTCPay Server instance to access your BTCPay Server wallet.'
})

14
app/components/Onboarding/FormContainer/FormContainer.js

@ -7,6 +7,8 @@ import FaAngleLeft from 'react-icons/lib/fa/angle-left'
import FaAngleRight from 'react-icons/lib/fa/angle-right'
import zapLogo from 'icons/zap_logo.svg'
import { FormattedMessage } from 'react-intl'
import messages from './messages'
import styles from './FormContainer.scss'
const FormContainer = ({ title, description, back, next, children }) => (
@ -24,7 +26,7 @@ const FormContainer = ({ title, description, back, next, children }) => (
shell.openExternal('https://ln-zap.github.io/zap-tutorials/zap-desktop-getting-started')
}
>
Need help?
<FormattedMessage {...messages.help} />
</div>
</section>
</header>
@ -41,14 +43,16 @@ const FormContainer = ({ title, description, back, next, children }) => (
<section>
{back && (
<div onClick={back} className={styles.backButton}>
<FaAngleLeft style={{ verticalAlign: 'top' }} /> Back
<FaAngleLeft style={{ verticalAlign: 'top' }} />{' '}
<FormattedMessage {...messages.back} />
</div>
)}
</section>
<section>
{next && (
<div onClick={next} className={styles.nextButton}>
Next <FaAngleRight style={{ verticalAlign: 'top' }} />
<FormattedMessage {...messages.next} />{' '}
<FaAngleRight style={{ verticalAlign: 'top' }} />
</div>
)}
</section>
@ -58,8 +62,8 @@ const FormContainer = ({ title, description, back, next, children }) => (
)
FormContainer.propTypes = {
title: PropTypes.string.isRequired,
description: PropTypes.string.isRequired,
title: PropTypes.node.isRequired,
description: PropTypes.node.isRequired,
back: PropTypes.func,
next: PropTypes.func,

8
app/components/Onboarding/FormContainer/messages.js

@ -0,0 +1,8 @@
import { defineMessages } from 'react-intl'
/* eslint-disable max-len */
export default defineMessages({
help: 'Need Help?',
next: 'Next',
back: 'back'
})

21
app/components/Onboarding/Login/Login.js

@ -1,12 +1,21 @@
import React from 'react'
import PropTypes from 'prop-types'
import { FormattedMessage, injectIntl } from 'react-intl'
import messages from './messages'
import styles from './Login.scss'
const Login = ({ password, updatePassword, unlockingWallet, unlockWallet, unlockWalletError }) => (
const Login = ({
password,
updatePassword,
unlockingWallet,
unlockWallet,
unlockWalletError,
intl
}) => (
<div className={styles.container}>
<input
type="password"
placeholder="Password"
placeholder={intl.formatMessage({ ...messages.password_placeholder })}
className={`${styles.password} ${unlockWalletError.isError ? styles.inputError : undefined}`}
ref={input => input && input.focus()}
value={password}
@ -27,7 +36,11 @@ const Login = ({ password, updatePassword, unlockingWallet, unlockWallet, unlock
className={`${!unlockingWallet ? styles.active : undefined} ${styles.button}`}
onClick={() => unlockWallet(password)}
>
{unlockingWallet ? <i className={styles.spinner} /> : 'Unlock'}
{unlockingWallet ? (
<i className={styles.spinner} />
) : (
<FormattedMessage {...messages.unlock} />
)}
</span>
</div>
</section>
@ -42,4 +55,4 @@ Login.propTypes = {
unlockWalletError: PropTypes.object.isRequired
}
export default Login
export default injectIntl(Login)

7
app/components/Onboarding/Login/messages.js

@ -0,0 +1,7 @@
import { defineMessages } from 'react-intl'
/* eslint-disable max-len */
export default defineMessages({
password_placeholder: 'Password',
unlock: 'Unlock'
})

20
app/components/Onboarding/NewWalletPassword/NewWalletPassword.js

@ -1,5 +1,7 @@
import React from 'react'
import PropTypes from 'prop-types'
import { FormattedMessage, injectIntl } from 'react-intl'
import messages from './messages'
import styles from './NewWalletPassword.scss'
const NewWalletPassword = ({
@ -8,13 +10,14 @@ const NewWalletPassword = ({
showCreateWalletPasswordConfirmationError,
passwordMinCharsError,
updateCreateWalletPassword,
updateCreateWalletPasswordConfirmation
updateCreateWalletPasswordConfirmation,
intl
}) => (
<div className={styles.container}>
<section className={styles.input}>
<input
type="password"
placeholder="Password"
placeholder={intl.formatMessage({ ...messages.password_placeholder })}
className={`${styles.password} ${
showCreateWalletPasswordConfirmationError ? styles.error : undefined
}
@ -27,7 +30,7 @@ const NewWalletPassword = ({
<section className={styles.input}>
<input
type="password"
placeholder="Confirm Password"
placeholder={intl.formatMessage({ ...messages.password_confirm_placeholder })}
className={`${styles.password} ${
showCreateWalletPasswordConfirmationError ? styles.error : undefined
}
@ -40,10 +43,15 @@ const NewWalletPassword = ({
showCreateWalletPasswordConfirmationError ? styles.visible : undefined
}`}
>
Passwords do not match
<FormattedMessage {...messages.password_error_match} />
</p>
<p className={`${styles.helpMessage} ${passwordMinCharsError ? styles.red : undefined}`}>
Password must be at least 8 characters long
<FormattedMessage
{...messages.password_error_length}
values={{
passwordMinLength: '8'
}}
/>
</p>
</section>
</div>
@ -58,4 +66,4 @@ NewWalletPassword.propTypes = {
updateCreateWalletPasswordConfirmation: PropTypes.func.isRequired
}
export default NewWalletPassword
export default injectIntl(NewWalletPassword)

10
app/components/Onboarding/NewWalletPassword/messages.js

@ -0,0 +1,10 @@
import { defineMessages } from 'react-intl'
/* eslint-disable max-len */
export default defineMessages({
password_placeholder: 'Password',
password_confirm_placeholder: 'Confirm Password',
password_error_match: 'Passwords do not match',
password_error_length: 'Password must be at least {passwordMinLength} characters long',
unlock: 'Unlock'
})

87
app/components/Onboarding/Onboarding.js

@ -1,7 +1,9 @@
import React from 'react'
import PropTypes from 'prop-types'
import { FormattedMessage } from 'react-intl'
import LoadingBolt from 'components/LoadingBolt'
import messages from './messages'
import FormContainer from './FormContainer'
import ConnectionType from './ConnectionType'
@ -54,12 +56,8 @@ const Onboarding = ({
case 0.1:
return (
<FormContainer
title="How do you want to connect to the Lightning Network?"
description="
By default Zap will spin up a node for you and handle all the nerdy stuff
in the background. However you can also setup a custom node connection and
use Zap to control a remote node if you desire (for advanced users).
"
title={<FormattedMessage {...messages.connection_title} />}
description={<FormattedMessage {...messages.connection_description} />}
back={null}
next={() => {
switch (connectionType) {
@ -81,8 +79,8 @@ const Onboarding = ({
case 0.2:
return (
<FormContainer
title="Connection details"
description="Enter the connection details for your Lightning node."
title={<FormattedMessage {...messages.connection_details_custom_title} />}
description={<FormattedMessage {...messages.connection_details_custom_description} />}
back={() => changeStep(0.1)}
next={() => {
// dont allow the user to move on if we don't at least have a hostname.
@ -100,8 +98,8 @@ const Onboarding = ({
case 0.3:
return (
<FormContainer
title="BTCPay Server"
description="Enter the connection details for your BTCPay Server node."
title={<FormattedMessage {...messages.btcpay_title} />}
description={<FormattedMessage {...messages.btcpay_description} />}
back={() => changeStep(0.1)}
next={() => {
// dont allow the user to move on if the connection string is invalid.
@ -119,8 +117,8 @@ const Onboarding = ({
case 0.4:
return (
<FormContainer
title="Confirm connection"
description="Confirm the connection details for your Lightning node."
title={<FormattedMessage {...messages.confirm_connection_title} />}
description={<FormattedMessage {...messages.confirm_connection_description} />}
back={() => changeStep(previousStep)}
next={() => {
startLnd({
@ -139,8 +137,8 @@ const Onboarding = ({
case 1:
return (
<FormContainer
title="What should we call you?"
description="Set your nickname to help others connect with you on the Lightning Network"
title={<FormattedMessage {...messages.alias_title} />}
description={<FormattedMessage {...messages.alias_description} />}
back={() => changeStep(0.1)}
next={() => changeStep(2)}
>
@ -150,8 +148,8 @@ const Onboarding = ({
case 2:
return (
<FormContainer
title="Autopilot"
description="Autopilot is an automatic network manager. Instead of manually adding people to build your network to make payments, enable autopilot to automatically connect you to the Lightning Network using 60% of your balance." // eslint-disable-line max-len
title={<FormattedMessage {...messages.autopilot_title} />}
description={<FormattedMessage {...messages.autopilot_description} />}
back={() => changeStep(1)}
next={() => startLnd({ type: connectionType, alias, autopilot })}
>
@ -159,24 +157,31 @@ const Onboarding = ({
</FormContainer>
)
case 3:
// eslint-disable-next-line no-case-declarations
let message = 'It looks like you already have a wallet'
if (initWalletProps.loginProps.existingWalletDir && connectionType === 'local') {
message += ` (we found one at ${initWalletProps.loginProps.existingWalletDir})`
} else {
message += ` at ${connectionHost.split(':')[0]}`
}
message += '. Please enter your wallet password to unlock it.'
return (
<FormContainer title="Welcome back!" description={`${message}`} back={null} next={null}>
<FormContainer
title={<FormattedMessage {...messages.login_title} />}
description={
<FormattedMessage
{...messages.login_description}
values={{
walletDir:
initWalletProps.loginProps.existingWalletDir && connectionType === 'local'
? initWalletProps.loginProps.existingWalletDir
: connectionHost.split(':')[0]
}}
/>
}
back={null}
next={null}
>
<Login {...initWalletProps.loginProps} />
</FormContainer>
)
case 4:
return (
<FormContainer
title="Welcome!"
description="Looks like you are new here. Set a password to encrypt your wallet. This password will be needed to unlock Zap in the future" // eslint-disable-line max-len
title={<FormattedMessage {...messages.create_wallet_password_title} />}
description={<FormattedMessage {...messages.create_wallet_password_description} />}
back={null}
next={() => {
// dont allow the user to move on if the confirmation password doesnt match the original password
@ -199,8 +204,8 @@ const Onboarding = ({
case 5:
return (
<FormContainer
title={"Alright, let's get set up"}
description="Would you like to create a new wallet or import an existing one?"
title={<FormattedMessage {...messages.signup_title} />}
description={<FormattedMessage {...messages.signup_description} />}
back={() => changeStep(4)}
next={() => {
// require the user to select create wallet or import wallet
@ -220,8 +225,8 @@ const Onboarding = ({
case 5.1:
return (
<FormContainer
title="Import your seed"
description="Recovering a wallet, nice. You don't need anyone else, you got yourself :)"
title={<FormattedMessage {...messages.import_title} />}
description={<FormattedMessage {...messages.import_description} />}
back={() => changeStep(5)}
next={() => {
const recoverySeed = recoverFormProps.recoverSeedInput.map(input => input.word)
@ -235,8 +240,8 @@ const Onboarding = ({
case 6:
return (
<FormContainer
title="Save your wallet seed"
description="Please save these 24 words securely! This will allow you to recover your wallet in the future"
title={<FormattedMessage {...messages.save_seed_title} />}
description={<FormattedMessage {...messages.save_seed_description} />}
back={() => changeStep(5)}
next={() => changeStep(7)}
>
@ -246,11 +251,17 @@ const Onboarding = ({
case 7:
return (
<FormContainer
title="Retype your seed"
description={`Your seed is important! If you lose your seed you'll have no way to recover your wallet.
To make sure that you have properly saved your seed, please retype words ${
reEnterSeedProps.seedIndexesArr[0]
}, ${reEnterSeedProps.seedIndexesArr[1]} and ${reEnterSeedProps.seedIndexesArr[2]}`}
title={<FormattedMessage {...messages.retype_seed_title} />}
description={
<FormattedMessage
{...messages.retype_seed_description}
values={{
word1: reEnterSeedProps.seedIndexesArr[0],
word2: reEnterSeedProps.seedIndexesArr[1],
word3: reEnterSeedProps.seedIndexesArr[2]
}}
/>
}
back={() => changeStep(6)}
next={() => {
// don't allow them to move on if they havent re-entered the seed correctly

11
app/components/Onboarding/RecoverForm/RecoverForm.js

@ -1,8 +1,10 @@
import React from 'react'
import PropTypes from 'prop-types'
import { injectIntl } from 'react-intl'
import messages from './messages'
import styles from './RecoverForm.scss'
const RecoverForm = ({ recoverSeedInput, updateRecoverSeedInput }) => (
const RecoverForm = ({ recoverSeedInput, updateRecoverSeedInput, intl }) => (
<div className={styles.container}>
<ul className={styles.seedContainer}>
{Array(24)
@ -16,7 +18,7 @@ const RecoverForm = ({ recoverSeedInput, updateRecoverSeedInput }) => (
<input
type="text"
id={index}
placeholder="word"
placeholder={intl.formatMessage({ ...messages.word_placeholder })}
value={recoverSeedInput[index] ? recoverSeedInput[index].word : ''}
onChange={event => updateRecoverSeedInput({ word: event.target.value, index })}
className={styles.word}
@ -30,7 +32,8 @@ const RecoverForm = ({ recoverSeedInput, updateRecoverSeedInput }) => (
RecoverForm.propTypes = {
recoverSeedInput: PropTypes.array.isRequired,
updateRecoverSeedInput: PropTypes.func.isRequired
updateRecoverSeedInput: PropTypes.func.isRequired,
intl: PropTypes.object.isRequired
}
export default RecoverForm
export default injectIntl(RecoverForm)

6
app/components/Onboarding/RecoverForm/messages.js

@ -0,0 +1,6 @@
import { defineMessages } from 'react-intl'
/* eslint-disable max-len */
export default defineMessages({
word_placeholder: 'word'
})

10
app/components/Onboarding/Signup/Signup.js

@ -2,6 +2,8 @@ import React from 'react'
import PropTypes from 'prop-types'
import FaCircle from 'react-icons/lib/fa/circle'
import FaCircleThin from 'react-icons/lib/fa/circle-thin'
import { FormattedMessage } from 'react-intl'
import messages from './messages'
import styles from './Signup.scss'
const Signup = ({ signupForm, setSignupCreate, setSignupImport }) => (
@ -9,13 +11,17 @@ const Signup = ({ signupForm, setSignupCreate, setSignupImport }) => (
<section className={`${styles.enable} ${signupForm.create ? styles.active : undefined}`}>
<div onClick={setSignupCreate}>
{signupForm.create ? <FaCircle /> : <FaCircleThin />}
<span className={styles.label}>Create new wallet</span>
<span className={styles.label}>
<FormattedMessage {...messages.signup_create} />
</span>
</div>
</section>
<section className={`${styles.disable} ${signupForm.import ? styles.active : undefined}`}>
<div onClick={setSignupImport}>
{signupForm.import ? <FaCircle /> : <FaCircleThin />}
<span className={styles.label}>Import existing wallet</span>
<span className={styles.label}>
<FormattedMessage {...messages.signup_import} />
</span>
</div>
</section>
</div>

7
app/components/Onboarding/Signup/messages.js

@ -0,0 +1,7 @@
import { defineMessages } from 'react-intl'
/* eslint-disable max-len */
export default defineMessages({
signup_create: 'Create new wallet',
signup_import: 'Import existing wallet'
})

52
app/components/Onboarding/Syncing/Syncing.js

@ -6,6 +6,8 @@ import Isvg from 'react-inlinesvg'
import zapLogo from 'icons/zap_logo.svg'
import copyIcon from 'icons/copy.svg'
import { showNotification } from 'lib/utils/notifications'
import { FormattedMessage, injectIntl } from 'react-intl'
import messages from './messages'
import styles from './Syncing.scss'
class Syncing extends Component {
@ -16,14 +18,13 @@ class Syncing extends Component {
}
componentWillMount() {
const { syncStatus } = this.props
const { syncStatus, intl } = this.props
// If we are still waiting for peers after some time, advise te user it could take a wile.
let timer = setTimeout(() => {
if (syncStatus === 'waiting') {
this.setState({
syncMessageDetail:
'It looks like this could take some time - you might want to grab a coffee or try again later!'
syncMessageDetail: intl.formatMessage({ ...messages.grab_coffee })
})
}
}, 10000)
@ -44,7 +45,8 @@ class Syncing extends Component {
address,
blockHeight,
lndBlockHeight,
lndCfilterHeight
lndCfilterHeight,
intl
} = this.props
let { syncMessageDetail, syncMessageExtraDetail } = this.state
@ -54,17 +56,27 @@ class Syncing extends Component {
}
let syncMessage
if (syncStatus === 'waiting') {
syncMessage = 'Waiting for peers...'
syncMessage = intl.formatMessage({ ...messages.waiting_for_peers })
} else if (syncStatus === 'in-progress') {
if (typeof syncPercentage === 'undefined' || syncPercentage <= 0) {
syncMessage = 'Preparing...'
syncMessage = intl.formatMessage({ ...messages.preparing })
syncMessageDetail = null
} else if (syncPercentage) {
syncMessage = `${syncPercentage}%`
syncMessageDetail = `Block:
${lndBlockHeight.toLocaleString()} of ${blockHeight.toLocaleString()}`
syncMessageExtraDetail = `Commitment Filter:
${lndCfilterHeight.toLocaleString()} of ${blockHeight.toLocaleString()}`
syncMessageDetail = intl.formatMessage(
{ ...messages.block_progress },
{
currentBlock: lndBlockHeight.toLocaleString(),
totalBlocks: blockHeight.toLocaleString()
}
)
syncMessageExtraDetail = intl.formatMessage(
{ ...messages.filter_progress },
{
currentFilter: lndCfilterHeight.toLocaleString(),
totalFilters: blockHeight.toLocaleString()
}
)
}
}
@ -84,9 +96,11 @@ class Syncing extends Component {
{hasSynced === true && (
<div>
<div className={styles.title}>
<h1>Welcome back to your Zap wallet!</h1>
<h1>
<FormattedMessage {...messages.sync_title} />
</h1>
<p>
Please wait a while whilst we fetch all of your latest data from the blockchain.
<FormattedMessage {...messages.sync_description} />
</p>
</div>
<div className={styles.loading}>
@ -98,8 +112,12 @@ class Syncing extends Component {
{hasSynced === false && (
<div>
<div className={styles.title}>
<h1>Fund your Zap wallet</h1>
<p>Might as well fund your wallet while you&apos;re waiting to sync.</p>
<h1>
<FormattedMessage {...messages.fund_title} />
</h1>
<p>
<FormattedMessage {...messages.fund_description} />
</p>
</div>
{address && address.length ? (
<div className={styles.address}>
@ -130,7 +148,9 @@ class Syncing extends Component {
)}
<section className={styles.progressContainer}>
<h3>Syncing to the blockchain</h3>
<h3>
<FormattedMessage {...messages.sync_caption} />
</h3>
<div className={styles.progressBar}>
<div
className={styles.progress}
@ -164,4 +184,4 @@ Syncing.propTypes = {
lndCfilterHeight: PropTypes.number
}
export default Syncing
export default injectIntl(Syncing)

17
app/components/Onboarding/Syncing/messages.js

@ -0,0 +1,17 @@
import { defineMessages } from 'react-intl'
/* eslint-disable max-len */
export default defineMessages({
grab_coffee:
'It looks like this could take some time - you might want to grab a coffee or try again later!',
waiting_for_peers: 'Waiting for peers…',
preparing: 'Preparing…',
sync_title: 'Welcome back to your Zap wallet!',
sync_description:
'Please wait a while whilst we fetch all of your latest data from the blockchain.',
fund_title: 'Fund your Zap wallet',
fund_description: 'Might as well fund your wallet while you’re waiting to sync.',
sync_caption: 'Syncing to the blockchain',
block_progress: 'Block {currentBlock} of {totalBlocks}',
filter_progress: 'Commitment Filter {currentFilter} of {totalFilters}'
})

35
app/components/Onboarding/messages.js

@ -0,0 +1,35 @@
import { defineMessages } from 'react-intl'
/* eslint-disable max-len */
export default defineMessages({
connection_title: 'How do you want to connect to the Lightning Network?',
connection_description:
'By default Zap will spin up a node for you and handle all the nerdy stuff in the background. However you can also setup a custom node connection and use Zap to control a remote node if you desire (for advanced users).',
connection_details_custom_title: 'Connection details',
connection_details_custom_description: 'Enter the connection details for your Lightning node.',
btcpay_title: 'BTCPay Server',
btcpay_description: 'Enter the connection details for your BTCPay Server node.',
confirm_connection_title: 'Confirm connection',
confirm_connection_description: 'Confirm the connection details for your Lightning node.',
alias_title: 'What should we call you?',
alias_description: 'Set your nickname to help others connect with you on the Lightning Network',
autopilot_title: 'Autopilot',
autopilot_description:
'Autopilot is an automatic network manager. Instead of manually adding people to build your network to make payments, enable autopilot to automatically connect you to the Lightning Network using 60% of your balance.',
create_wallet_password_title: 'Welcome!',
create_wallet_password_description:
'Looks like you are new here. Set a password to encrypt your wallet. This password will be needed to unlock Zap in the future',
signup_title: "Alright, let's get set up",
signup_description: 'Would you like to create a new wallet or import an existing one?',
login_title: 'Welcome back!',
login_description:
'It looks like you already have a wallet (wallet found at: `{walletDir}`). Please enter your wallet password to unlock it.',
import_title: 'Import your seed',
import_description: "Recovering a wallet, nice. You don't need anyone else, you got yourself :)",
save_seed_title: 'Save your wallet seed',
save_seed_description:
'Please save these 24 words securely! This will allow you to recover your wallet in the future',
retype_seed_title: 'Retype your seed',
retype_seed_description:
"Your seed is important! If you lose your seed you'll have no way to recover your wallet. To make sure that you have properly saved your seed, please retype words {word1}, {word2} & {word3}"
})

6
app/components/Settings/Fiat/Fiat.js

@ -3,13 +3,17 @@ import PropTypes from 'prop-types'
import FaAngleLeft from 'react-icons/lib/fa/angle-left'
import Isvg from 'react-inlinesvg'
import checkIcon from 'icons/check.svg'
import { FormattedMessage } from 'react-intl'
import messages from './messages'
import styles from './Fiat.scss'
const Fiat = ({ fiatTicker, fiatTickers, disableSubMenu, setFiatTicker }) => (
<div>
<header className={styles.submenuHeader} onClick={disableSubMenu}>
<FaAngleLeft />
<span>Fiat currency</span>
<FormattedMessage {...messages.title} />
</header>
<ul className={styles.fiatTickers}>
{fiatTickers.map(ft => (

6
app/components/Settings/Fiat/messages.js

@ -0,0 +1,6 @@
import { defineMessages } from 'react-intl'
/* eslint-disable max-len */
export default defineMessages({
title: 'Fiat Currency'
})

49
app/components/Settings/Locale/Locale.js

@ -0,0 +1,49 @@
import React from 'react'
import PropTypes from 'prop-types'
import FaAngleLeft from 'react-icons/lib/fa/angle-left'
import { getLanguageName } from 'lib/utils/i18n'
import Isvg from 'react-inlinesvg'
import checkIcon from 'icons/check.svg'
import { FormattedMessage } from 'react-intl'
import messages from './messages'
import styles from './Locale.scss'
const Translate = ({ locales, disableSubMenu, currentLocale, setLocale }) => {
const changeLocale = lng => {
setLocale(lng)
}
return (
<div>
<header className={styles.submenuHeader} onClick={disableSubMenu}>
<FaAngleLeft />
<FormattedMessage {...messages.title} />
</header>
<ul className={styles.locales}>
{Object.keys(locales).map(lang => {
return (
<li
key={lang}
className={currentLocale === lang ? styles.active : ''}
onClick={() => changeLocale(lang)}
>
<span>{getLanguageName(lang)}</span>
{currentLocale === lang && <Isvg src={checkIcon} />}
</li>
)
})}
</ul>
</div>
)
}
Translate.propTypes = {
locales: PropTypes.object.isRequired,
currentLocale: PropTypes.string.isRequired,
setLocale: PropTypes.func.isRequired,
disableSubMenu: PropTypes.func.isRequired
}
export default Translate

42
app/components/Settings/Locale/Locale.scss

@ -0,0 +1,42 @@
@import '../../../styles/variables.scss';
.submenuHeader {
padding: 20px;
background: lighten(#1d1f27, 20%);
font-size: 10px;
display: flex;
flex-direction: row;
justify-content: end;
align-items: center;
transition: all 0.25s;
&:hover {
background: lighten(#1d1f27, 10%);
}
}
.locales {
height: 300px;
overflow-y: scroll;
li {
background: #191919;
cursor: pointer;
border-bottom: 1px solid #0f0f0f;
transition: 0.25s hover;
&.active {
background: #0f0f0f;
svg {
height: 10px;
width: 10px;
color: $green;
}
}
span:nth-child(1) {
line-height: 12px;
}
}
}

3
app/components/Settings/Locale/index.js

@ -0,0 +1,3 @@
import Locale from './Locale'
export default Locale

6
app/components/Settings/Locale/messages.js

@ -0,0 +1,6 @@
import { defineMessages } from 'react-intl'
/* eslint-disable max-len */
export default defineMessages({
title: 'Language'
})

10
app/components/Settings/Menu/Menu.js

@ -1,12 +1,20 @@
import React from 'react'
import PropTypes from 'prop-types'
import FaAngleRight from 'react-icons/lib/fa/angle-right'
import { FormattedMessage } from 'react-intl'
import messages from './messages'
import styles from './Menu.scss'
const Menu = ({ setActiveSubMenu }) => (
<ul>
<li className={styles.fiat} onClick={() => setActiveSubMenu('fiat')}>
<span>Fiat Currency</span>
<FormattedMessage {...messages.fiat} />
<FaAngleRight />
</li>
<li className={styles.locale} onClick={() => setActiveSubMenu('locale')}>
<FormattedMessage {...messages.locale} />
<FaAngleRight />
</li>
</ul>

7
app/components/Settings/Menu/messages.js

@ -0,0 +1,7 @@
import { defineMessages } from 'react-intl'
/* eslint-disable max-len */
export default defineMessages({
fiat: 'Fiat Currency',
locale: 'Language'
})

8
app/components/Settings/Settings.js

@ -2,6 +2,7 @@ import React from 'react'
import PropTypes from 'prop-types'
import Menu from './Menu'
import Fiat from './Fiat'
import Locale from './Locale'
import styles from './Settings.scss'
class Settings extends React.Component {
@ -47,11 +48,13 @@ class Settings extends React.Component {
}
renderSettings() {
const { settings, fiatProps, setActiveSubMenu } = this.props
const { settings, fiatProps, localeProps, setActiveSubMenu } = this.props
switch (settings.activeSubMenu) {
case 'fiat':
return <Fiat {...fiatProps} />
case 'locale':
return <Locale {...localeProps} />
default:
return <Menu setActiveSubMenu={setActiveSubMenu} />
}
@ -70,7 +73,8 @@ Settings.propTypes = {
settings: PropTypes.object.isRequired,
setActiveSubMenu: PropTypes.func.isRequired,
toggleSettings: PropTypes.func.isRequired,
fiatProps: PropTypes.object.isRequired
fiatProps: PropTypes.object.isRequired,
localeProps: PropTypes.object.isRequired
}
export default Settings

23
app/components/Wallet/ReceiveModal/ReceiveModal.js

@ -8,6 +8,9 @@ import Isvg from 'react-inlinesvg'
import x from 'icons/x.svg'
import { showNotification } from 'lib/utils/notifications'
import { FormattedMessage, injectIntl } from 'react-intl'
import messages from './messages'
import styles from './ReceiveModal.scss'
class ReceiveModal extends React.Component {
@ -34,7 +37,7 @@ class ReceiveModal extends React.Component {
}
}
const { isOpen, pubkey, address, alias, closeReceiveModal, network } = this.props
const { isOpen, pubkey, address, alias, closeReceiveModal, network, intl } = this.props
const { qrCodeType } = this.state
@ -60,13 +63,13 @@ class ReceiveModal extends React.Component {
className={qrCodeType === 1 ? styles.active : undefined}
onClick={changeQrCode}
>
Node Pubkey
<FormattedMessage {...messages.node_pubkey} />
</div>
<div
className={qrCodeType === 2 ? styles.active : undefined}
onClick={changeQrCode}
>
Bitcoin Address
<FormattedMessage {...messages.bitcoin_address} />
</div>
</div>
</header>
@ -85,13 +88,15 @@ class ReceiveModal extends React.Component {
</section>
<section className={styles.right}>
<div className={styles.pubkey}>
<h4>Node Public Key</h4>
<h4>
<FormattedMessage {...messages.node_public_key} />
</h4>
<p>
<span className={styles.data}>{pubkey}</span>
<span
onClick={() => copyOnClick(pubkey)}
className={`${styles.copy} hint--left`}
data-hint="Copy pubkey"
data-hint={intl.formatMessage({ ...messages.copy_pubkey })}
>
<Isvg src={copyIcon} />
</span>
@ -99,13 +104,15 @@ class ReceiveModal extends React.Component {
</div>
<div className={styles.address}>
<h4>Bitcoin {network.name} Address</h4>
<h4>
<FormattedMessage {...messages.bitcoin_address} /> ({network.name})
</h4>
<p>
<span className={styles.data}>{address}</span>
<span
onClick={() => copyOnClick(address)}
className={`${styles.copy} hint--left`}
data-hint="Copy address"
data-hint={intl.formatMessage({ ...messages.copy_address })}
>
<Isvg src={copyIcon} />
</span>
@ -129,4 +136,4 @@ ReceiveModal.propTypes = {
closeReceiveModal: PropTypes.func.isRequired
}
export default ReceiveModal
export default injectIntl(ReceiveModal)

9
app/components/Wallet/ReceiveModal/messages.js

@ -0,0 +1,9 @@
import { defineMessages } from 'react-intl'
export default defineMessages({
node_public_key: 'Node Public Key',
node_pubkey: 'Node Pubkey',
bitcoin_address: 'Bitcoin Address',
copy_address: 'Copy address',
copy_pubkey: 'Copy Pubkey'
})

35
app/components/Wallet/Wallet.js

@ -12,6 +12,9 @@ import Settings from 'components/Settings'
import zapLogo from 'icons/zap_logo.svg'
import qrCode from 'icons/qrcode.svg'
import { FormattedNumber, FormattedMessage } from 'react-intl'
import messages from './messages'
import styles from './Wallet.scss'
const Wallet = ({
@ -95,20 +98,26 @@ const Wallet = ({
</section>
</span>
</h1>
<span className={styles.usdValue}>
{currentTicker[ticker.fiatTicker].symbol}
{fiatAmount ? fiatAmount.toLocaleString() : ''}
</span>
{Boolean(fiatAmount) && (
<span>
{'≈ '}
<FormattedNumber
currency={ticker.fiatTicker}
style="currency"
value={fiatAmount}
/>
</span>
)}
</div>
</div>
</div>
<div className={styles.right}>
<div className={styles.rightContent}>
<div className={styles.pay} onClick={openPayForm}>
Pay
<FormattedMessage {...messages.pay} />
</div>
<div className={styles.request} onClick={openRequestForm}>
Request
<FormattedMessage {...messages.request} />
</div>
</div>
<div className={styles.notificationBox}>
@ -118,7 +127,9 @@ const Wallet = ({
<section className={`${styles.spinner} ${styles.icon}`} />
<span className={styles.timeout}>{paymentTimeout / 1000}</span>
</div>
<section>Sending your transaction</section>
<section>
<FormattedMessage {...messages.sending_tx} />
</section>
</span>
)}
{showSuccessPayScreen && (
@ -126,7 +137,9 @@ const Wallet = ({
<section className={styles.icon}>
<AnimatedCheckmark />
</section>
<section>Successfully sent payment</section>
<section>
<FormattedMessage {...messages.payment_success} />
</section>
</span>
)}
{successTransactionScreen.show && (
@ -135,16 +148,14 @@ const Wallet = ({
<AnimatedCheckmark />
</section>
<section>
Successfully{' '}
<span
className={styles.txLink}
onClick={() => {
return blockExplorer.showTransaction(network, successTransactionScreen.txid)
}}
>
sent
</span>{' '}
transaction
<FormattedMessage {...messages.transaction_success} />
</span>
</section>
</span>
)}

10
app/components/Wallet/messages.js

@ -0,0 +1,10 @@
import { defineMessages } from 'react-intl'
/* eslint-disable max-len */
export default defineMessages({
pay: 'Pay',
request: 'Request',
sending_tx: 'Sending your transaction…',
payment_success: 'Successfully sent payment',
transaction_success: 'Successfully sent transaction'
})

11
app/containers/Activity.js

@ -1,4 +1,5 @@
import { connect } from 'react-redux'
import { setLocale } from 'reducers/locale'
import { setCurrency, setFiatTicker, tickerSelectors } from 'reducers/ticker'
import { fetchBalance } from 'reducers/balance'
import { fetchInvoices, setInvoice, invoiceSelectors } from 'reducers/invoice'
@ -26,6 +27,7 @@ import { setSettingsOpen, setActiveSubMenu, disableSubMenu } from 'reducers/sett
import Activity from 'components/Activity'
const mapDispatchToProps = {
setLocale,
setCurrency,
setFiatTicker,
setPayment,
@ -69,6 +71,9 @@ const mapStateToProps = state => ({
settings: state.settings,
currentLocale: state.intl.locale,
locales: state.locale,
paymentModalOpen: paymentSelectors.paymentModalOpen(state),
invoiceModalOpen: invoiceSelectors.invoiceModalOpen(state),
@ -129,6 +134,12 @@ const mergeProps = (stateProps, dispatchProps, ownProps) => ({
fiatTickers: stateProps.ticker.fiatTickers,
disableSubMenu: dispatchProps.disableSubMenu,
setFiatTicker: dispatchProps.setFiatTicker
},
localeProps: {
locales: stateProps.locales,
currentLocale: stateProps.currentLocale,
disableSubMenu: dispatchProps.disableSubMenu,
setLocale: dispatchProps.setLocale
}
}
}

14
app/containers/App.js

@ -45,7 +45,6 @@ import {
toggleFilterPulldown,
changeFilter,
updateChannelSearchQuery,
closeContactModal,
setSelectedChannel
} from 'reducers/channels'
@ -115,7 +114,6 @@ const mapDispatchToProps = {
toggleFilterPulldown,
changeFilter,
updateChannelSearchQuery,
closeContactModal,
setSelectedChannel,
openContactsForm,
@ -361,16 +359,6 @@ const mergeProps = (stateProps, dispatchProps, ownProps) => {
pendingOpenChannelPubkeys: stateProps.pendingOpenChannelPubkeys
}
const contactModalProps = {
closeContactModal: dispatchProps.closeContactModal,
closeChannel: dispatchProps.closeChannel,
isOpen: stateProps.channels.contactModal.isOpen,
channel: stateProps.channels.contactModal.channel,
channelNodes: stateProps.channelNodes,
closingChannelIds: stateProps.channels.closingChannelIds
}
const activityModalProps = {
itemType: stateProps.activity.modal.itemType,
itemId: stateProps.activity.modal.itemId,
@ -478,8 +466,6 @@ const mergeProps = (stateProps, dispatchProps, ownProps) => {
networkTabProps,
// props for the contacts form
contactsFormProps,
// props for the contact modal
contactModalProps,
// props for the receive modal
receiveModalProps,
// props for the activity modals

28
app/containers/Root.js

@ -1,5 +1,5 @@
import React from 'react'
import { Provider, connect } from 'react-redux'
import { connect } from 'react-redux'
import { ConnectedRouter } from 'react-router-redux'
import { Switch, Route } from 'react-router'
import PropTypes from 'prop-types'
@ -205,14 +205,7 @@ const mergeProps = (stateProps, dispatchProps, ownProps) => {
}
}
const Root = ({
store,
history,
lnd,
onboardingProps,
syncingProps
}) => {
const Root = ({ history, lnd, onboardingProps, syncingProps }) => {
// If we are onboarding show the onboarding screen.
if (onboardingProps.onboarding.onboarding) {
return <Onboarding {...onboardingProps} />
@ -234,20 +227,17 @@ const Root = ({
}
return (
<Provider store={store}>
<ConnectedRouter history={history}>
<App>
<Switch>
<Route path="/" component={Activity} />
</Switch>
</App>
</ConnectedRouter>
</Provider>
<ConnectedRouter history={history}>
<App>
<Switch>
<Route path="/" component={Activity} />
</Switch>
</App>
</ConnectedRouter>
)
}
Root.propTypes = {
store: PropTypes.object.isRequired,
history: PropTypes.object.isRequired,
lnd: PropTypes.object.isRequired,
onboardingProps: PropTypes.object.isRequired,

38
app/index.js

@ -1,21 +1,33 @@
import React from 'react'
import { render } from 'react-dom'
import { AppContainer } from 'react-hot-loader'
import ReactDOM from 'react-dom'
import { Provider } from 'react-intl-redux'
import jstz from 'jstimezonedetect'
import Root from './containers/Root'
import { configureStore, history } from './store/configureStore'
import './styles/app.global.scss'
const store = configureStore()
import { translationMessages, getLocale } from './lib/utils/i18n'
const locale = getLocale()
const initialState = {
intl: {
locale,
messages: translationMessages[locale],
timeZone: jstz.determine().name()
}
}
render(
<AppContainer>
<Root store={store} history={history} />
</AppContainer>,
document.getElementById('root')
)
const store = configureStore(initialState)
const MOUNT_NODE = document.getElementById('root')
if (module.hot) {
module.hot.accept('./containers/Root', () => {
render(<Root store={store} history={history} />, document.getElementById('root'))
})
const render = () => {
ReactDOM.render(
<Provider store={store}>
<Root history={history} />
</Provider>,
MOUNT_NODE
)
}
render()

211
app/lib/utils/i18n.js

@ -0,0 +1,211 @@
import { app, remote } from 'electron'
import { addLocaleData } from 'react-intl'
import Store from 'electron-store'
import get from 'lodash.get'
import { lookup } from 'country-data-lookup'
import createDebug from 'debug'
// Load locale data.
import bg from 'react-intl/locale-data/bg'
import cs from 'react-intl/locale-data/cs'
import de from 'react-intl/locale-data/de'
import el from 'react-intl/locale-data/el'
import en from 'react-intl/locale-data/en'
import es from 'react-intl/locale-data/es'
import fr from 'react-intl/locale-data/fr'
import ga from 'react-intl/locale-data/ga'
import hr from 'react-intl/locale-data/hr'
import ja from 'react-intl/locale-data/ja'
import nl from 'react-intl/locale-data/nl'
import pt from 'react-intl/locale-data/pt'
import ro from 'react-intl/locale-data/ro'
import ru from 'react-intl/locale-data/ru'
import sv from 'react-intl/locale-data/sv'
import tr from 'react-intl/locale-data/tr'
import uk from 'react-intl/locale-data/uk'
import zh from 'react-intl/locale-data/zh'
// Load translation data.
import bgTranslationMessages from '../../translations/bg-BG.json'
import csTranslationMessages from '../../translations/cs-CZ.json'
import deTranslationMessages from '../../translations/de-DE.json'
import elTranslationMessages from '../../translations/el-GR.json'
import enTranslationMessages from '../../translations/en.json'
import esTranslationMessages from '../../translations/es-ES.json'
import frTranslationMessages from '../../translations/fr-FR.json'
import gaTranslationMessages from '../../translations/ga-IE.json'
import hrTranslationMessages from '../../translations/hr-HR.json'
import jaTranslationMessages from '../../translations/ja-JP.json'
import nlTranslationMessages from '../../translations/nl-NL.json'
import ptTranslationMessages from '../../translations/pt-BR.json'
import roTranslationMessages from '../../translations/ro-RO.json'
import ruTranslationMessages from '../../translations/ru-RU.json'
import svTranslationMessages from '../../translations/sv-SE.json'
import trTranslationMessages from '../../translations/tr-TR.json'
import ukTranslationMessages from '../../translations/uk-UA.json'
import zhCNTranslationMessages from '../../translations/zh-CN.json'
import zhTWTranslationMessages from '../../translations/zh-TW.json'
const debug = createDebug('zap:i18n')
// Add locale data.
addLocaleData([
...bg,
...cs,
...de,
...el,
...en,
...es,
...fr,
...ga,
...hr,
...ja,
...nl,
...pt,
...ro,
...ru,
...sv,
...tr,
...uk,
...zh
])
// Defaine list of language that we will support.
export const locales = [
'bg',
'cs',
'de',
'el',
'en',
'es',
'fr',
'ga',
'hr',
'ja',
'nl',
'pt',
'ro',
'ru',
'sv',
'tr',
'uk',
'zh-CN',
'zh-TW'
]
// Defaine list of currencies that we will support.
export const currencies = [
'USD',
'EUR',
'JPY',
'GBP',
'CAD',
'KRW',
'AUD',
'BRL',
'CHF',
'CLP',
'CNY',
'DKK',
'HKD',
'INR',
'ISK',
'NZD',
'PLN',
'RUB',
'SEK',
'SGD',
'THB',
'TWB'
]
// Collate all translations.
export const translationMessages = {
en: enTranslationMessages,
bg: bgTranslationMessages,
'zh-CN': zhCNTranslationMessages,
'zh-TW': zhTWTranslationMessages,
hr: hrTranslationMessages,
cs: csTranslationMessages,
nl: nlTranslationMessages,
fr: frTranslationMessages,
ga: gaTranslationMessages,
de: deTranslationMessages,
el: elTranslationMessages,
ja: jaTranslationMessages,
pt: ptTranslationMessages,
ro: roTranslationMessages,
ru: ruTranslationMessages,
es: esTranslationMessages,
sv: svTranslationMessages,
tr: trTranslationMessages,
uk: ukTranslationMessages
}
/**
* Get the most appropriate language code.
* @return {string} Language code.
*/
export const getLocale = () => {
const store = new Store({ name: 'settings' })
const userLocale = store.get('locale')
if (userLocale) {
debug('Determined locale as %s from settings', userLocale)
return userLocale
}
const defaultLocale = (app || remote.app).getLocale() || 'en-US'
const language = defaultLocale.toLowerCase().split(/[_-]+/)[0]
let locale = 'en'
if (locales.includes(language)) {
locale = language
}
if (locales.includes(defaultLocale)) {
locale = userLocale
}
debug('Determined locale as %s', locale)
return locale
}
/**
* Get the most appropriate language code.
* @return {string} Language code.
*/
export const getLanguageName = lang => {
const customNames = {
el: 'Greek',
'zh-CN': 'Chinese (Simplified, PRC)',
'zh-TW': 'Chinese (Traditional, Taiwan)'
}
if (customNames[lang]) {
return customNames[lang]
}
const language = lang.toLowerCase().split(/[_-]+/)[0]
const data = lookup.languages({ alpha2: language })
const name = get(data, '[0]name', language)
debug('Determined language as %s', name)
return name
}
/**
* Get the most appropriate currency code.
* @return {string} Currency code.
*/
export const getCurrency = () => {
const store = new Store({ name: 'settings' })
const userCurrency = store.get('fiatTicker')
if (userCurrency) {
debug('Determined currency as %s from settings', userCurrency)
return userCurrency
}
const defaultLocale = (app || remote.app).getLocale() || 'en-US'
const country = defaultLocale.split(/[_-]+/)[1]
const data = lookup.countries({ alpha2: country })
const detectedCurrency = get(data, '[0]currencies[0]', 'USD')
let currency = 'USD'
if (currencies.includes(detectedCurrency)) {
currency = detectedCurrency
}
debug('Determined currency as %s', currency)
return currency
}

39
app/lib/zap/menuBuilder.js

@ -1,16 +1,23 @@
// @flow
import { app, Menu, shell, BrowserWindow } from 'electron'
import { app, Menu, shell, BrowserWindow, ipcMain } from 'electron'
import { locales, getLocale, getLanguageName } from '../utils/i18n'
export default class ZapMenuBuilder {
mainWindow: BrowserWindow
locale: string
constructor(mainWindow: BrowserWindow) {
this.mainWindow = mainWindow
this.locale = getLocale()
ipcMain.on('setLocale', (event, locale) => this.buildMenu(locale))
}
buildMenu() {
let template
buildMenu(locale?: string) {
if (locale) {
this.locale = locale
}
let template
if (process.platform === 'darwin') {
template = this.buildDarwinTemplate()
} else {
@ -168,7 +175,14 @@ export default class ZapMenuBuilder {
const subMenuView = process.env.NODE_ENV === 'development' ? subMenuViewDev : subMenuViewProd
return [subMenuAbout, subMenuEdit, subMenuView, subMenuWindow, subMenuHelp]
return [
subMenuAbout,
subMenuEdit,
subMenuView,
subMenuWindow,
subMenuHelp,
this.buildLanguageMenu()
]
}
buildDefaultTemplate() {
@ -254,9 +268,24 @@ export default class ZapMenuBuilder {
}
}
]
}
},
this.buildLanguageMenu()
]
return templateDefault
}
buildLanguageMenu() {
return {
label: 'Language',
submenu: locales.map(locale => {
return {
label: getLanguageName(locale),
type: 'radio',
checked: this.locale === locale,
click: () => this.mainWindow.webContents.send('receiveLocale', locale)
}
})
}
}
}

8
app/reducers/activity.js

@ -7,10 +7,10 @@ const initialState = {
filterPulldown: false,
filter: { key: 'ALL_ACTIVITY', name: 'All Activity' },
filters: [
{ key: 'ALL_ACTIVITY', name: 'All' },
{ key: 'SENT_ACTIVITY', name: 'Sent' },
{ key: 'REQUESTED_ACTIVITY', name: 'Requested' },
{ key: 'PENDING_ACTIVITY', name: 'Pending' }
{ key: 'ALL_ACTIVITY', name: 'all' },
{ key: 'SENT_ACTIVITY', name: 'sent' },
{ key: 'REQUESTED_ACTIVITY', name: 'requested' },
{ key: 'PENDING_ACTIVITY', name: 'pending' }
],
modal: {
itemType: null,

28
app/reducers/channels.js

@ -37,9 +37,6 @@ export const REMOVE_LOADING_PUBKEY = 'REMOVE_LOADING_PUBKEY'
export const ADD_ClOSING_CHAN_ID = 'ADD_ClOSING_CHAN_ID'
export const REMOVE_ClOSING_CHAN_ID = 'REMOVE_ClOSING_CHAN_ID'
export const OPEN_CONTACT_MODAL = 'OPEN_CONTACT_MODAL'
export const CLOSE_CONTACT_MODAL = 'CLOSE_CONTACT_MODAL'
export const SET_SELECTED_CHANNEL = 'SET_SELECTED_CHANNEL'
export const GET_SUGGESTED_NODES = 'GET_SUGGESTED_NODES'
@ -134,19 +131,6 @@ export function removeClosingChanId(chanId) {
}
}
export function openContactModal(channel) {
return {
type: OPEN_CONTACT_MODAL,
channel
}
}
export function closeContactModal() {
return {
type: CLOSE_CONTACT_MODAL
}
}
export function setSelectedChannel(selectedChannel) {
return {
type: SET_SELECTED_CHANNEL,
@ -263,7 +247,6 @@ export const closeChannelSuccessful = () => dispatch => {
export const pushclosechannelupdated = (event, { chan_id }) => dispatch => {
dispatch(fetchChannels())
dispatch(removeClosingChanId(chan_id))
dispatch(closeContactModal())
}
// Receive IPC event for closing channel end
@ -393,12 +376,6 @@ const ACTION_HANDLERS = {
closingChannelIds: state.closingChannelIds.filter(closingChanId => closingChanId !== chanId)
}),
[OPEN_CONTACT_MODAL]: (state, { channel }) => ({
...state,
contactModal: { isOpen: true, channel }
}),
[CLOSE_CONTACT_MODAL]: state => ({ ...state, contactModal: { isOpen: false, channel: null } }),
[SET_SELECTED_CHANNEL]: (state, { selectedChannel }) => ({ ...state, selectedChannel }),
[GET_SUGGESTED_NODES]: state => ({ ...state, suggestedNodesLoading: true }),
@ -629,11 +606,6 @@ const initialState = {
loadingChannelPubkeys: [],
closingChannelIds: [],
contactModal: {
isOpen: false,
channel: null
},
selectedChannel: null,
// nodes stored at zap.jackmallers.com/suggested-peers manages by JimmyMow

4
app/reducers/index.js

@ -1,5 +1,7 @@
import { combineReducers } from 'redux'
import { routerReducer as router } from 'react-router-redux'
import { intlReducer as intl } from 'react-intl-redux'
import locale from './locale'
import onboarding from './onboarding'
import lnd from './lnd'
import ticker from './ticker'
@ -25,6 +27,8 @@ import settings from './settings'
const rootReducer = combineReducers({
router,
intl,
locale,
onboarding,
lnd,
ticker,

2
app/reducers/ipc.js

@ -1,4 +1,5 @@
import createIpc from 'redux-electron-ipc'
import { receiveLocale } from './locale'
import {
lndSyncStatus,
currentBlockHeight,
@ -58,6 +59,7 @@ import {
// Import all receiving IPC event handlers and pass them into createIpc
const ipc = createIpc({
receiveLocale,
lndSyncStatus,
currentBlockHeight,
lndBlockHeight,

40
app/reducers/locale.js

@ -0,0 +1,40 @@
import Store from 'electron-store'
import { updateIntl } from 'react-intl-redux'
import { ipcRenderer } from 'electron'
import { translationMessages } from 'lib/utils/i18n'
// Settings store
const store = new Store({ name: 'settings' })
// ------------------------------------
// Actions
// ------------------------------------
export const setLocale = locale => (dispatch, getState) => {
const state = getState()
// Switch the active locale.
dispatch(
updateIntl({
locale,
messages: state.locale[locale]
})
)
// Save the new locale sa our language preference.
store.set('locale', locale)
// Let the main process know the locale has changed.
ipcRenderer.send('setLocale', locale)
}
export const receiveLocale = (event, locale) => dispatch => {
dispatch(setLocale(locale))
}
// ------------------------------------
// Reducer
// ------------------------------------
export default function localeReducer(state = translationMessages) {
return state
}

28
app/reducers/ticker.js

@ -1,6 +1,7 @@
import { createSelector } from 'reselect'
import Store from 'electron-store'
import { requestTicker } from 'lib/utils/api'
import { currencies, getCurrency } from 'lib/utils/i18n'
import { infoSelectors } from './info'
// Settings store
@ -141,31 +142,8 @@ const initialState = {
crypto: '',
btcTicker: null,
ltcTicker: null,
fiatTicker: store.get('fiatTicker', 'USD'),
fiatTickers: [
'USD',
'EUR',
'JPY',
'GBP',
'CAD',
'KRW',
'AUD',
'BRL',
'CHF',
'CLP',
'CNY',
'DKK',
'HKD',
'INR',
'ISK',
'NZD',
'PLN',
'RUB',
'SEK',
'SGD',
'THB',
'TWB'
],
fiatTicker: getCurrency(),
fiatTickers: currencies,
currencyFilters: [
{
key: 'btc',

157
app/translations/af-ZA.json

@ -0,0 +1,157 @@
{
"components.Activity.Countdown.expires": "",
"components.Activity.Invoice.amount": "",
"components.Activity.Invoice.received": "",
"components.Activity.Invoice.requested": "",
"components.Activity.Invoice.type_paid": "",
"components.Activity.Invoice.type_unpaid": "",
"components.Activity.InvoiceModal.copy": "",
"components.Activity.InvoiceModal.memo": "",
"components.Activity.InvoiceModal.not_paid": "",
"components.Activity.InvoiceModal.paid": "",
"components.Activity.InvoiceModal.pay_req": "",
"components.Activity.InvoiceModal.request": "",
"components.Activity.InvoiceModal.save": "",
"components.Activity.Payment.amount": "",
"components.Activity.Payment.fee": "",
"components.Activity.Payment.type": "",
"components.Activity.PaymentModal.fee": "",
"components.Activity.PaymentModal.lightning": "",
"components.Activity.PaymentModal.sent": "",
"components.Activity.Transaction.amount": "",
"components.Activity.Transaction.fee": "",
"components.Activity.Transaction.received": "",
"components.Activity.Transaction.sent": "",
"components.Activity.Transaction.type": "",
"components.Activity.TransactionModal.fee": "",
"components.Activity.TransactionModal.on_chain": "",
"components.Activity.TransactionModal.received": "",
"components.Activity.TransactionModal.sent": "",
"components.Activity.all": "",
"components.Activity.hide_expired": "",
"components.Activity.pending": "",
"components.Activity.refresh": "",
"components.Activity.requested": "",
"components.Activity.search": "",
"components.Activity.sent": "",
"components.Activity.show_expired": "",
"components.Contacts.AddChannel.manual_button": "",
"components.Contacts.AddChannel.manual_description": "",
"components.Contacts.AddChannel.offline": "",
"components.Contacts.AddChannel.online": "",
"components.Contacts.AddChannel.pending": "",
"components.Contacts.AddChannel.private": "",
"components.Contacts.ConnectManually.description": "",
"components.Contacts.ConnectManually.placeholder": "",
"components.Contacts.ConnectManually.submit": "",
"components.Contacts.ConnectManually.title": "",
"components.Contacts.Network.closing": "",
"components.Contacts.Network.loading": "",
"components.Contacts.Network.offline": "",
"components.Contacts.Network.online": "",
"components.Contacts.Network.open_channel": "",
"components.Contacts.Network.pay_limit": "",
"components.Contacts.Network.pending": "",
"components.Contacts.Network.refresh": "",
"components.Contacts.Network.req_limit": "",
"components.Contacts.Network.search_placeholder": "",
"components.Contacts.Network.title": "",
"components.Contacts.SubmitChannelForm.description": "",
"components.Contacts.SubmitChannelForm.duplicate_warnig": "",
"components.Contacts.SubmitChannelForm.submit": "",
"components.Contacts.SubmitChannelForm.title": "",
"components.Contacts.SuggestedNodes.connect": "",
"components.Contacts.SuggestedNodes.empty_description": "",
"components.Form.Pay.amount": "",
"components.Form.Pay.destination": "",
"components.Form.Pay.onchain_description": "",
"components.Form.Pay.pay": "",
"components.Form.Pay.request_placeholder": "",
"components.Form.Pay.title": "",
"components.Form.Request.amount": "",
"components.Form.Request.details": "",
"components.Form.Request.memo": "",
"components.Form.Request.request": "",
"components.Form.Request.title": "",
"components.LoadingBolt.loading": "",
"components.Onboarding.Autopilot.disable": "",
"components.Onboarding.Autopilot.enable": "",
"components.Onboarding.BtcPayServer.btcpay_description": "",
"components.Onboarding.BtcPayServer.btcpay_error": "",
"components.Onboarding.BtcPayServer.connection_string_label": "",
"components.Onboarding.BtcPayServer.connection_string_placeholder": "",
"components.Onboarding.ConnectionConfirm.verify_host_description": "",
"components.Onboarding.ConnectionConfirm.verify_host_title": "",
"components.Onboarding.ConnectionDetails.cert_description": "",
"components.Onboarding.ConnectionDetails.cert_title": "",
"components.Onboarding.ConnectionDetails.hostname_description": "",
"components.Onboarding.ConnectionDetails.hostname_title": "",
"components.Onboarding.ConnectionDetails.macaroon_description": "",
"components.Onboarding.ConnectionType.btcpay_description": "",
"components.Onboarding.ConnectionType.custom": "",
"components.Onboarding.ConnectionType.custom_description": "",
"components.Onboarding.ConnectionType.default": "",
"components.Onboarding.ConnectionType.default_description": "",
"components.Onboarding.ConnectionType.only": "",
"components.Onboarding.FormContainer.back": "",
"components.Onboarding.FormContainer.help": "",
"components.Onboarding.FormContainer.next": "",
"components.Onboarding.Login.password_placeholder": "",
"components.Onboarding.Login.unlock": "",
"components.Onboarding.NewWalletPassword.password_confirm_placeholder": "",
"components.Onboarding.NewWalletPassword.password_error_length": "",
"components.Onboarding.NewWalletPassword.password_error_match": "",
"components.Onboarding.NewWalletPassword.password_placeholder": "",
"components.Onboarding.NewWalletPassword.unlock": "",
"components.Onboarding.RecoverForm.word_placeholder": "",
"components.Onboarding.Signup.signup_create": "",
"components.Onboarding.Signup.signup_import": "",
"components.Onboarding.Syncing.block_progress": "",
"components.Onboarding.Syncing.filter_progress": "",
"components.Onboarding.Syncing.fund_description": "",
"components.Onboarding.Syncing.fund_title": "",
"components.Onboarding.Syncing.grab_coffee": "",
"components.Onboarding.Syncing.preparing": "",
"components.Onboarding.Syncing.sync_caption": "",
"components.Onboarding.Syncing.sync_description": "",
"components.Onboarding.Syncing.sync_title": "",
"components.Onboarding.Syncing.waiting_for_peers": "",
"components.Onboarding.alias_description": "",
"components.Onboarding.alias_title": "",
"components.Onboarding.autopilot_description": "",
"components.Onboarding.autopilot_title": "",
"components.Onboarding.btcpay_description": "",
"components.Onboarding.btcpay_title": "",
"components.Onboarding.confirm_connection_description": "",
"components.Onboarding.confirm_connection_title": "",
"components.Onboarding.connection_description": "",
"components.Onboarding.connection_details_custom_description": "",
"components.Onboarding.connection_details_custom_title": "",
"components.Onboarding.connection_title": "",
"components.Onboarding.create_wallet_password_description": "",
"components.Onboarding.create_wallet_password_title": "",
"components.Onboarding.import_description": "",
"components.Onboarding.import_title": "",
"components.Onboarding.login_description": "",
"components.Onboarding.login_title": "",
"components.Onboarding.retype_seed_description": "",
"components.Onboarding.retype_seed_title": "",
"components.Onboarding.save_seed_description": "",
"components.Onboarding.save_seed_title": "",
"components.Onboarding.signup_description": "",
"components.Onboarding.signup_title": "",
"components.Settings.Fiat.title": "",
"components.Settings.Locale.title": "",
"components.Settings.Menu.fiat": "",
"components.Settings.Menu.locale": "",
"components.Wallet.ReceiveModal.bitcoin_address": "",
"components.Wallet.ReceiveModal.copy_address": "",
"components.Wallet.ReceiveModal.copy_pubkey": "",
"components.Wallet.ReceiveModal.node_pubkey": "",
"components.Wallet.ReceiveModal.node_public_key": "",
"components.Wallet.pay": "",
"components.Wallet.payment_success": "",
"components.Wallet.request": "",
"components.Wallet.sending_tx": "",
"components.Wallet.transaction_success": ""
}

157
app/translations/ar-SA.json

@ -0,0 +1,157 @@
{
"components.Activity.Countdown.expires": "",
"components.Activity.Invoice.amount": "",
"components.Activity.Invoice.received": "",
"components.Activity.Invoice.requested": "",
"components.Activity.Invoice.type_paid": "",
"components.Activity.Invoice.type_unpaid": "",
"components.Activity.InvoiceModal.copy": "",
"components.Activity.InvoiceModal.memo": "",
"components.Activity.InvoiceModal.not_paid": "",
"components.Activity.InvoiceModal.paid": "",
"components.Activity.InvoiceModal.pay_req": "",
"components.Activity.InvoiceModal.request": "",
"components.Activity.InvoiceModal.save": "",
"components.Activity.Payment.amount": "",
"components.Activity.Payment.fee": "",
"components.Activity.Payment.type": "",
"components.Activity.PaymentModal.fee": "",
"components.Activity.PaymentModal.lightning": "",
"components.Activity.PaymentModal.sent": "",
"components.Activity.Transaction.amount": "",
"components.Activity.Transaction.fee": "",
"components.Activity.Transaction.received": "",
"components.Activity.Transaction.sent": "",
"components.Activity.Transaction.type": "",
"components.Activity.TransactionModal.fee": "",
"components.Activity.TransactionModal.on_chain": "",
"components.Activity.TransactionModal.received": "",
"components.Activity.TransactionModal.sent": "",
"components.Activity.all": "",
"components.Activity.hide_expired": "",
"components.Activity.pending": "قيد الانتظار",
"components.Activity.refresh": "",
"components.Activity.requested": "",
"components.Activity.search": "",
"components.Activity.sent": "",
"components.Activity.show_expired": "",
"components.Contacts.AddChannel.manual_button": "",
"components.Contacts.AddChannel.manual_description": "",
"components.Contacts.AddChannel.offline": "غير متصل",
"components.Contacts.AddChannel.online": "متصل",
"components.Contacts.AddChannel.pending": "قيد الانتظار",
"components.Contacts.AddChannel.private": "",
"components.Contacts.ConnectManually.description": "",
"components.Contacts.ConnectManually.placeholder": "",
"components.Contacts.ConnectManually.submit": "",
"components.Contacts.ConnectManually.title": "",
"components.Contacts.Network.closing": "إغلاق",
"components.Contacts.Network.loading": "",
"components.Contacts.Network.offline": "غير متصل",
"components.Contacts.Network.online": "متصل",
"components.Contacts.Network.open_channel": "",
"components.Contacts.Network.pay_limit": "",
"components.Contacts.Network.pending": "قيد الانتظار",
"components.Contacts.Network.refresh": "",
"components.Contacts.Network.req_limit": "",
"components.Contacts.Network.search_placeholder": "",
"components.Contacts.Network.title": "",
"components.Contacts.SubmitChannelForm.description": "",
"components.Contacts.SubmitChannelForm.duplicate_warnig": "",
"components.Contacts.SubmitChannelForm.submit": "",
"components.Contacts.SubmitChannelForm.title": "",
"components.Contacts.SuggestedNodes.connect": "",
"components.Contacts.SuggestedNodes.empty_description": "",
"components.Form.Pay.amount": "المبلغ",
"components.Form.Pay.destination": "",
"components.Form.Pay.onchain_description": "",
"components.Form.Pay.pay": "",
"components.Form.Pay.request_placeholder": "",
"components.Form.Pay.title": "",
"components.Form.Request.amount": "المبلغ",
"components.Form.Request.details": "",
"components.Form.Request.memo": "",
"components.Form.Request.request": "",
"components.Form.Request.title": "",
"components.LoadingBolt.loading": "",
"components.Onboarding.Autopilot.disable": "",
"components.Onboarding.Autopilot.enable": "",
"components.Onboarding.BtcPayServer.btcpay_description": "",
"components.Onboarding.BtcPayServer.btcpay_error": "",
"components.Onboarding.BtcPayServer.connection_string_label": "",
"components.Onboarding.BtcPayServer.connection_string_placeholder": "",
"components.Onboarding.ConnectionConfirm.verify_host_description": "",
"components.Onboarding.ConnectionConfirm.verify_host_title": "",
"components.Onboarding.ConnectionDetails.cert_description": "",
"components.Onboarding.ConnectionDetails.cert_title": "",
"components.Onboarding.ConnectionDetails.hostname_description": "",
"components.Onboarding.ConnectionDetails.hostname_title": "",
"components.Onboarding.ConnectionDetails.macaroon_description": "",
"components.Onboarding.ConnectionType.btcpay_description": "",
"components.Onboarding.ConnectionType.custom": "",
"components.Onboarding.ConnectionType.custom_description": "",
"components.Onboarding.ConnectionType.default": "",
"components.Onboarding.ConnectionType.default_description": "",
"components.Onboarding.ConnectionType.only": "",
"components.Onboarding.FormContainer.back": "",
"components.Onboarding.FormContainer.help": "تحتاج مساعدة؟",
"components.Onboarding.FormContainer.next": "",
"components.Onboarding.Login.password_placeholder": "",
"components.Onboarding.Login.unlock": "",
"components.Onboarding.NewWalletPassword.password_confirm_placeholder": "",
"components.Onboarding.NewWalletPassword.password_error_length": "",
"components.Onboarding.NewWalletPassword.password_error_match": "",
"components.Onboarding.NewWalletPassword.password_placeholder": "",
"components.Onboarding.NewWalletPassword.unlock": "",
"components.Onboarding.RecoverForm.word_placeholder": "",
"components.Onboarding.Signup.signup_create": "",
"components.Onboarding.Signup.signup_import": "",
"components.Onboarding.Syncing.block_progress": "",
"components.Onboarding.Syncing.filter_progress": "",
"components.Onboarding.Syncing.fund_description": "",
"components.Onboarding.Syncing.fund_title": "",
"components.Onboarding.Syncing.grab_coffee": "",
"components.Onboarding.Syncing.preparing": "",
"components.Onboarding.Syncing.sync_caption": "",
"components.Onboarding.Syncing.sync_description": "",
"components.Onboarding.Syncing.sync_title": "",
"components.Onboarding.Syncing.waiting_for_peers": "",
"components.Onboarding.alias_description": "",
"components.Onboarding.alias_title": "",
"components.Onboarding.autopilot_description": "",
"components.Onboarding.autopilot_title": "",
"components.Onboarding.btcpay_description": "",
"components.Onboarding.btcpay_title": "",
"components.Onboarding.confirm_connection_description": "",
"components.Onboarding.confirm_connection_title": "",
"components.Onboarding.connection_description": "",
"components.Onboarding.connection_details_custom_description": "",
"components.Onboarding.connection_details_custom_title": "",
"components.Onboarding.connection_title": "",
"components.Onboarding.create_wallet_password_description": "",
"components.Onboarding.create_wallet_password_title": "",
"components.Onboarding.import_description": "",
"components.Onboarding.import_title": "",
"components.Onboarding.login_description": "",
"components.Onboarding.login_title": "",
"components.Onboarding.retype_seed_description": "",
"components.Onboarding.retype_seed_title": "",
"components.Onboarding.save_seed_description": "",
"components.Onboarding.save_seed_title": "",
"components.Onboarding.signup_description": "",
"components.Onboarding.signup_title": "",
"components.Settings.Fiat.title": "",
"components.Settings.Locale.title": "",
"components.Settings.Menu.fiat": "",
"components.Settings.Menu.locale": "",
"components.Wallet.ReceiveModal.bitcoin_address": "",
"components.Wallet.ReceiveModal.copy_address": "",
"components.Wallet.ReceiveModal.copy_pubkey": "",
"components.Wallet.ReceiveModal.node_pubkey": "",
"components.Wallet.ReceiveModal.node_public_key": "",
"components.Wallet.pay": "",
"components.Wallet.payment_success": "",
"components.Wallet.request": "",
"components.Wallet.sending_tx": "",
"components.Wallet.transaction_success": ""
}

157
app/translations/bg-BG.json

@ -0,0 +1,157 @@
{
"components.Activity.Countdown.expires": "",
"components.Activity.Invoice.amount": "Сума",
"components.Activity.Invoice.received": "Получени",
"components.Activity.Invoice.requested": "Заявени",
"components.Activity.Invoice.type_paid": "",
"components.Activity.Invoice.type_unpaid": "",
"components.Activity.InvoiceModal.copy": "",
"components.Activity.InvoiceModal.memo": "Бележка",
"components.Activity.InvoiceModal.not_paid": "Не платени",
"components.Activity.InvoiceModal.paid": "Платени",
"components.Activity.InvoiceModal.pay_req": "Заявка за плащане",
"components.Activity.InvoiceModal.request": "Заявка",
"components.Activity.InvoiceModal.save": "Запази като изображение",
"components.Activity.Payment.amount": "Сума",
"components.Activity.Payment.fee": "Такса",
"components.Activity.Payment.type": "",
"components.Activity.PaymentModal.fee": "Такса",
"components.Activity.PaymentModal.lightning": "",
"components.Activity.PaymentModal.sent": "Изпратени",
"components.Activity.Transaction.amount": "Сума",
"components.Activity.Transaction.fee": "Такса",
"components.Activity.Transaction.received": "Получени",
"components.Activity.Transaction.sent": "Изпратени",
"components.Activity.Transaction.type": "",
"components.Activity.TransactionModal.fee": "Такса",
"components.Activity.TransactionModal.on_chain": "On-Chain",
"components.Activity.TransactionModal.received": "Получени",
"components.Activity.TransactionModal.sent": "Изпратени",
"components.Activity.all": "Всички",
"components.Activity.hide_expired": "",
"components.Activity.pending": "Чакащи",
"components.Activity.refresh": "Обновяване",
"components.Activity.requested": "Заявени",
"components.Activity.search": "Търсене",
"components.Activity.sent": "Изпратени",
"components.Activity.show_expired": "",
"components.Contacts.AddChannel.manual_button": "Свържи се ръчно",
"components.Contacts.AddChannel.manual_description": "Хм изглежда, че не можем да видим този възел от тук, искате ли да опитате да се свържете ръчно?",
"components.Contacts.AddChannel.offline": "Неактивни",
"components.Contacts.AddChannel.online": "",
"components.Contacts.AddChannel.pending": "Чакащи",
"components.Contacts.AddChannel.private": "",
"components.Contacts.ConnectManually.description": "Моля, въведете pubkey@host на възела към който искате да се свържете",
"components.Contacts.ConnectManually.placeholder": "pubkey@host",
"components.Contacts.ConnectManually.submit": "Свържи се",
"components.Contacts.ConnectManually.title": "Свържи се ръчно",
"components.Contacts.Network.closing": "Затварящи се",
"components.Contacts.Network.loading": "",
"components.Contacts.Network.offline": "Неактивни",
"components.Contacts.Network.online": "",
"components.Contacts.Network.open_channel": "Отвори канал",
"components.Contacts.Network.pay_limit": "",
"components.Contacts.Network.pending": "Чакащи",
"components.Contacts.Network.refresh": "Обновяване",
"components.Contacts.Network.req_limit": "",
"components.Contacts.Network.search_placeholder": "",
"components.Contacts.Network.title": "Моята мрежа",
"components.Contacts.SubmitChannelForm.description": "Отварянето на канал ще ви позволи да изпращате и получавате пари в Lightning мрежата. Вие не харчите пари, а по-скоро ги премествате в мрежата, където може да ги използвате.",
"components.Contacts.SubmitChannelForm.duplicate_warnig": "",
"components.Contacts.SubmitChannelForm.submit": "Създай Канал",
"components.Contacts.SubmitChannelForm.title": "Добавете средства към мрежа",
"components.Contacts.SuggestedNodes.connect": "",
"components.Contacts.SuggestedNodes.empty_description": "Хмм, изглежда, че все още нямате отворени канали. Ето някои предложения за възли, към които да отворите канал за да започнете",
"components.Form.Pay.amount": "Сума",
"components.Form.Pay.destination": "Дестинация",
"components.Form.Pay.onchain_description": "",
"components.Form.Pay.pay": "Плати",
"components.Form.Pay.request_placeholder": "Поставете заявката за плащане или bitcoin адресът тук",
"components.Form.Pay.title": "",
"components.Form.Request.amount": "Сума",
"components.Form.Request.details": "Подробности относно заявката",
"components.Form.Request.memo": "Бележка",
"components.Form.Request.request": "Заяви плащане",
"components.Form.Request.title": "Заявка за плащане",
"components.LoadingBolt.loading": "",
"components.Onboarding.Autopilot.disable": "Забрани",
"components.Onboarding.Autopilot.enable": "Разреши",
"components.Onboarding.BtcPayServer.btcpay_description": "Поставете цялото съдържание на вашия BTCPay Server connection конфигурационен файл. Той може да бъде намерен, като щракнете върху връзката наречена &quot;Click here to open the configuration file.&quot; в настройките на BTCPay Server gRPC.",
"components.Onboarding.BtcPayServer.btcpay_error": "Невалиден текст за свързване.",
"components.Onboarding.BtcPayServer.connection_string_label": "",
"components.Onboarding.BtcPayServer.connection_string_placeholder": "",
"components.Onboarding.ConnectionConfirm.verify_host_description": "Моля, проверете името на хоста внимателно.",
"components.Onboarding.ConnectionConfirm.verify_host_title": "Сигурни ли сте, че искате да се свържете към",
"components.Onboarding.ConnectionDetails.cert_description": "Път до lnd tls сертификата. Пример: /path/to/tls.cert",
"components.Onboarding.ConnectionDetails.cert_title": "",
"components.Onboarding.ConnectionDetails.hostname_description": "Име на хост и порт на Lnd gRPC интерфейса. Пример: localhost:10009",
"components.Onboarding.ConnectionDetails.hostname_title": "",
"components.Onboarding.ConnectionDetails.macaroon_description": "Път до lnd macaroon файла. Пример: /path/to/admin.macaroon",
"components.Onboarding.ConnectionType.btcpay_description": "Поставете цялото съдържание на вашия BTCPay Server connection конфигурационен файл. Той може да бъде намерен, като щракнете върху връзката наречена &quot;Click here to open the configuration file.&quot; в настройките на BTCPay Server gRPC.",
"components.Onboarding.ConnectionType.custom": "Ръчна настройка",
"components.Onboarding.ConnectionType.custom_description": "",
"components.Onboarding.ConnectionType.default": "По подразбиране",
"components.Onboarding.ConnectionType.default_description": "",
"components.Onboarding.ConnectionType.only": "",
"components.Onboarding.FormContainer.back": "Назад",
"components.Onboarding.FormContainer.help": "Нужда от помощ?",
"components.Onboarding.FormContainer.next": "Напред",
"components.Onboarding.Login.password_placeholder": "",
"components.Onboarding.Login.unlock": "Отключи",
"components.Onboarding.NewWalletPassword.password_confirm_placeholder": "",
"components.Onboarding.NewWalletPassword.password_error_length": "",
"components.Onboarding.NewWalletPassword.password_error_match": "",
"components.Onboarding.NewWalletPassword.password_placeholder": "",
"components.Onboarding.NewWalletPassword.unlock": "Отключи",
"components.Onboarding.RecoverForm.word_placeholder": "дума",
"components.Onboarding.Signup.signup_create": "Създай нов портфейл",
"components.Onboarding.Signup.signup_import": "Възстановяване на съществуващ портфейл",
"components.Onboarding.Syncing.block_progress": "",
"components.Onboarding.Syncing.filter_progress": "",
"components.Onboarding.Syncing.fund_description": "Можете да внесете пари във вашия портфейл докато чакате синхронизирането.",
"components.Onboarding.Syncing.fund_title": "Внеси пари в Zap портфейла",
"components.Onboarding.Syncing.grab_coffee": "Изглежда, че зареждането може да отнеме повече време. По-добре си направи едно кафе и опитай по-късно!",
"components.Onboarding.Syncing.preparing": "Подготвяне…",
"components.Onboarding.Syncing.sync_caption": "Синхронизиране с blockchain-a",
"components.Onboarding.Syncing.sync_description": "Моля, изчакайте известно време, докато ние зареждаме последните данни от blockchain.",
"components.Onboarding.Syncing.sync_title": "Добре дошъл отново в Zap портфейла!",
"components.Onboarding.Syncing.waiting_for_peers": "Изчакване за връзки…",
"components.Onboarding.alias_description": "Задайте псевдоним, с който ще ви разпознават, в Lightning мрежата",
"components.Onboarding.alias_title": "Как да ви наричаме?",
"components.Onboarding.autopilot_description": "Автопилотът е автоматичен мрежови мениджър. Вместо ръчно да изграждате мрежа от хора за извършване на плащания, разрешете автопилота за да може автоматично да се свържете към Lightning мрежата използвайки 60 % от вашия баланс.",
"components.Onboarding.autopilot_title": "",
"components.Onboarding.btcpay_description": "Поставете цялото съдържание на вашия BTCPay Server connection конфигурационен файл. Той може да бъде намерен, като щракнете върху връзката наречена &quot;Click here to open the configuration file.&quot; в настройките на BTCPay Server gRPC.",
"components.Onboarding.btcpay_title": "",
"components.Onboarding.confirm_connection_description": "",
"components.Onboarding.confirm_connection_title": "",
"components.Onboarding.connection_description": "По подразбиране Zap ще направи възел към мрежата и ще направи настройките автоматично. Също така, може да настройте и ръчна връзка и да използвате Zap за дистанционно контролиране на възел, ако желаете (за напреднали потребители).",
"components.Onboarding.connection_details_custom_description": "",
"components.Onboarding.connection_details_custom_title": "",
"components.Onboarding.connection_title": "Как искате да се свържете към Lightning мрежата?",
"components.Onboarding.create_wallet_password_description": "",
"components.Onboarding.create_wallet_password_title": "",
"components.Onboarding.import_description": "Добре, възстановяване на портфейла. Никой не ти е нужен, ще се справиш сам :)",
"components.Onboarding.import_title": "Възстановете вашия seed",
"components.Onboarding.login_description": "Изглежда, че вече имате портфейл. (намерихме един в `{walletDir}`). Моля, въведете паролата на портфейла си, за да го отключите.",
"components.Onboarding.login_title": "Добре дошъл отново!",
"components.Onboarding.retype_seed_description": "Вашите seed думи са важни! Ако ги загубите, няма да можете да възстановите портфейла си. За да се уверите, че правилно сте въвели вашите seed думи, моля въведете ги отново {word1}, {word2} & {word3}",
"components.Onboarding.retype_seed_title": "Въведете отново вашите seed думи",
"components.Onboarding.save_seed_description": "Моля, запазете тези 24 думи на сигурно място. Те ще ви помогнат да възстановите портфейла си в бъдеще",
"components.Onboarding.save_seed_title": "Запазете seed думите на портфейла ви",
"components.Onboarding.signup_description": "Искате ли да създадете нов портфейл или да възстановите съществуващ такъв?",
"components.Onboarding.signup_title": "Добре, нека направим някои настройки",
"components.Settings.Fiat.title": "Fiat валута",
"components.Settings.Locale.title": "Език",
"components.Settings.Menu.fiat": "Fiat валута",
"components.Settings.Menu.locale": "Език",
"components.Wallet.ReceiveModal.bitcoin_address": "Bitcoin адрес",
"components.Wallet.ReceiveModal.copy_address": "",
"components.Wallet.ReceiveModal.copy_pubkey": "",
"components.Wallet.ReceiveModal.node_pubkey": "",
"components.Wallet.ReceiveModal.node_public_key": "Публичния ключ на възела",
"components.Wallet.pay": "Плати",
"components.Wallet.payment_success": "Успешно изпратено плащане",
"components.Wallet.request": "Заяви",
"components.Wallet.sending_tx": "Изпращане на вашата транзакция…",
"components.Wallet.transaction_success": "Успешно изпратена транзакция"
}

157
app/translations/ca-ES.json

@ -0,0 +1,157 @@
{
"components.Activity.Countdown.expires": "",
"components.Activity.Invoice.amount": "",
"components.Activity.Invoice.received": "",
"components.Activity.Invoice.requested": "",
"components.Activity.Invoice.type_paid": "",
"components.Activity.Invoice.type_unpaid": "",
"components.Activity.InvoiceModal.copy": "",
"components.Activity.InvoiceModal.memo": "",
"components.Activity.InvoiceModal.not_paid": "",
"components.Activity.InvoiceModal.paid": "",
"components.Activity.InvoiceModal.pay_req": "",
"components.Activity.InvoiceModal.request": "",
"components.Activity.InvoiceModal.save": "",
"components.Activity.Payment.amount": "",
"components.Activity.Payment.fee": "",
"components.Activity.Payment.type": "",
"components.Activity.PaymentModal.fee": "",
"components.Activity.PaymentModal.lightning": "",
"components.Activity.PaymentModal.sent": "",
"components.Activity.Transaction.amount": "",
"components.Activity.Transaction.fee": "",
"components.Activity.Transaction.received": "",
"components.Activity.Transaction.sent": "",
"components.Activity.Transaction.type": "",
"components.Activity.TransactionModal.fee": "",
"components.Activity.TransactionModal.on_chain": "",
"components.Activity.TransactionModal.received": "",
"components.Activity.TransactionModal.sent": "",
"components.Activity.all": "",
"components.Activity.hide_expired": "",
"components.Activity.pending": "",
"components.Activity.refresh": "",
"components.Activity.requested": "",
"components.Activity.search": "",
"components.Activity.sent": "",
"components.Activity.show_expired": "",
"components.Contacts.AddChannel.manual_button": "",
"components.Contacts.AddChannel.manual_description": "",
"components.Contacts.AddChannel.offline": "",
"components.Contacts.AddChannel.online": "",
"components.Contacts.AddChannel.pending": "",
"components.Contacts.AddChannel.private": "",
"components.Contacts.ConnectManually.description": "",
"components.Contacts.ConnectManually.placeholder": "",
"components.Contacts.ConnectManually.submit": "",
"components.Contacts.ConnectManually.title": "",
"components.Contacts.Network.closing": "",
"components.Contacts.Network.loading": "",
"components.Contacts.Network.offline": "",
"components.Contacts.Network.online": "",
"components.Contacts.Network.open_channel": "",
"components.Contacts.Network.pay_limit": "",
"components.Contacts.Network.pending": "",
"components.Contacts.Network.refresh": "",
"components.Contacts.Network.req_limit": "",
"components.Contacts.Network.search_placeholder": "",
"components.Contacts.Network.title": "",
"components.Contacts.SubmitChannelForm.description": "",
"components.Contacts.SubmitChannelForm.duplicate_warnig": "",
"components.Contacts.SubmitChannelForm.submit": "",
"components.Contacts.SubmitChannelForm.title": "",
"components.Contacts.SuggestedNodes.connect": "",
"components.Contacts.SuggestedNodes.empty_description": "",
"components.Form.Pay.amount": "",
"components.Form.Pay.destination": "",
"components.Form.Pay.onchain_description": "",
"components.Form.Pay.pay": "",
"components.Form.Pay.request_placeholder": "",
"components.Form.Pay.title": "",
"components.Form.Request.amount": "",
"components.Form.Request.details": "",
"components.Form.Request.memo": "",
"components.Form.Request.request": "",
"components.Form.Request.title": "",
"components.LoadingBolt.loading": "",
"components.Onboarding.Autopilot.disable": "",
"components.Onboarding.Autopilot.enable": "",
"components.Onboarding.BtcPayServer.btcpay_description": "",
"components.Onboarding.BtcPayServer.btcpay_error": "",
"components.Onboarding.BtcPayServer.connection_string_label": "",
"components.Onboarding.BtcPayServer.connection_string_placeholder": "",
"components.Onboarding.ConnectionConfirm.verify_host_description": "",
"components.Onboarding.ConnectionConfirm.verify_host_title": "",
"components.Onboarding.ConnectionDetails.cert_description": "",
"components.Onboarding.ConnectionDetails.cert_title": "",
"components.Onboarding.ConnectionDetails.hostname_description": "",
"components.Onboarding.ConnectionDetails.hostname_title": "",
"components.Onboarding.ConnectionDetails.macaroon_description": "",
"components.Onboarding.ConnectionType.btcpay_description": "",
"components.Onboarding.ConnectionType.custom": "",
"components.Onboarding.ConnectionType.custom_description": "",
"components.Onboarding.ConnectionType.default": "",
"components.Onboarding.ConnectionType.default_description": "",
"components.Onboarding.ConnectionType.only": "",
"components.Onboarding.FormContainer.back": "",
"components.Onboarding.FormContainer.help": "",
"components.Onboarding.FormContainer.next": "",
"components.Onboarding.Login.password_placeholder": "",
"components.Onboarding.Login.unlock": "",
"components.Onboarding.NewWalletPassword.password_confirm_placeholder": "",
"components.Onboarding.NewWalletPassword.password_error_length": "",
"components.Onboarding.NewWalletPassword.password_error_match": "",
"components.Onboarding.NewWalletPassword.password_placeholder": "",
"components.Onboarding.NewWalletPassword.unlock": "",
"components.Onboarding.RecoverForm.word_placeholder": "",
"components.Onboarding.Signup.signup_create": "",
"components.Onboarding.Signup.signup_import": "",
"components.Onboarding.Syncing.block_progress": "",
"components.Onboarding.Syncing.filter_progress": "",
"components.Onboarding.Syncing.fund_description": "",
"components.Onboarding.Syncing.fund_title": "",
"components.Onboarding.Syncing.grab_coffee": "",
"components.Onboarding.Syncing.preparing": "",
"components.Onboarding.Syncing.sync_caption": "",
"components.Onboarding.Syncing.sync_description": "",
"components.Onboarding.Syncing.sync_title": "",
"components.Onboarding.Syncing.waiting_for_peers": "",
"components.Onboarding.alias_description": "",
"components.Onboarding.alias_title": "",
"components.Onboarding.autopilot_description": "",
"components.Onboarding.autopilot_title": "",
"components.Onboarding.btcpay_description": "",
"components.Onboarding.btcpay_title": "",
"components.Onboarding.confirm_connection_description": "",
"components.Onboarding.confirm_connection_title": "",
"components.Onboarding.connection_description": "",
"components.Onboarding.connection_details_custom_description": "",
"components.Onboarding.connection_details_custom_title": "",
"components.Onboarding.connection_title": "",
"components.Onboarding.create_wallet_password_description": "",
"components.Onboarding.create_wallet_password_title": "",
"components.Onboarding.import_description": "",
"components.Onboarding.import_title": "",
"components.Onboarding.login_description": "",
"components.Onboarding.login_title": "",
"components.Onboarding.retype_seed_description": "",
"components.Onboarding.retype_seed_title": "",
"components.Onboarding.save_seed_description": "",
"components.Onboarding.save_seed_title": "",
"components.Onboarding.signup_description": "",
"components.Onboarding.signup_title": "",
"components.Settings.Fiat.title": "",
"components.Settings.Locale.title": "",
"components.Settings.Menu.fiat": "",
"components.Settings.Menu.locale": "",
"components.Wallet.ReceiveModal.bitcoin_address": "",
"components.Wallet.ReceiveModal.copy_address": "",
"components.Wallet.ReceiveModal.copy_pubkey": "",
"components.Wallet.ReceiveModal.node_pubkey": "",
"components.Wallet.ReceiveModal.node_public_key": "",
"components.Wallet.pay": "",
"components.Wallet.payment_success": "",
"components.Wallet.request": "",
"components.Wallet.sending_tx": "",
"components.Wallet.transaction_success": ""
}

157
app/translations/cs-CZ.json

@ -0,0 +1,157 @@
{
"components.Activity.Countdown.expires": "",
"components.Activity.Invoice.amount": "Částka",
"components.Activity.Invoice.received": "Přijato",
"components.Activity.Invoice.requested": "Vyžádáno",
"components.Activity.Invoice.type_paid": "",
"components.Activity.Invoice.type_unpaid": "",
"components.Activity.InvoiceModal.copy": "",
"components.Activity.InvoiceModal.memo": "Poznámka",
"components.Activity.InvoiceModal.not_paid": "Nezaplaceno",
"components.Activity.InvoiceModal.paid": "Zaplaceno",
"components.Activity.InvoiceModal.pay_req": "Žádost o platbu",
"components.Activity.InvoiceModal.request": "Vyžádat",
"components.Activity.InvoiceModal.save": "Uložit jako obrázek",
"components.Activity.Payment.amount": "Částka",
"components.Activity.Payment.fee": "Poplatek",
"components.Activity.Payment.type": "",
"components.Activity.PaymentModal.fee": "Poplatek",
"components.Activity.PaymentModal.lightning": "",
"components.Activity.PaymentModal.sent": "Odesláno",
"components.Activity.Transaction.amount": "Částka",
"components.Activity.Transaction.fee": "Poplatek",
"components.Activity.Transaction.received": "Přijato",
"components.Activity.Transaction.sent": "Odesláno",
"components.Activity.Transaction.type": "",
"components.Activity.TransactionModal.fee": "Poplatek",
"components.Activity.TransactionModal.on_chain": "On-Chain",
"components.Activity.TransactionModal.received": "Přijato",
"components.Activity.TransactionModal.sent": "Odesláno",
"components.Activity.all": "Všechny",
"components.Activity.hide_expired": "",
"components.Activity.pending": "Čekající",
"components.Activity.refresh": "Aktualizovat",
"components.Activity.requested": "Vyžádáno",
"components.Activity.search": "Hledat",
"components.Activity.sent": "Odesláno",
"components.Activity.show_expired": "",
"components.Contacts.AddChannel.manual_button": "Propojit ručně",
"components.Contacts.AddChannel.manual_description": "Hm, vypadá to, že takhle uzel neuvidíme. Chcete se zkusit připojit manuálně?",
"components.Contacts.AddChannel.offline": "Offline",
"components.Contacts.AddChannel.online": "",
"components.Contacts.AddChannel.pending": "Čekající",
"components.Contacts.AddChannel.private": "",
"components.Contacts.ConnectManually.description": "Prosím zadejte údaj o uzlu: pubkey@host",
"components.Contacts.ConnectManually.placeholder": "pubkey@host",
"components.Contacts.ConnectManually.submit": "Odeslat",
"components.Contacts.ConnectManually.title": "Propojit ručně",
"components.Contacts.Network.closing": "Uzavírané",
"components.Contacts.Network.loading": "",
"components.Contacts.Network.offline": "Offline",
"components.Contacts.Network.online": "",
"components.Contacts.Network.open_channel": "Otevřít kanál",
"components.Contacts.Network.pay_limit": "",
"components.Contacts.Network.pending": "Čekající",
"components.Contacts.Network.refresh": "Aktualizovat",
"components.Contacts.Network.req_limit": "",
"components.Contacts.Network.search_placeholder": "",
"components.Contacts.Network.title": "Moje síť",
"components.Contacts.SubmitChannelForm.description": "Otevření kanálu vám pomůže odesílat a přijímat peníze přes Lightning Network. Neutrácíte tím žádné peníze, ale přesouváte tolik, kolik plánujete v síti použít.",
"components.Contacts.SubmitChannelForm.duplicate_warnig": "",
"components.Contacts.SubmitChannelForm.submit": "Odeslat",
"components.Contacts.SubmitChannelForm.title": "Přidat prostředky do sítě",
"components.Contacts.SuggestedNodes.connect": "",
"components.Contacts.SuggestedNodes.empty_description": "Hmmm, vypadá to, že zatím nemáte žádné otevřené kanály. Pro začátek navrhujeme otevřít kanál k některému z navrhovaných uzlů",
"components.Form.Pay.amount": "Částka",
"components.Form.Pay.destination": "Cíl",
"components.Form.Pay.onchain_description": "",
"components.Form.Pay.pay": "Zaplatit",
"components.Form.Pay.request_placeholder": "Vložte žádost o platbu nebo bitcoinovou adresu",
"components.Form.Pay.title": "",
"components.Form.Request.amount": "Částka",
"components.Form.Request.details": "Podrobnosti o žádosti",
"components.Form.Request.memo": "Poznámka",
"components.Form.Request.request": "Vyžádat",
"components.Form.Request.title": "Vyžádat platbu",
"components.LoadingBolt.loading": "",
"components.Onboarding.Autopilot.disable": "Zakázat",
"components.Onboarding.Autopilot.enable": "Povolit",
"components.Onboarding.BtcPayServer.btcpay_description": "Vložce celý obsah konfiguračního souboru vašeho BTCPay serveru. Naleznete ho po kliknutí na odkaz s názvem&quot;Klikněte zde pro otevření konfiguračního souboru.&quot; v nastavení gRPC vašeho BTCPay serveru.",
"components.Onboarding.BtcPayServer.btcpay_error": "Neplatný připojovací řetězec.",
"components.Onboarding.BtcPayServer.connection_string_label": "",
"components.Onboarding.BtcPayServer.connection_string_placeholder": "",
"components.Onboarding.ConnectionConfirm.verify_host_description": "Prosím, pečlivě zkontrolujte název hositele.",
"components.Onboarding.ConnectionConfirm.verify_host_title": "Jste si jistí, že chcete připojit k",
"components.Onboarding.ConnectionDetails.cert_description": "Cesta k certifikátu lnd tls. Příklad /path/to/tls.cert",
"components.Onboarding.ConnectionDetails.cert_title": "",
"components.Onboarding.ConnectionDetails.hostname_description": "Název hostitele a portu rozhraní Lnd gRPC. Příklad: localhost:10009",
"components.Onboarding.ConnectionDetails.hostname_title": "",
"components.Onboarding.ConnectionDetails.macaroon_description": "Cesta k souboru lnd macaroon. Příklad: /path/to/admin.macaroon",
"components.Onboarding.ConnectionType.btcpay_description": "Vložce celý obsah konfiguračního souboru vašeho BTCPay serveru. Naleznete ho po kliknutí na odkaz s názvem&quot;Klikněte zde pro otevření konfiguračního souboru.&quot; v nastavení gRPC vašeho BTCPay serveru.",
"components.Onboarding.ConnectionType.custom": "Vlastní",
"components.Onboarding.ConnectionType.custom_description": "",
"components.Onboarding.ConnectionType.default": "Výchozí",
"components.Onboarding.ConnectionType.default_description": "",
"components.Onboarding.ConnectionType.only": "",
"components.Onboarding.FormContainer.back": "Zpět",
"components.Onboarding.FormContainer.help": "Potřebujete poradit?",
"components.Onboarding.FormContainer.next": "Další",
"components.Onboarding.Login.password_placeholder": "",
"components.Onboarding.Login.unlock": "Odemknout",
"components.Onboarding.NewWalletPassword.password_confirm_placeholder": "",
"components.Onboarding.NewWalletPassword.password_error_length": "",
"components.Onboarding.NewWalletPassword.password_error_match": "",
"components.Onboarding.NewWalletPassword.password_placeholder": "",
"components.Onboarding.NewWalletPassword.unlock": "Odemknout",
"components.Onboarding.RecoverForm.word_placeholder": "slovo",
"components.Onboarding.Signup.signup_create": "Vytvořit novou peněženku",
"components.Onboarding.Signup.signup_import": "Importovat existující peněženku",
"components.Onboarding.Syncing.block_progress": "",
"components.Onboarding.Syncing.filter_progress": "",
"components.Onboarding.Syncing.fund_description": "Během sycnrhonizace si zatím můžete dobít vaši peněženku.",
"components.Onboarding.Syncing.fund_title": "Dobijte vaši Zap peněženku",
"components.Onboarding.Syncing.grab_coffee": "Vypadá to, že to nějakou dobu potrvá - dejte si kávu a nebo to zkuste později!",
"components.Onboarding.Syncing.preparing": "Příprava…",
"components.Onboarding.Syncing.sync_caption": "Synchronizace blockchainu",
"components.Onboarding.Syncing.sync_description": "Prosím čekejte, načítají se aktuální data z blockhainu.",
"components.Onboarding.Syncing.sync_title": "Vítejte zpět do peněženky Zap!",
"components.Onboarding.Syncing.waiting_for_peers": "Čekání na peery…",
"components.Onboarding.alias_description": "Zvolte si přezdívku, aby vás ostatní našli rychleji na Lightning Network",
"components.Onboarding.alias_title": "Jak vám máme říkat?",
"components.Onboarding.autopilot_description": "Autopilot je váš automatický manažer spojení. Místo manuálního přidávání lidí za vás autopilot automaticky vytvoří spojení do Lightning Network. Využije k tomu 60 % vašich prostředků.",
"components.Onboarding.autopilot_title": "",
"components.Onboarding.btcpay_description": "Vložce celý obsah konfiguračního souboru vašeho BTCPay serveru. Naleznete ho po kliknutí na odkaz s názvem&quot;Klikněte zde pro otevření konfiguračního souboru.&quot; v nastavení gRPC vašeho BTCPay serveru.",
"components.Onboarding.btcpay_title": "",
"components.Onboarding.confirm_connection_description": "",
"components.Onboarding.confirm_connection_title": "",
"components.Onboarding.connection_description": "Zap automaticky vybere uzel a všechnu práci udělá v pozadí za vás. Můžete nicméně nastavit vlastní spojení a použít Zap ke kontrole vzdáleného uzlu (pro pokročilé uživatele).",
"components.Onboarding.connection_details_custom_description": "",
"components.Onboarding.connection_details_custom_title": "",
"components.Onboarding.connection_title": "Jak se chcete připojit k Lightning Network?",
"components.Onboarding.create_wallet_password_description": "",
"components.Onboarding.create_wallet_password_title": "",
"components.Onboarding.import_description": "Peněženka se obnovuje, skvělé. Nepotřebujete nikoho jiného, máte sebe :)",
"components.Onboarding.import_title": "Importovat seed",
"components.Onboarding.login_description": "Vypadá to, že už jednu peněženku máte (našli jsme ji zde: `{walletDir}`). Prosím, zadejte heslo pro její odemknutí.",
"components.Onboarding.login_title": "Vítejte zpět!",
"components.Onboarding.retype_seed_description": "Váš seed je důležitý! Když ho ztratíte, nepůjde obnovit peněženku. Abychom se ujistili, že jste si ho správně opsali, zadejte slova znovu {word1}, {word2} & {word3}",
"components.Onboarding.retype_seed_title": "Zadejte znovu seed",
"components.Onboarding.save_seed_description": "Prosím, uložte těchto 24 slov bezpečně! Umožní vám v budoucnu obnovit peněženku",
"components.Onboarding.save_seed_title": "Uložit seed peněženky",
"components.Onboarding.signup_description": "Chcete vytvořit novou peněženku nebo importovat existující?",
"components.Onboarding.signup_title": "Pojďme vše nastavit",
"components.Settings.Fiat.title": "Fiat měna",
"components.Settings.Locale.title": "Jazyk",
"components.Settings.Menu.fiat": "Fiat měna",
"components.Settings.Menu.locale": "Jazyk",
"components.Wallet.ReceiveModal.bitcoin_address": "Bitcoinová adresa",
"components.Wallet.ReceiveModal.copy_address": "",
"components.Wallet.ReceiveModal.copy_pubkey": "",
"components.Wallet.ReceiveModal.node_pubkey": "",
"components.Wallet.ReceiveModal.node_public_key": "Veřejný klíč uzlu",
"components.Wallet.pay": "Zaplatit",
"components.Wallet.payment_success": "Platba úspěšně odeslána",
"components.Wallet.request": "Vyžádat",
"components.Wallet.sending_tx": "Probíhá odesílání vaší transakce…",
"components.Wallet.transaction_success": "Transakce úspěšně odeslána"
}

157
app/translations/da-DK.json

@ -0,0 +1,157 @@
{
"components.Activity.Countdown.expires": "",
"components.Activity.Invoice.amount": "",
"components.Activity.Invoice.received": "",
"components.Activity.Invoice.requested": "",
"components.Activity.Invoice.type_paid": "",
"components.Activity.Invoice.type_unpaid": "",
"components.Activity.InvoiceModal.copy": "",
"components.Activity.InvoiceModal.memo": "Memo",
"components.Activity.InvoiceModal.not_paid": "",
"components.Activity.InvoiceModal.paid": "",
"components.Activity.InvoiceModal.pay_req": "Anmodning om betaling",
"components.Activity.InvoiceModal.request": "",
"components.Activity.InvoiceModal.save": "",
"components.Activity.Payment.amount": "",
"components.Activity.Payment.fee": "",
"components.Activity.Payment.type": "",
"components.Activity.PaymentModal.fee": "Gebyr",
"components.Activity.PaymentModal.lightning": "",
"components.Activity.PaymentModal.sent": "",
"components.Activity.Transaction.amount": "",
"components.Activity.Transaction.fee": "",
"components.Activity.Transaction.received": "",
"components.Activity.Transaction.sent": "",
"components.Activity.Transaction.type": "",
"components.Activity.TransactionModal.fee": "Gebyr",
"components.Activity.TransactionModal.on_chain": "",
"components.Activity.TransactionModal.received": "",
"components.Activity.TransactionModal.sent": "",
"components.Activity.all": "",
"components.Activity.hide_expired": "",
"components.Activity.pending": "",
"components.Activity.refresh": "",
"components.Activity.requested": "",
"components.Activity.search": "",
"components.Activity.sent": "",
"components.Activity.show_expired": "",
"components.Contacts.AddChannel.manual_button": "",
"components.Contacts.AddChannel.manual_description": "",
"components.Contacts.AddChannel.offline": "Offline",
"components.Contacts.AddChannel.online": "Online",
"components.Contacts.AddChannel.pending": "",
"components.Contacts.AddChannel.private": "",
"components.Contacts.ConnectManually.description": "",
"components.Contacts.ConnectManually.placeholder": "",
"components.Contacts.ConnectManually.submit": "",
"components.Contacts.ConnectManually.title": "",
"components.Contacts.Network.closing": "lukker",
"components.Contacts.Network.loading": "",
"components.Contacts.Network.offline": "offline",
"components.Contacts.Network.online": "online",
"components.Contacts.Network.open_channel": "",
"components.Contacts.Network.pay_limit": "",
"components.Contacts.Network.pending": "",
"components.Contacts.Network.refresh": "",
"components.Contacts.Network.req_limit": "",
"components.Contacts.Network.search_placeholder": "",
"components.Contacts.Network.title": "",
"components.Contacts.SubmitChannelForm.description": "",
"components.Contacts.SubmitChannelForm.duplicate_warnig": "",
"components.Contacts.SubmitChannelForm.submit": "",
"components.Contacts.SubmitChannelForm.title": "",
"components.Contacts.SuggestedNodes.connect": "Tilslut",
"components.Contacts.SuggestedNodes.empty_description": "",
"components.Form.Pay.amount": "Beløb",
"components.Form.Pay.destination": "",
"components.Form.Pay.onchain_description": "",
"components.Form.Pay.pay": "",
"components.Form.Pay.request_placeholder": "",
"components.Form.Pay.title": "",
"components.Form.Request.amount": "Beløb",
"components.Form.Request.details": "",
"components.Form.Request.memo": "Memo",
"components.Form.Request.request": "",
"components.Form.Request.title": "",
"components.LoadingBolt.loading": "",
"components.Onboarding.Autopilot.disable": "",
"components.Onboarding.Autopilot.enable": "",
"components.Onboarding.BtcPayServer.btcpay_description": "",
"components.Onboarding.BtcPayServer.btcpay_error": "",
"components.Onboarding.BtcPayServer.connection_string_label": "",
"components.Onboarding.BtcPayServer.connection_string_placeholder": "",
"components.Onboarding.ConnectionConfirm.verify_host_description": "",
"components.Onboarding.ConnectionConfirm.verify_host_title": "",
"components.Onboarding.ConnectionDetails.cert_description": "",
"components.Onboarding.ConnectionDetails.cert_title": "",
"components.Onboarding.ConnectionDetails.hostname_description": "",
"components.Onboarding.ConnectionDetails.hostname_title": "",
"components.Onboarding.ConnectionDetails.macaroon_description": "",
"components.Onboarding.ConnectionType.btcpay_description": "",
"components.Onboarding.ConnectionType.custom": "",
"components.Onboarding.ConnectionType.custom_description": "",
"components.Onboarding.ConnectionType.default": "",
"components.Onboarding.ConnectionType.default_description": "",
"components.Onboarding.ConnectionType.only": "",
"components.Onboarding.FormContainer.back": "",
"components.Onboarding.FormContainer.help": "Brug for hjælp?",
"components.Onboarding.FormContainer.next": "Næste",
"components.Onboarding.Login.password_placeholder": "",
"components.Onboarding.Login.unlock": "",
"components.Onboarding.NewWalletPassword.password_confirm_placeholder": "",
"components.Onboarding.NewWalletPassword.password_error_length": "",
"components.Onboarding.NewWalletPassword.password_error_match": "",
"components.Onboarding.NewWalletPassword.password_placeholder": "",
"components.Onboarding.NewWalletPassword.unlock": "",
"components.Onboarding.RecoverForm.word_placeholder": "",
"components.Onboarding.Signup.signup_create": "",
"components.Onboarding.Signup.signup_import": "",
"components.Onboarding.Syncing.block_progress": "",
"components.Onboarding.Syncing.filter_progress": "",
"components.Onboarding.Syncing.fund_description": "",
"components.Onboarding.Syncing.fund_title": "",
"components.Onboarding.Syncing.grab_coffee": "",
"components.Onboarding.Syncing.preparing": "",
"components.Onboarding.Syncing.sync_caption": "",
"components.Onboarding.Syncing.sync_description": "",
"components.Onboarding.Syncing.sync_title": "",
"components.Onboarding.Syncing.waiting_for_peers": "",
"components.Onboarding.alias_description": "",
"components.Onboarding.alias_title": "",
"components.Onboarding.autopilot_description": "",
"components.Onboarding.autopilot_title": "",
"components.Onboarding.btcpay_description": "",
"components.Onboarding.btcpay_title": "",
"components.Onboarding.confirm_connection_description": "",
"components.Onboarding.confirm_connection_title": "",
"components.Onboarding.connection_description": "",
"components.Onboarding.connection_details_custom_description": "",
"components.Onboarding.connection_details_custom_title": "",
"components.Onboarding.connection_title": "",
"components.Onboarding.create_wallet_password_description": "",
"components.Onboarding.create_wallet_password_title": "",
"components.Onboarding.import_description": "",
"components.Onboarding.import_title": "",
"components.Onboarding.login_description": "",
"components.Onboarding.login_title": "",
"components.Onboarding.retype_seed_description": "",
"components.Onboarding.retype_seed_title": "",
"components.Onboarding.save_seed_description": "",
"components.Onboarding.save_seed_title": "",
"components.Onboarding.signup_description": "",
"components.Onboarding.signup_title": "",
"components.Settings.Fiat.title": "",
"components.Settings.Locale.title": "",
"components.Settings.Menu.fiat": "",
"components.Settings.Menu.locale": "",
"components.Wallet.ReceiveModal.bitcoin_address": "",
"components.Wallet.ReceiveModal.copy_address": "",
"components.Wallet.ReceiveModal.copy_pubkey": "",
"components.Wallet.ReceiveModal.node_pubkey": "",
"components.Wallet.ReceiveModal.node_public_key": "",
"components.Wallet.pay": "",
"components.Wallet.payment_success": "",
"components.Wallet.request": "",
"components.Wallet.sending_tx": "",
"components.Wallet.transaction_success": ""
}

157
app/translations/de-DE.json

@ -0,0 +1,157 @@
{
"components.Activity.Countdown.expires": "Ablaufend in",
"components.Activity.Invoice.amount": "Betrag",
"components.Activity.Invoice.received": "Erhaltene Zahlung",
"components.Activity.Invoice.requested": "Angeforderte Zahlung",
"components.Activity.Invoice.type_paid": "Lightning Rechnung (bezahlt)",
"components.Activity.Invoice.type_unpaid": "Lightning Rechnung (nicht bezahlt)",
"components.Activity.InvoiceModal.copy": "Rechnungsanfrage kopieren",
"components.Activity.InvoiceModal.memo": "Memo",
"components.Activity.InvoiceModal.not_paid": "Nicht bezahlt",
"components.Activity.InvoiceModal.paid": "Bezahlt",
"components.Activity.InvoiceModal.pay_req": "Zahlungsanfrage",
"components.Activity.InvoiceModal.request": "Anfrage",
"components.Activity.InvoiceModal.save": "Als Bild speichern",
"components.Activity.Payment.amount": "Betrag",
"components.Activity.Payment.fee": "Gebühr",
"components.Activity.Payment.type": "Lightning Zahlung",
"components.Activity.PaymentModal.fee": "Gebühr",
"components.Activity.PaymentModal.lightning": "Lightning Network",
"components.Activity.PaymentModal.sent": "Gesendet",
"components.Activity.Transaction.amount": "Betrag",
"components.Activity.Transaction.fee": "Gebühr",
"components.Activity.Transaction.received": "Erhalten",
"components.Activity.Transaction.sent": "Gesendet",
"components.Activity.Transaction.type": "Transaktion im Bitcoin Netzwerk",
"components.Activity.TransactionModal.fee": "Gebühr",
"components.Activity.TransactionModal.on_chain": "On-Chain",
"components.Activity.TransactionModal.received": "Erhalten",
"components.Activity.TransactionModal.sent": "Gesendet",
"components.Activity.all": "Alle",
"components.Activity.hide_expired": "Verstecke abgelaufene Anfragen",
"components.Activity.pending": "Ausstehend",
"components.Activity.refresh": "Aktualisieren",
"components.Activity.requested": "Angefragt",
"components.Activity.search": "Suche",
"components.Activity.sent": "Gesendet",
"components.Activity.show_expired": "Zeige abgelaufene Anfragen",
"components.Contacts.AddChannel.manual_button": "Manuell verbinden",
"components.Contacts.AddChannel.manual_description": "Hm, offenbar können wir diesen Node nicht erreichen. Möchtest du dich manuell verbinden?",
"components.Contacts.AddChannel.offline": "Offline",
"components.Contacts.AddChannel.online": "Online",
"components.Contacts.AddChannel.pending": "Ausstehend",
"components.Contacts.AddChannel.private": "Privat",
"components.Contacts.ConnectManually.description": "Bitte pubkey@host des Peers einfügen",
"components.Contacts.ConnectManually.placeholder": "pubkey@host",
"components.Contacts.ConnectManually.submit": "Senden",
"components.Contacts.ConnectManually.title": "Manuell verbinden",
"components.Contacts.Network.closing": "Schließen",
"components.Contacts.Network.loading": "lädt",
"components.Contacts.Network.offline": "Offline",
"components.Contacts.Network.online": "online",
"components.Contacts.Network.open_channel": "Zahlungskanal öffnen",
"components.Contacts.Network.pay_limit": "Limit für Zahlungen",
"components.Contacts.Network.pending": "Ausstehend",
"components.Contacts.Network.refresh": "Aktualisieren",
"components.Contacts.Network.req_limit": "Anfragelimit",
"components.Contacts.Network.search_placeholder": "suche anhand alias oder öffentlichen schlüssel",
"components.Contacts.Network.title": "Mein Netzwerk",
"components.Contacts.SubmitChannelForm.description": "Das Öffnen eines Zahlungskanals hilft dir Zahlungen über das Lightning Netzwerk zu senden und zu empfangen. Du gibst dabei kein Geld aus, sondern speicherst Geld im Netzwerk, das du später nutzen kannst.",
"components.Contacts.SubmitChannelForm.duplicate_warnig": "Sie haben derzeit {activeChannels, plural, zero {keine aktiven kanäle} one {1 aktive(r) kanäle} other {{activeChannels} aktive kanäle}} gegenüber {aliasMsg, select, this_node {node} other{{aliasMsg}}} geöffnet mit einer Kapazität von",
"components.Contacts.SubmitChannelForm.submit": "Senden",
"components.Contacts.SubmitChannelForm.title": "Guthaben dem Netzwerk hinzufügen",
"components.Contacts.SuggestedNodes.connect": "Verbinden",
"components.Contacts.SuggestedNodes.empty_description": "Hmmm, sieht so aus als hättest Du noch keine Zahlungskanäle. Hier sind einige empfohlene Nodes, mit denen Du einen Kanal öffnen kannst um loszulegen",
"components.Form.Pay.amount": "Betrag",
"components.Form.Pay.destination": "Ziel",
"components.Form.Pay.onchain_description": "Im Bitcoin Netzwerk (~10 Minuten)",
"components.Form.Pay.pay": "Bezahlen",
"components.Form.Pay.request_placeholder": "Füge Zahlungsanfrage oder Bitcoin Adresse ein",
"components.Form.Pay.title": "Zahlung ausführen",
"components.Form.Request.amount": "Betrag",
"components.Form.Request.details": "Details zur Anfrage",
"components.Form.Request.memo": "Memo",
"components.Form.Request.request": "Anforderung",
"components.Form.Request.title": "Zahlung anfordern",
"components.LoadingBolt.loading": "lädt",
"components.Onboarding.Autopilot.disable": "Aus",
"components.Onboarding.Autopilot.enable": "An",
"components.Onboarding.BtcPayServer.btcpay_description": "Füge den gesamten Inhalt deiner BTCPay Server connection config Datei ein. Du findest diese unter folgendem Link &quot; Klicke hier um die Konfigurationsdatei &quot; in deinen BTCPay Server gRPC Einstellungen zu öffnen.",
"components.Onboarding.BtcPayServer.btcpay_error": "Ungültiger Verbindungsstring.",
"components.Onboarding.BtcPayServer.connection_string_label": "Zeichenfolge der Verbindung",
"components.Onboarding.BtcPayServer.connection_string_placeholder": "Verbindungszeichenfolge des BTCPay Server",
"components.Onboarding.ConnectionConfirm.verify_host_description": "Bitte überprüfe den Hostnamen sorgfältig.",
"components.Onboarding.ConnectionConfirm.verify_host_title": "Willst du wirklich eine Verbindung zu .............. herstellen",
"components.Onboarding.ConnectionDetails.cert_description": "Pfad zum lnd tls cert. Beispiel: /path/to/tls.cert",
"components.Onboarding.ConnectionDetails.cert_title": "TLS-Zertifikat",
"components.Onboarding.ConnectionDetails.hostname_description": "Hostname und Port des Lnd gRPC Interface. Beispiel: localhost:10009",
"components.Onboarding.ConnectionDetails.hostname_title": "Betreiber",
"components.Onboarding.ConnectionDetails.macaroon_description": "Pfad zur lnd macaroon Datei. Beispiel: /path/to/admin.macaroon",
"components.Onboarding.ConnectionType.btcpay_description": "Füge den gesamten Inhalt deiner BTCPay Server connection config Datei ein. Du findest diese unter folgendem Link &quot; Klicke hier um die Konfigurationsdatei &quot; in deinen BTCPay Server gRPC Einstellungen zu öffnen.",
"components.Onboarding.ConnectionType.custom": "Benutzerdefiniert",
"components.Onboarding.ConnectionType.custom_description": "Verbinden Sie sich mit Ihrem eigenen Node. Sie werden Ihre eigenen Verbindungsinformationen benötigen. Nur für fortgeschrittene Benutzer.",
"components.Onboarding.ConnectionType.default": "Voreingestellt",
"components.Onboarding.ConnectionType.default_description": "Durch die Auswahl des Standardmodus wird alles automatisch für Sie getan. Einfach klicken und los!",
"components.Onboarding.ConnectionType.only": "nur",
"components.Onboarding.FormContainer.back": "Zurück",
"components.Onboarding.FormContainer.help": "Brauchst du Hilfe?",
"components.Onboarding.FormContainer.next": "Weiter",
"components.Onboarding.Login.password_placeholder": "Passwort",
"components.Onboarding.Login.unlock": "Entsperren",
"components.Onboarding.NewWalletPassword.password_confirm_placeholder": "Passwort bestätigen",
"components.Onboarding.NewWalletPassword.password_error_length": "Das Passwort muss mindestens {passwordMinLength} Zeichen lang sein",
"components.Onboarding.NewWalletPassword.password_error_match": "Die Passwörter stimmen nicht überein",
"components.Onboarding.NewWalletPassword.password_placeholder": "Passwort",
"components.Onboarding.NewWalletPassword.unlock": "Entsperren",
"components.Onboarding.RecoverForm.word_placeholder": "wort",
"components.Onboarding.Signup.signup_create": "Neues Wallet erstellen",
"components.Onboarding.Signup.signup_import": "Bestehendes Wallet importieren",
"components.Onboarding.Syncing.block_progress": "Block {currentBlock} von {totalBlocks}",
"components.Onboarding.Syncing.filter_progress": "Überweisungsfilter {currentFilter} von {totalFilters}",
"components.Onboarding.Syncing.fund_description": "Während der Synchronisation kannst du gleich dein Wallet aufladen.",
"components.Onboarding.Syncing.fund_title": "Lade dein Zap Wallet auf",
"components.Onboarding.Syncing.grab_coffee": "Sieht aus als könnte dies eine Weile dauern. Schnapp dir einen Kaffee oder versuche es später erneut!",
"components.Onboarding.Syncing.preparing": "Wird vorbereitet…",
"components.Onboarding.Syncing.sync_caption": "Synchronisierung mit der Blockchain",
"components.Onboarding.Syncing.sync_description": "Bitte hab Geduld während wir deine aktuellen Daten aus der Blockchain sammeln.",
"components.Onboarding.Syncing.sync_title": "Willkommen zurück in deiner Zap Wallet!",
"components.Onboarding.Syncing.waiting_for_peers": "Warte auf Verbindungen…",
"components.Onboarding.alias_description": "Gib deinen Benutzernamen ein, um anderen zu helfen, sich mit dir über das Lightning Network zu verbinden",
"components.Onboarding.alias_title": "Wie sollen wir dich nennen?",
"components.Onboarding.autopilot_description": "Autopilot ist ein automatischer Netzwerkverwalter. Anstatt manuell neue Leute hinzuzufügen um dein Zahlungsnetzwerk zu kreieren, kannst du Autopilot aktivieren um automatisch 60% deines Guthabens für Verbindungen zum Lightning Netzwerk zu verwenden.",
"components.Onboarding.autopilot_title": "Autopilot",
"components.Onboarding.btcpay_description": "Füge den gesamten Inhalt deiner BTCPay Server connection config Datei ein. Du findest diese unter folgendem Link &quot; Klicke hier um die Konfigurationsdatei &quot; in deinen BTCPay Server gRPC Einstellungen zu öffnen.",
"components.Onboarding.btcpay_title": "BTCPay Server",
"components.Onboarding.confirm_connection_description": "Bestätigen Sie die Verbindungsinformationen für Ihren Lightning Node.",
"components.Onboarding.confirm_connection_title": "Verbindung bestätigen",
"components.Onboarding.connection_description": "Standardmässig setzt Zap für dich einen Node auf und übernimmt die komplizierten Dinge im Hintergrund. Du hast jedoch die Möglichkeit, eine benutzerdefinierte Verbindung zu einem Node aufzubauen und diesen über Zap fernzuverwalten (für erfahrene Nutzer).",
"components.Onboarding.connection_details_custom_description": "Geben Sie die Verbindungsdaten für Ihren Lightning Node an.",
"components.Onboarding.connection_details_custom_title": "Verbindungsdetails",
"components.Onboarding.connection_title": "Wie möchtest Du Dich mit dem Lightning Network verbinden?",
"components.Onboarding.create_wallet_password_description": "Sieht aus als wären Sie neu. Erstellen Sie ein Passwort um Ihre Geldbörse zu verschlüsseln. Dieses Passwort wird benötigt um Zap in der Zukunft zu entsperren",
"components.Onboarding.create_wallet_password_title": "Willkommen!",
"components.Onboarding.import_description": "Wallet wiederhergestellt, toll! Du brauchst niemand anderen, du hast alles unter deiner Kontrolle :)",
"components.Onboarding.import_title": "Importiere deinen Seed",
"components.Onboarding.login_description": "Offenbar hast du bereits ein Wallet (wir haben eines gefunden: `{walletDir}`). Bitte gib dein Passwort ein um es zu entsperren.",
"components.Onboarding.login_title": "Willkommen zurück!",
"components.Onboarding.retype_seed_description": "Dein Seed ist wichtig! Wenn du deinen Seed verlierst, gibt es keine Möglichkeit dein Wallet wiederherzustellen. Um sicher zu gehen, dass du deinen Seed korrekt gespeichert hast, tippe folgende Wörter noch einmal ein {word1}, {word2} & {word3}",
"components.Onboarding.retype_seed_title": "Tippe deinen Seed noch einmal ein",
"components.Onboarding.save_seed_description": "Bitte bewahre diese 24 Wörter unbedingt sicher auf! Du brauchst diese Wörter um dein Wallet in Zukunft wiederherzustellen",
"components.Onboarding.save_seed_title": "Schreibe deinen (Wallet) Seed auf ein Blatt Papier und bewahre es an einem sicheren Ort auf",
"components.Onboarding.signup_description": "Möchtest du ein neues Wallet aufsetzen oder ein bestehendes importieren?",
"components.Onboarding.signup_title": "Ok, legen wir los",
"components.Settings.Fiat.title": "Fiat-Währung",
"components.Settings.Locale.title": "Sprache",
"components.Settings.Menu.fiat": "Fiat-Währung",
"components.Settings.Menu.locale": "Sprache",
"components.Wallet.ReceiveModal.bitcoin_address": "Bitcoin Adresse",
"components.Wallet.ReceiveModal.copy_address": "Kopiere Adresse",
"components.Wallet.ReceiveModal.copy_pubkey": "Public Key kopieren",
"components.Wallet.ReceiveModal.node_pubkey": "Node öffentlicher Schlüssel",
"components.Wallet.ReceiveModal.node_public_key": "Node Public Key",
"components.Wallet.pay": "Bezahlen",
"components.Wallet.payment_success": "Zahlung erfolgreich gesendet",
"components.Wallet.request": "Anfrage",
"components.Wallet.sending_tx": "Sende deine Transaktion…",
"components.Wallet.transaction_success": "Transaktion erfolgreich gesendet"
}

157
app/translations/el-GR.json

@ -0,0 +1,157 @@
{
"components.Activity.Countdown.expires": "",
"components.Activity.Invoice.amount": "Ποσό",
"components.Activity.Invoice.received": "Έλαβε",
"components.Activity.Invoice.requested": "Ζητείται",
"components.Activity.Invoice.type_paid": "",
"components.Activity.Invoice.type_unpaid": "",
"components.Activity.InvoiceModal.copy": "",
"components.Activity.InvoiceModal.memo": "Τιμολόγιο",
"components.Activity.InvoiceModal.not_paid": "Δεν καταβάλλεται",
"components.Activity.InvoiceModal.paid": "Καταβάλλεται",
"components.Activity.InvoiceModal.pay_req": "Αίτηση πληρωμής",
"components.Activity.InvoiceModal.request": "Ζητείται",
"components.Activity.InvoiceModal.save": "Αποθηκεύστε ως εικόνα",
"components.Activity.Payment.amount": "Ποσό",
"components.Activity.Payment.fee": "Αμοιβή",
"components.Activity.Payment.type": "",
"components.Activity.PaymentModal.fee": "Αμοιβή",
"components.Activity.PaymentModal.lightning": "",
"components.Activity.PaymentModal.sent": "Αποστέλλονται",
"components.Activity.Transaction.amount": "Ποσό",
"components.Activity.Transaction.fee": "Αμοιβή",
"components.Activity.Transaction.received": "Έλαβε",
"components.Activity.Transaction.sent": "Αποστέλλονται",
"components.Activity.Transaction.type": "",
"components.Activity.TransactionModal.fee": "Αμοιβή",
"components.Activity.TransactionModal.on_chain": "Στο blockchain",
"components.Activity.TransactionModal.received": "Έλαβε",
"components.Activity.TransactionModal.sent": "Αποστέλλονται",
"components.Activity.all": "Ολα",
"components.Activity.hide_expired": "",
"components.Activity.pending": "Εκκρεμής",
"components.Activity.refresh": "Ανανέωση",
"components.Activity.requested": "Ζητείται",
"components.Activity.search": "Αναζήτηση",
"components.Activity.sent": "Απεσταλμένα",
"components.Activity.show_expired": "",
"components.Contacts.AddChannel.manual_button": "Συνδέστε μη αυτόματα",
"components.Contacts.AddChannel.manual_description": "Χμμμ, μοιάζει να μην βλέπουμε τον κόμβο από εδώ, να προσπαθήσουμε να συνδεθούμε χειροκίνητα;",
"components.Contacts.AddChannel.offline": "Χωρίς σύνδεση",
"components.Contacts.AddChannel.online": "Σε απευθείας σύνδεση",
"components.Contacts.AddChannel.pending": "Εκκρεμής",
"components.Contacts.AddChannel.private": "",
"components.Contacts.ConnectManually.description": "Παρακαλώ εισάγετε την pubkey@host του ομότιμου",
"components.Contacts.ConnectManually.placeholder": "pubkey@host",
"components.Contacts.ConnectManually.submit": "Υποβάλουν",
"components.Contacts.ConnectManually.title": "Συνδέστε μη αυτόματα",
"components.Contacts.Network.closing": "Κλείσιμο",
"components.Contacts.Network.loading": "",
"components.Contacts.Network.offline": "Χωρίς σύνδεση",
"components.Contacts.Network.online": "σε απευθείας σύνδεση",
"components.Contacts.Network.open_channel": "Ανοίξει ένα κανάλι",
"components.Contacts.Network.pay_limit": "",
"components.Contacts.Network.pending": "Εκκρεμής",
"components.Contacts.Network.refresh": "Ανανέωση",
"components.Contacts.Network.req_limit": "",
"components.Contacts.Network.search_placeholder": "",
"components.Contacts.Network.title": "Δίκτυο μου",
"components.Contacts.SubmitChannelForm.description": "Το άνοιγμα ενός καναλιού θα σας βοηθήσει να στείλετε και να λάβετε χρήματα στο δίκτυο Lightning. Δεν ξοδεύετε χρήματα, αλλά μεταφέρετε τα χρήματα που σκοπεύετε να χρησιμοποιήσετε στο δίκτυο.",
"components.Contacts.SubmitChannelForm.duplicate_warnig": "",
"components.Contacts.SubmitChannelForm.submit": "Υποβάλουν",
"components.Contacts.SubmitChannelForm.title": "Προσθήκη πόρων στο δίκτυο",
"components.Contacts.SuggestedNodes.connect": "Συνδέω-συωδεομαι",
"components.Contacts.SuggestedNodes.empty_description": "Χμμμ, μοιάζει ότι δεν έχετε ακόμα κανάλια. Ακολουθούν ορισμένοι προτεινόμενοι κόμβοι για να ανοίξετε ένα κανάλι για να ξεκινήσετε",
"components.Form.Pay.amount": "Ποσό",
"components.Form.Pay.destination": "Προορισμός",
"components.Form.Pay.onchain_description": "",
"components.Form.Pay.pay": "Πληρώσει",
"components.Form.Pay.request_placeholder": "Επικολλήστε το αίτημα ή το bitcoin διεύθυνση πληρωμής εδώ",
"components.Form.Pay.title": "",
"components.Form.Request.amount": "Ποσό",
"components.Form.Request.details": "Λεπτομέρειες σχετικά με την αίτηση",
"components.Form.Request.memo": "Τιμολόγιο",
"components.Form.Request.request": "Ζητείται",
"components.Form.Request.title": "Αίτηση πληρωμής",
"components.LoadingBolt.loading": "",
"components.Onboarding.Autopilot.disable": "Απενεργοποίηση",
"components.Onboarding.Autopilot.enable": "Ενεργοποίηση",
"components.Onboarding.BtcPayServer.btcpay_description": "Επικολλήστε το πλήρες περιεχόμενο του αρχείου ρύθμισης σύνδεσης BTCPay Server. Αυτό μπορεί να βρεθεί κάνοντας κλικ στον σύνδεσμο με τίτλο \"Κάντε κλικ εδώ για να ανοίξετε το αρχείο ρυθμίσεων\" στις ρυθμίσεις gRPC του διακομιστή BTCPay.",
"components.Onboarding.BtcPayServer.btcpay_error": "Μη έγκυρη συμβολοσειρά σύνδεσης.",
"components.Onboarding.BtcPayServer.connection_string_label": "",
"components.Onboarding.BtcPayServer.connection_string_placeholder": "",
"components.Onboarding.ConnectionConfirm.verify_host_description": "Ελέγξτε προσεκτικά το όνομα του κεντρικού υπολογιστή.",
"components.Onboarding.ConnectionConfirm.verify_host_title": "Είστε βέβαιοι ότι θέλετε να συνδεθείτε προς",
"components.Onboarding.ConnectionDetails.cert_description": "Διαδρομή προς το αρχείο macaroon. Παράδειγμα: /path/to/tls.cert",
"components.Onboarding.ConnectionDetails.cert_title": "",
"components.Onboarding.ConnectionDetails.hostname_description": "Όνομα κεντρικού υπολογιστή και θύρα της διεπαφής Lnd gRPC. Παράδειγμα: localhost:10009",
"components.Onboarding.ConnectionDetails.hostname_title": "",
"components.Onboarding.ConnectionDetails.macaroon_description": "Διαδρομή προς το αρχείο macaroon. Παράδειγμα: /path/to/admin.macaroon",
"components.Onboarding.ConnectionType.btcpay_description": "Επικολλήστε το πλήρες περιεχόμενο του αρχείου ρύθμισης σύνδεσης BTCPay Server. Αυτό μπορεί να βρεθεί κάνοντας κλικ στον σύνδεσμο με τίτλο \"Κάντε κλικ εδώ για να ανοίξετε το αρχείο ρυθμίσεων\" στις ρυθμίσεις gRPC του διακομιστή BTCPay.",
"components.Onboarding.ConnectionType.custom": "Προσαρμοσμένη",
"components.Onboarding.ConnectionType.custom_description": "",
"components.Onboarding.ConnectionType.default": "Προεπιλογή",
"components.Onboarding.ConnectionType.default_description": "",
"components.Onboarding.ConnectionType.only": "",
"components.Onboarding.FormContainer.back": "Πίσω",
"components.Onboarding.FormContainer.help": "Χρειάζεστε βοήθεια;",
"components.Onboarding.FormContainer.next": "Επόμενη",
"components.Onboarding.Login.password_placeholder": "",
"components.Onboarding.Login.unlock": "Ξεκλειδώσετε",
"components.Onboarding.NewWalletPassword.password_confirm_placeholder": "",
"components.Onboarding.NewWalletPassword.password_error_length": "",
"components.Onboarding.NewWalletPassword.password_error_match": "",
"components.Onboarding.NewWalletPassword.password_placeholder": "",
"components.Onboarding.NewWalletPassword.unlock": "Ξεκλειδώσετε",
"components.Onboarding.RecoverForm.word_placeholder": "λέξη",
"components.Onboarding.Signup.signup_create": "Δημιουργήστε νέο πορτοφόλι",
"components.Onboarding.Signup.signup_import": "Εισαγωγή υπάρχουσας πορτοφόλι",
"components.Onboarding.Syncing.block_progress": "",
"components.Onboarding.Syncing.filter_progress": "",
"components.Onboarding.Syncing.fund_description": "Μπορεί επίσης να χρηματοδοτήσει το πορτοφόλι σας ενώ περιμένετε να συγχρονιστεί.",
"components.Onboarding.Syncing.fund_title": "Χρηματοδοτήστε το πορτοφόλι σας Zap",
"components.Onboarding.Syncing.grab_coffee": "Αυτό μπορεί να διαρκέσει λίγο. Μπορεί να θέλετε να πιείτε έναν καφέ ή να δοκιμάσετε αργότερα!",
"components.Onboarding.Syncing.preparing": "Προετοιμασία…",
"components.Onboarding.Syncing.sync_caption": "Συγχρονισμός με το blockchain",
"components.Onboarding.Syncing.sync_description": "Παρακαλώ περιμένετε λίγο ενώ φέρουμε όλα τα τελευταία σας δεδομένα από το blockchain.",
"components.Onboarding.Syncing.sync_title": "Καλώς ήρθατε πίσω στο πορτοφόλι σας Zap!",
"components.Onboarding.Syncing.waiting_for_peers": "Αναμονή για συνομηλίκους…",
"components.Onboarding.alias_description": "Ορίστε το ψευδώνυμό σας για να βοηθήσει άλλους να συνδεθεί μαζί σας στο δίκτυο Lightning",
"components.Onboarding.alias_title": "Τι να σας καλέσουμε;",
"components.Onboarding.autopilot_description": "Ο αυτόματος πιλότος είναι ένας αυτόματος διαχειριστής δικτύου. Αντί να προσθέσετε με μη αυτόματα άτομα για να δημιουργήσετε το δίκτυό σας για να πραγματοποιήσετε πληρωμές, ενεργοποιήστε τον αυτόματο πιλότο για αυτόματη σύνδεση στο δίκτυο Lightning Network χρησιμοποιώντας το 60% του υπολοίπου σας.",
"components.Onboarding.autopilot_title": "",
"components.Onboarding.btcpay_description": "Επικολλήστε το πλήρες περιεχόμενο του αρχείου ρύθμισης σύνδεσης BTCPay Server. Αυτό μπορεί να βρεθεί κάνοντας κλικ στον σύνδεσμο με τίτλο \"Κάντε κλικ εδώ για να ανοίξετε το αρχείο ρυθμίσεων\" στις ρυθμίσεις gRPC του διακομιστή BTCPay.",
"components.Onboarding.btcpay_title": "",
"components.Onboarding.confirm_connection_description": "",
"components.Onboarding.confirm_connection_title": "",
"components.Onboarding.connection_description": "Από προεπιλογή, το Zap θα περιστρέψει έναν κόμβο για σας και θα χειριστεί όλα τα αστεία πράγματα στο παρασκήνιο. Ωστόσο, μπορείτε επίσης να ρυθμίσετε μια προσαρμοσμένη σύνδεση κόμβου και να χρησιμοποιήσετε το Zap για να ελέγξετε έναν απομακρυσμένο κόμβο εάν το επιθυμείτε (για προχωρημένους χρήστες).",
"components.Onboarding.connection_details_custom_description": "",
"components.Onboarding.connection_details_custom_title": "",
"components.Onboarding.connection_title": "Πώς θέλετε να συνδέσετε στο δίκτυο Lightning;",
"components.Onboarding.create_wallet_password_description": "",
"components.Onboarding.create_wallet_password_title": "",
"components.Onboarding.import_description": "Ανακτώντας ένα πορτοφόλι, ωραία. Δεν χρειάζεται κάποιος άλλος, έχεις τον εαυτό σας :)",
"components.Onboarding.import_title": "Εισαγάγετε το σπόρο σας",
"components.Onboarding.login_description": "Φαίνεται ότι έχετε ήδη ένα πορτοφόλι (we found one at `{walletDir}`). Εισαγάγετε τον κωδικό πρόσβασης πορτοφολιού για να το ξεκλειδώσετε.",
"components.Onboarding.login_title": "Καλωσόρισες ξανά!",
"components.Onboarding.retype_seed_description": "Το σπόρο σας είναι σημαντική! Αν χάσετε το σπόρο σας, θα έχετε δεν υπάρχει τρόπος να ανακτήσετε το πορτοφόλι σας. Για να βεβαιωθείτε ότι έχετε αποθηκεύσει σωστά το σπόρο σας, Παρακαλούμε πληκτρολογήστε λέξεις {word1}, {word2} & {word3}",
"components.Onboarding.retype_seed_title": "Πληκτρολογήστε ξανά το σπόρο σας",
"components.Onboarding.save_seed_description": "Παρακαλώ αποθηκεύστε με ασφάλεια τα λόγια αυτά 24! Αυτό θα σας επιτρέψει να ανακτήσετε το πορτοφόλι σας στο μέλλον",
"components.Onboarding.save_seed_title": "Αποθηκεύσετε το σπόρο σας πορτοφόλι",
"components.Onboarding.signup_description": "Θα θέλατε να δημιουργήσετε ένα νέο πορτοφόλι ή την εισαγωγή μιας υπάρχουσας;",
"components.Onboarding.signup_title": "Εντάξει, Ας πάρουν συσταθεί",
"components.Settings.Fiat.title": "Κυβερνητικό νόμισμα",
"components.Settings.Locale.title": "Γλώσσα",
"components.Settings.Menu.fiat": "Κυβερνητικό νόμισμα",
"components.Settings.Menu.locale": "Γλώσσα",
"components.Wallet.ReceiveModal.bitcoin_address": "Διεύθυνση Bitcoin",
"components.Wallet.ReceiveModal.copy_address": "",
"components.Wallet.ReceiveModal.copy_pubkey": "",
"components.Wallet.ReceiveModal.node_pubkey": "",
"components.Wallet.ReceiveModal.node_public_key": "Κόμβος δημόσιου κλειδιού",
"components.Wallet.pay": "Αποστολή πληρωμής",
"components.Wallet.payment_success": "Η πληρωμή έγινε με επιτυχία",
"components.Wallet.request": "Αίτηση πληρωμής",
"components.Wallet.sending_tx": "Αποστολή της συναλλαγής σας…",
"components.Wallet.transaction_success": "Η συναλλαγή στάλθηκε με επιτυχία"
}

157
app/translations/en.json

@ -0,0 +1,157 @@
{
"components.Activity.Countdown.expires": "Expires in",
"components.Activity.Invoice.amount": "Invoice amount",
"components.Activity.Invoice.received": "Received payment",
"components.Activity.Invoice.requested": "Requested payment",
"components.Activity.Invoice.type_paid": "Lightning invoice (paid)",
"components.Activity.Invoice.type_unpaid": "Lightning invoice (unpaid)",
"components.Activity.InvoiceModal.copy": "Copy Request",
"components.Activity.InvoiceModal.memo": "Memo",
"components.Activity.InvoiceModal.not_paid": "Not Paid",
"components.Activity.InvoiceModal.paid": "Paid",
"components.Activity.InvoiceModal.pay_req": "Payment Request",
"components.Activity.InvoiceModal.request": "Request",
"components.Activity.InvoiceModal.save": "Save as image",
"components.Activity.Payment.amount": "Payment amount",
"components.Activity.Payment.fee": "Payment fee",
"components.Activity.Payment.type": "Lightning payment",
"components.Activity.PaymentModal.fee": "Fee",
"components.Activity.PaymentModal.lightning": "Lightning Network",
"components.Activity.PaymentModal.sent": "Sent",
"components.Activity.Transaction.amount": "Transaction amount",
"components.Activity.Transaction.fee": "Transaction fee",
"components.Activity.Transaction.received": "Received",
"components.Activity.Transaction.sent": "Sent",
"components.Activity.Transaction.type": "On-chain transaction",
"components.Activity.TransactionModal.fee": "Fee",
"components.Activity.TransactionModal.on_chain": "On-Chain",
"components.Activity.TransactionModal.received": "Received",
"components.Activity.TransactionModal.sent": "Sent",
"components.Activity.all": "All",
"components.Activity.hide_expired": "Hide Expired Requests",
"components.Activity.pending": "Pending",
"components.Activity.refresh": "Refresh",
"components.Activity.requested": "Requested",
"components.Activity.search": "Search",
"components.Activity.sent": "Sent",
"components.Activity.show_expired": "Show Expired Requests",
"components.Contacts.AddChannel.manual_button": "Connect Manually",
"components.Contacts.AddChannel.manual_description": "Hm, looks like we can't see that node from here, wanna try to manually connect?",
"components.Contacts.AddChannel.offline": "Offline",
"components.Contacts.AddChannel.online": "Online",
"components.Contacts.AddChannel.pending": "Pending",
"components.Contacts.AddChannel.private": "Private",
"components.Contacts.ConnectManually.description": "Please enter the peer’s pubkey@host",
"components.Contacts.ConnectManually.placeholder": "pubkey@host",
"components.Contacts.ConnectManually.submit": "Submit",
"components.Contacts.ConnectManually.title": "Connect Manually",
"components.Contacts.Network.closing": "closing",
"components.Contacts.Network.loading": "loading",
"components.Contacts.Network.offline": "offline",
"components.Contacts.Network.online": "online",
"components.Contacts.Network.open_channel": "Open a channel",
"components.Contacts.Network.pay_limit": "Pay Limit",
"components.Contacts.Network.pending": "pending",
"components.Contacts.Network.refresh": "Refresh",
"components.Contacts.Network.req_limit": "Request Limit",
"components.Contacts.Network.search_placeholder": "search by alias or pubkey",
"components.Contacts.Network.title": "My Network",
"components.Contacts.SubmitChannelForm.description": "Opening a channel will help you send and receive money on the Lightning Network. You aren't spending any money, rather moving the money you plan to use onto the network.",
"components.Contacts.SubmitChannelForm.duplicate_warnig": "You currently have {activeChannels, plural, zero {no active channels} one {1 active channel} other {{activeChannels} active channels}} open to {aliasMsg, select, this_node {this node} other {{aliasMsg}}} with a capacity of",
"components.Contacts.SubmitChannelForm.submit": "Submit",
"components.Contacts.SubmitChannelForm.title": "Add Funds to Network",
"components.Contacts.SuggestedNodes.connect": "Connect",
"components.Contacts.SuggestedNodes.empty_description": "Hmmm, looks like you don't have any channels yet. Here are some suggested nodes to open a channel with to get started",
"components.Form.Pay.amount": "Amount",
"components.Form.Pay.destination": "Destination",
"components.Form.Pay.onchain_description": "On-Chain (~10 minutes)",
"components.Form.Pay.pay": "Pay",
"components.Form.Pay.request_placeholder": "Paste payment request or bitcoin address here",
"components.Form.Pay.title": "Make Payment",
"components.Form.Request.amount": "Amount",
"components.Form.Request.details": "Details about the request",
"components.Form.Request.memo": "Memo",
"components.Form.Request.request": "Request",
"components.Form.Request.title": "Request Payment",
"components.LoadingBolt.loading": "loading",
"components.Onboarding.Autopilot.disable": "Disable",
"components.Onboarding.Autopilot.enable": "Enable",
"components.Onboarding.BtcPayServer.btcpay_description": "Paste the full content of your BTCPay Server connection config file. This can be found by clicking the link entitled 'Click here to open the configuration file' in your BTCPay Server gRPC settings.",
"components.Onboarding.BtcPayServer.btcpay_error": "Invalid connection string.",
"components.Onboarding.BtcPayServer.connection_string_label": "Connection String",
"components.Onboarding.BtcPayServer.connection_string_placeholder": "BTCPay Server Connection String",
"components.Onboarding.ConnectionConfirm.verify_host_description": "Please check the hostname carefully.",
"components.Onboarding.ConnectionConfirm.verify_host_title": "Are you sure you want to connect to",
"components.Onboarding.ConnectionDetails.cert_description": "Path to the lnd tls cert. Example: /path/to/tls.cert",
"components.Onboarding.ConnectionDetails.cert_title": "TLS Certificate",
"components.Onboarding.ConnectionDetails.hostname_description": "Hostname and port of the Lnd gRPC interface. Example: localhost:10009",
"components.Onboarding.ConnectionDetails.hostname_title": "Host",
"components.Onboarding.ConnectionDetails.macaroon_description": "Path to the lnd macaroon file. Example: /path/to/admin.macaroon",
"components.Onboarding.ConnectionType.btcpay_description": "Connect to your own BTCPay Server instance to access your BTCPay Server wallet.",
"components.Onboarding.ConnectionType.custom": "Custom",
"components.Onboarding.ConnectionType.custom_description": "Connect to your own node. You will need to provide your own connection settings so this is for advanced users only.",
"components.Onboarding.ConnectionType.default": "Default",
"components.Onboarding.ConnectionType.default_description": "By selecting the defualt mode we will do everything for you. Just click and go!",
"components.Onboarding.ConnectionType.only": "only",
"components.Onboarding.FormContainer.back": "back",
"components.Onboarding.FormContainer.help": "Need Help?",
"components.Onboarding.FormContainer.next": "Next",
"components.Onboarding.Login.password_placeholder": "Password",
"components.Onboarding.Login.unlock": "Unlock",
"components.Onboarding.NewWalletPassword.password_confirm_placeholder": "Confirm Password",
"components.Onboarding.NewWalletPassword.password_error_length": "Password must be at least {passwordMinLength} characters long",
"components.Onboarding.NewWalletPassword.password_error_match": "Passwords do not match",
"components.Onboarding.NewWalletPassword.password_placeholder": "Password",
"components.Onboarding.NewWalletPassword.unlock": "Unlock",
"components.Onboarding.RecoverForm.word_placeholder": "word",
"components.Onboarding.Signup.signup_create": "Create new wallet",
"components.Onboarding.Signup.signup_import": "Import existing wallet",
"components.Onboarding.Syncing.block_progress": "Block {currentBlock} of {totalBlocks}",
"components.Onboarding.Syncing.filter_progress": "Commitment Filter {currentFilter} of {totalFilters}",
"components.Onboarding.Syncing.fund_description": "Might as well fund your wallet while you’re waiting to sync.",
"components.Onboarding.Syncing.fund_title": "Fund your Zap wallet",
"components.Onboarding.Syncing.grab_coffee": "It looks like this could take some time - you might want to grab a coffee or try again later!",
"components.Onboarding.Syncing.preparing": "Preparing…",
"components.Onboarding.Syncing.sync_caption": "Syncing to the blockchain",
"components.Onboarding.Syncing.sync_description": "Please wait a while whilst we fetch all of your latest data from the blockchain.",
"components.Onboarding.Syncing.sync_title": "Welcome back to your Zap wallet!",
"components.Onboarding.Syncing.waiting_for_peers": "Waiting for peers…",
"components.Onboarding.alias_description": "Set your nickname to help others connect with you on the Lightning Network",
"components.Onboarding.alias_title": "What should we call you?",
"components.Onboarding.autopilot_description": "Autopilot is an automatic network manager. Instead of manually adding people to build your network to make payments, enable autopilot to automatically connect you to the Lightning Network using 60% of your balance.",
"components.Onboarding.autopilot_title": "Autopilot",
"components.Onboarding.btcpay_description": "Enter the connection details for your BTCPay Server node.",
"components.Onboarding.btcpay_title": "BTCPay Server",
"components.Onboarding.confirm_connection_description": "Confirm the connection details for your Lightning node.",
"components.Onboarding.confirm_connection_title": "Confirm connection",
"components.Onboarding.connection_description": "By default Zap will spin up a node for you and handle all the nerdy stuff in the background. However you can also setup a custom node connection and use Zap to control a remote node if you desire (for advanced users).",
"components.Onboarding.connection_details_custom_description": "Enter the connection details for your Lightning node.",
"components.Onboarding.connection_details_custom_title": "Connection details",
"components.Onboarding.connection_title": "How do you want to connect to the Lightning Network?",
"components.Onboarding.create_wallet_password_description": "Looks like you are new here. Set a password to encrypt your wallet. This password will be needed to unlock Zap in the future",
"components.Onboarding.create_wallet_password_title": "Welcome!",
"components.Onboarding.import_description": "Recovering a wallet, nice. You don't need anyone else, you got yourself :)",
"components.Onboarding.import_title": "Import your seed",
"components.Onboarding.login_description": "It looks like you already have a wallet (wallet found at: `{walletDir}`). Please enter your wallet password to unlock it.",
"components.Onboarding.login_title": "Welcome back!",
"components.Onboarding.retype_seed_description": "Your seed is important! If you lose your seed you'll have no way to recover your wallet. To make sure that you have properly saved your seed, please retype words {word1}, {word2} & {word3}",
"components.Onboarding.retype_seed_title": "Retype your seed",
"components.Onboarding.save_seed_description": "Please save these 24 words securely! This will allow you to recover your wallet in the future",
"components.Onboarding.save_seed_title": "Save your wallet seed",
"components.Onboarding.signup_description": "Would you like to create a new wallet or import an existing one?",
"components.Onboarding.signup_title": "Alright, let's get set up",
"components.Settings.Fiat.title": "Fiat Currency",
"components.Settings.Locale.title": "Language",
"components.Settings.Menu.fiat": "Fiat Currency",
"components.Settings.Menu.locale": "Language",
"components.Wallet.ReceiveModal.bitcoin_address": "Bitcoin Address",
"components.Wallet.ReceiveModal.copy_address": "Copy address",
"components.Wallet.ReceiveModal.copy_pubkey": "Copy Pubkey",
"components.Wallet.ReceiveModal.node_pubkey": "Node Pubkey",
"components.Wallet.ReceiveModal.node_public_key": "Node Public Key",
"components.Wallet.pay": "Pay",
"components.Wallet.payment_success": "Successfully sent payment",
"components.Wallet.request": "Request",
"components.Wallet.sending_tx": "Sending your transaction…",
"components.Wallet.transaction_success": "Successfully sent transaction"
}

Some files were not shown because too many files changed in this diff

Loading…
Cancel
Save