Translation Updates (#1323)

* Update account view routing

* Temporarily add unicode character to translated strings for testing

* Temporarily select add unicode to all untranslated strings

* Format changes

* Add all english translations for /account & /generate

* Add the rest of the english translations

* Add a few more missing translations

* Update en translations

* Get selectedLanguage from localstorage instead of redux sttate

* Update snapshots

* Add missing translation keys & Update translate functs & change variable prefix

* translate all markdown strings & remove old translation strings

* Update snapshot

* Add a few more translation strs

* Move raw strings being translated into json

* All translation keys are now Uppercase

* Fix up the last few translations

* Update snapshot

* Uppercase de translation strings

* Bring back shapeshift logo on swap

* Fix contracts tab translations

* Fix a few more translations

* Fix translations

* remove debugging stuff

* Update snapshots

* Use react.fragment as markdown root renderer

* Seperate markdown translations into their own function

* Clean up translation functions

* Clean up translation functions

* Update snapshot

* Fix some broken translation strings

* Add prettier ignore file
This commit is contained in:
James Prado 2018-03-21 23:50:25 -04:00 committed by Daniel Ternyak
parent 7521337bda
commit 816ce3180f
135 changed files with 16096 additions and 16149 deletions

1
.prettierignore Normal file
View File

@ -0,0 +1 @@
common/translations

View File

@ -13,7 +13,7 @@ export const AddressField: React.SFC<Props> = ({ isReadOnly }) => (
withProps={({ currentTo, isValid, onChange, readOnly }) => ( withProps={({ currentTo, isValid, onChange, readOnly }) => (
<div className="input-group-wrapper"> <div className="input-group-wrapper">
<label className="input-group"> <label className="input-group">
<div className="input-group-header">{translate('SEND_addr')}</div> <div className="input-group-header">{translate('SEND_ADDR_SHORT')}</div>
<Input <Input
className={`input-group-input ${isValid ? '' : 'invalid'}`} className={`input-group-input ${isValid ? '' : 'invalid'}`}
type="text" type="text"

View File

@ -1,7 +1,7 @@
import React from 'react'; import React from 'react';
import { AmountFieldFactory } from './AmountFieldFactory'; import { AmountFieldFactory } from './AmountFieldFactory';
import { UnitDropDown } from 'components'; import { UnitDropDown } from 'components';
import translate, { translateRaw } from 'translations'; import translate from 'translations';
import { Input } from 'components/ui'; import { Input } from 'components/ui';
interface Props { interface Props {
@ -19,13 +19,13 @@ export const AmountField: React.SFC<Props> = ({
withProps={({ currentValue: { raw }, isValid, onChange, readOnly }) => ( withProps={({ currentValue: { raw }, isValid, onChange, readOnly }) => (
<div className="input-group-wrapper"> <div className="input-group-wrapper">
<label className="input-group input-group-inline"> <label className="input-group input-group-inline">
<div className="input-group-header">{translate('SEND_amount')}</div> <div className="input-group-header">{translate('SEND_AMOUNT_SHORT')}</div>
<Input <Input
className={`input-group-input ${ className={`input-group-input ${
isAmountValid(raw, customValidator, isValid) ? '' : 'invalid' isAmountValid(raw, customValidator, isValid) ? '' : 'invalid'
}`} }`}
type="number" type="number"
placeholder={translateRaw('SEND_amount_short')} placeholder={'1'}
value={raw} value={raw}
readOnly={!!readOnly} readOnly={!!readOnly}
onChange={onChange} onChange={onChange}

View File

@ -98,7 +98,7 @@ class AccountInfo extends React.Component<Props, State> {
const wallet = this.props.wallet as LedgerWallet | TrezorWallet; const wallet = this.props.wallet as LedgerWallet | TrezorWallet;
return ( return (
<div className="AccountInfo"> <div className="AccountInfo">
<h5 className="AccountInfo-section-header">{translate('sidebar_AccountAddr')}</h5> <h5 className="AccountInfo-section-header">{translate('SIDEBAR_ACCOUNTADDR')}</h5>
<div className="AccountInfo-section AccountInfo-address-section"> <div className="AccountInfo-section AccountInfo-address-section">
<div className="AccountInfo-address-icon"> <div className="AccountInfo-address-icon">
<Identicon address={address} size="100%" /> <Identicon address={address} size="100%" />
@ -134,7 +134,9 @@ class AccountInfo extends React.Component<Props, State> {
}); });
}} }}
> >
{confirmAddr ? null : 'Display address on ' + wallet.getWalletType()} {confirmAddr
? null
: translate('SIDEBAR_DISPLAY_ADDR', { $wallet: wallet.getWalletType() })}
</a> </a>
{confirmAddr ? ( {confirmAddr ? (
<span className="AccountInfo-address-confirm"> <span className="AccountInfo-address-confirm">
@ -145,7 +147,7 @@ class AccountInfo extends React.Component<Props, State> {
)} )}
<div className="AccountInfo-section"> <div className="AccountInfo-section">
<h5 className="AccountInfo-section-header">{translate('sidebar_AccountBal')}</h5> <h5 className="AccountInfo-section-header">{translate('SIDEBAR_ACCOUNTBAL')}</h5>
<ul className="AccountInfo-list"> <ul className="AccountInfo-list">
<li className="AccountInfo-list-item AccountInfo-balance"> <li className="AccountInfo-list-item AccountInfo-balance">
<span <span
@ -182,7 +184,7 @@ class AccountInfo extends React.Component<Props, State> {
{(!!blockExplorer || !!tokenExplorer) && ( {(!!blockExplorer || !!tokenExplorer) && (
<div className="AccountInfo-section"> <div className="AccountInfo-section">
<h5 className="AccountInfo-section-header">{translate('sidebar_TransHistory')}</h5> <h5 className="AccountInfo-section-header">{translate('SIDEBAR_TRANSHISTORY')}</h5>
<ul className="AccountInfo-list"> <ul className="AccountInfo-list">
{!!blockExplorer && ( {!!blockExplorer && (
<li className="AccountInfo-list-item"> <li className="AccountInfo-list-item">

View File

@ -169,7 +169,7 @@ class EquivalentValues extends React.Component<Props, State> {
return ( return (
<div className="EquivalentValues"> <div className="EquivalentValues">
<div className="EquivalentValues-header"> <div className="EquivalentValues-header">
<h5 className="EquivalentValues-title">{translate('sidebar_Equiv')}</h5> <h5 className="EquivalentValues-title">{translate('SIDEBAR_EQUIV')}</h5>
<Select <Select
name="equivalentValues" name="equivalentValues"
// TODO: Update type // TODO: Update type
@ -183,13 +183,11 @@ class EquivalentValues extends React.Component<Props, State> {
{isOffline ? ( {isOffline ? (
<div className="EquivalentValues-offline well well-sm"> <div className="EquivalentValues-offline well well-sm">
Equivalent values are unavailable offline {translate('EQUIV_VALS_OFFLINE')}
</div> </div>
) : network.isTestnet ? ( ) : network.isTestnet ? (
<div className="text-center"> <div className="text-center">
<h5 style={{ color: 'red' }}> <h5 style={{ color: 'red' }}>{translate('EQUIV_VALS_TESTNET')}</h5>
On test network, equivalent values will not be displayed.
</h5>
</div> </div>
) : ratesError ? ( ) : ratesError ? (
<h5>{ratesError}</h5> <h5>{ratesError}</h5>
@ -228,7 +226,7 @@ class EquivalentValues extends React.Component<Props, State> {
)} )}
</React.Fragment> </React.Fragment>
) : ( ) : (
<p>Sorry, equivalent values are not supported for this unit.</p> <p>{translate('EQUIV_VALS_UNSUPPORTED_UNIT')}</p>
)} )}
</div> </div>
)} )}

View File

@ -1,7 +1,7 @@
import React from 'react'; import React from 'react';
import { HELP_ARTICLE } from 'config'; import { HELP_ARTICLE } from 'config';
import { isPositiveIntegerOrZero, isValidETHAddress } from 'libs/validators'; import { isPositiveIntegerOrZero, isValidETHAddress } from 'libs/validators';
import translate from 'translations'; import translate, { translateRaw } from 'translations';
import { HelpLink, Input } from 'components/ui'; import { HelpLink, Input } from 'components/ui';
import './AddCustomTokenForm.scss'; import './AddCustomTokenForm.scss';
import { Token } from 'types/network'; import { Token } from 'types/network';
@ -47,17 +47,17 @@ export default class AddCustomTokenForm extends React.PureComponent<Props, State
{ {
name: 'symbol', name: 'symbol',
value: symbol, value: symbol,
label: translate('TOKEN_Symbol') label: translateRaw('TOKEN_SYMBOL')
}, },
{ {
name: 'address', name: 'address',
value: address, value: address,
label: translate('TOKEN_Addr') label: translateRaw('TOKEN_ADDR')
}, },
{ {
name: 'decimal', name: 'decimal',
value: decimal, value: decimal,
label: translate('TOKEN_Dec') label: translateRaw('TOKEN_DEC')
} }
]; ];
@ -84,20 +84,20 @@ export default class AddCustomTokenForm extends React.PureComponent<Props, State
})} })}
<HelpLink article={HELP_ARTICLE.ADDING_NEW_TOKENS} className="AddCustom-buttons-help"> <HelpLink article={HELP_ARTICLE.ADDING_NEW_TOKENS} className="AddCustom-buttons-help">
{translate('Need help? Learn how to add custom tokens.')} {translate('ADD_CUSTOM_TKN_HELP')}
</HelpLink> </HelpLink>
<div className="AddCustom-buttons"> <div className="AddCustom-buttons">
<button <button
className="AddCustom-buttons-btn btn btn-sm btn-default" className="AddCustom-buttons-btn btn btn-sm btn-default"
onClick={this.props.toggleForm} onClick={this.props.toggleForm}
> >
{translate('x_Cancel')} {translate('ACTION_2')}
</button> </button>
<button <button
className="AddCustom-buttons-btn btn btn-primary btn-sm" className="AddCustom-buttons-btn btn btn-primary btn-sm"
disabled={!this.isValid()} disabled={!this.isValid()}
> >
{translate('x_Save')} {translate('X_SAVE')}
</button> </button>
</div> </div>
</form> </form>

View File

@ -50,11 +50,9 @@ export default class TokenBalances extends React.PureComponent<Props, State> {
bottom = ( bottom = (
<div className="TokenBalances-buttons"> <div className="TokenBalances-buttons">
<button className="btn btn-primary btn-block" onClick={this.handleSetWalletTokens}> <button className="btn btn-primary btn-block" onClick={this.handleSetWalletTokens}>
<span>{translate('x_Save')}</span> <span>{translate('X_SAVE')}</span>
</button> </button>
<p className="TokenBalances-buttons-help"> <p className="TokenBalances-buttons-help">{translate('PROMPT_ADD_CUSTOM_TKN')}</p>
{translate('Missing tokens? You can add custom tokens next.')}
</p>
</div> </div>
); );
} else if (showCustomTokenForm) { } else if (showCustomTokenForm) {
@ -71,10 +69,10 @@ export default class TokenBalances extends React.PureComponent<Props, State> {
bottom = ( bottom = (
<div className="TokenBalances-buttons"> <div className="TokenBalances-buttons">
<button className="btn btn-default btn-xs" onClick={this.toggleShowCustomTokenForm}> <button className="btn btn-default btn-xs" onClick={this.toggleShowCustomTokenForm}>
<span>{translate('SEND_custom')}</span> <span>{translate('SEND_CUSTOM')}</span>
</button>{' '} </button>
<button className="btn btn-default btn-xs" onClick={this.props.scanWalletForTokens}> <button className="btn btn-default btn-xs" onClick={this.props.scanWalletForTokens}>
<span>Scan for New Tokens</span> <span>{translate('SCAN_TOKENS')}</span>
</button> </button>
</div> </div>
); );
@ -105,7 +103,7 @@ export default class TokenBalances extends React.PureComponent<Props, State> {
</tbody> </tbody>
</table> </table>
) : ( ) : (
<div className="well well-sm text-center">No tokens found</div> <div className="well well-sm text-center">{translate('SCAN_TOKENS_FAIL_NO_TOKENS')}</div>
)} )}
{bottom} {bottom}
</div> </div>

View File

@ -74,7 +74,7 @@ class TokenBalances extends React.Component<Props> {
className="TokenBalances-scan btn btn-primary btn-block" className="TokenBalances-scan btn btn-primary btn-block"
onClick={this.scanWalletForTokens} onClick={this.scanWalletForTokens}
> >
{translate('Scan for my Tokens')} {translate('SCAN_TOKENS')}
</button> </button>
); );
} else { } else {
@ -95,7 +95,7 @@ class TokenBalances extends React.Component<Props> {
return ( return (
<section className="TokenBalances"> <section className="TokenBalances">
<h5 className="TokenBalances-title">{translate('sidebar_TokenBal')}</h5> <h5 className="TokenBalances-title">{translate('SIDEBAR_TOKENBAL')}</h5>
{content} {content}
</section> </section>
); );

View File

@ -7,6 +7,7 @@ import { AppState } from 'reducers';
import './Body.scss'; import './Body.scss';
import { getNetworkConfig } from 'selectors/config'; import { getNetworkConfig } from 'selectors/config';
import { NetworkConfig } from 'types/network'; import { NetworkConfig } from 'types/network';
import translate from 'translations';
interface State { interface State {
showDetails: boolean; showDetails: boolean;
@ -43,7 +44,7 @@ class BodyClass extends React.Component<StateProps, State> {
}`} }`}
onClick={this.toggleDetails} onClick={this.toggleDetails}
> >
Details {translate('ACTION_8')}
</button> </button>
{showDetails && <Details />} {showDetails && <Details />}
</div> </div>

View File

@ -9,6 +9,7 @@ import { SerializedTransaction } from 'components/renderCbs';
import { AppState } from 'reducers'; import { AppState } from 'reducers';
import { getFrom, getUnit, isEtherTransaction } from 'selectors/transaction'; import { getFrom, getUnit, isEtherTransaction } from 'selectors/transaction';
import { toChecksumAddress } from 'ethereumjs-util'; import { toChecksumAddress } from 'ethereumjs-util';
import translate from 'translations';
interface StateProps { interface StateProps {
from: AppState['transaction']['meta']['from']; from: AppState['transaction']['meta']['from'];
@ -35,7 +36,7 @@ class AddressesClass extends Component<StateProps> {
<Identicon className="tx-modal-address-from-icon" size={size} address={from} /> <Identicon className="tx-modal-address-from-icon" size={size} address={from} />
)} )}
<div className="tx-modal-address-from-content"> <div className="tx-modal-address-from-content">
<h5 className="tx-modal-address-from-title">From </h5> <h5 className="tx-modal-address-from-title">{translate('CONFIRM_TX_FROM')} </h5>
<h5 className="tx-modal-address-from-address small">{from}</h5> <h5 className="tx-modal-address-from-address small">{from}</h5>
</div> </div>
</div> </div>
@ -45,7 +46,9 @@ class AddressesClass extends Component<StateProps> {
<img src={arrow} alt="arrow" /> <img src={arrow} alt="arrow" />
</div> </div>
<div className="tx-modal-address-tkn-contract-content"> <div className="tx-modal-address-tkn-contract-content">
<p className="tx-modal-address-tkn-contract-title">via the {unit} contract</p> <p className="tx-modal-address-tkn-contract-title">
{translate('CONFIRM_TX_VIA_CONTRACT', { unit })}
</p>
<a <a
className="small tx-modal-address-tkn-contract-link" className="small tx-modal-address-tkn-contract-link"
href={ETHAddressExplorer(to)} href={ETHAddressExplorer(to)}
@ -62,7 +65,7 @@ class AddressesClass extends Component<StateProps> {
address={toFormatted} address={toFormatted}
/> />
<div className="tx-modal-address-to-content"> <div className="tx-modal-address-to-content">
<h5 className="tx-modal-address-to-title">To </h5> <h5 className="tx-modal-address-to-title">{translate('CONFIRM_TX_TO')} </h5>
<h5 className="small tx-modal-address-to-address">{toFormatted}</h5> <h5 className="small tx-modal-address-to-address">{toFormatted}</h5>
</div> </div>
</div> </div>

View File

@ -7,6 +7,7 @@ import { SerializedTxParams, getParamsFromSerializedTx } from 'selectors/transac
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import { getNetworkConfig } from 'selectors/config'; import { getNetworkConfig } from 'selectors/config';
import { NetworkConfig } from 'types/network'; import { NetworkConfig } from 'types/network';
import translate from 'translations';
interface StateProps extends SerializedTxParams, AllUSDValues { interface StateProps extends SerializedTxParams, AllUSDValues {
network: NetworkConfig; network: NetworkConfig;
@ -32,7 +33,7 @@ class AmountsClass extends Component<StateProps> {
<table className="tx-modal-amount"> <table className="tx-modal-amount">
<tbody> <tbody>
<tr className="tx-modal-amount-send"> <tr className="tx-modal-amount-send">
<td>You'll Send</td> <td>{translate('CONFIRM_TX_SENDING')}</td>
<td> <td>
<UnitDisplay <UnitDisplay
value={currentValue} value={currentValue}
@ -54,7 +55,7 @@ class AmountsClass extends Component<StateProps> {
)} )}
</tr> </tr>
<tr className="tx-modal-amount-fee"> <tr className="tx-modal-amount-fee">
<td>Transaction Fee</td> <td>{translate('CONFIRM_TX_FEE')}</td>
<td> <td>
<UnitDisplay <UnitDisplay
value={fee} value={fee}
@ -77,7 +78,7 @@ class AmountsClass extends Component<StateProps> {
</tr> </tr>
{!isToken && ( {!isToken && (
<tr className="tx-modal-amount-total"> <tr className="tx-modal-amount-total">
<td>Total</td> <td>{translate('CONFIRM_TX_TOTAL')}</td>
<td> <td>
<UnitDisplay <UnitDisplay
value={total} value={total}

View File

@ -11,9 +11,9 @@ import {
TBroadcastWeb3TransactionRequested TBroadcastWeb3TransactionRequested
} from 'actions/transaction'; } from 'actions/transaction';
import { currentTransactionBroadcasting } from 'selectors/transaction'; import { currentTransactionBroadcasting } from 'selectors/transaction';
import { translateRaw } from 'translations';
import './ConfirmationModalTemplate.scss'; import './ConfirmationModalTemplate.scss';
import { AppState } from 'reducers'; import { AppState } from 'reducers';
import { translateRaw, translate } from 'translations';
interface DispatchProps { interface DispatchProps {
broadcastLocalTransactionRequested: TBroadcastLocalTransactionRequested; broadcastLocalTransactionRequested: TBroadcastLocalTransactionRequested;
@ -73,7 +73,7 @@ class ConfirmationModalTemplateClass extends React.Component<Props, State> {
const { timeToRead } = this.state; const { timeToRead } = this.state;
const buttonPrefix = timeToRead > 0 ? `(${timeToRead}) ` : ''; const buttonPrefix = timeToRead > 0 ? `(${timeToRead}) ` : '';
const defaultConfirmButton = { const defaultConfirmButton = {
text: buttonPrefix + translateRaw('SENDModal_Yes'), text: buttonPrefix + translateRaw('ACTION_11'),
type: 'primary' as IButton['type'], type: 'primary' as IButton['type'],
disabled: timeToRead > 0, disabled: timeToRead > 0,
onClick: this.confirm onClick: this.confirm
@ -85,7 +85,7 @@ class ConfirmationModalTemplateClass extends React.Component<Props, State> {
timeLeft: timeToRead, timeLeft: timeToRead,
timePrefix: buttonPrefix, timePrefix: buttonPrefix,
timeLocked: defaultConfirmButton.disabled, timeLocked: defaultConfirmButton.disabled,
defaultText: translateRaw('SENDModal_Yes'), defaultText: translateRaw('ACTION_11'),
type: defaultConfirmButton.type type: defaultConfirmButton.type
}) })
: defaultConfirmButton; : defaultConfirmButton;
@ -93,7 +93,7 @@ class ConfirmationModalTemplateClass extends React.Component<Props, State> {
const buttons: IButton[] = [ const buttons: IButton[] = [
confirmButton, confirmButton,
{ {
text: translateRaw('SENDModal_No'), text: translate('ACTION_2'),
type: 'default', type: 'default',
onClick: onClose onClick: onClose
} }
@ -101,7 +101,7 @@ class ConfirmationModalTemplateClass extends React.Component<Props, State> {
return ( return (
<Modal <Modal
title="Confirm Transaction" title={translateRaw('CONFIRM_TX_MODAL_TITLE')}
buttons={buttons} buttons={buttons}
handleClose={onClose} handleClose={onClose}
disableButtons={transactionBroadcasting} disableButtons={transactionBroadcasting}

View File

@ -9,7 +9,7 @@ export const DataField: React.SFC<{}> = () => (
withProps={({ data: { raw }, dataExists, onChange, readOnly }) => ( withProps={({ data: { raw }, dataExists, onChange, readOnly }) => (
<div className="input-group-wrapper"> <div className="input-group-wrapper">
<label className="input-group"> <label className="input-group">
<div className="input-group-header">{translate('OFFLINE_Step2_Label_6')}</div> <div className="input-group-header">{translate('OFFLINE_STEP2_LABEL_6')}</div>
<Input <Input
className={dataExists ? 'is-valid' : 'is-invalid'} className={dataExists ? 'is-valid' : 'is-invalid'}
type="text" type="text"

View File

@ -14,7 +14,7 @@ const TransactionSucceeded = ({ txHash, blockExplorer }: TransactionSucceededPro
if (blockExplorer) { if (blockExplorer) {
verifyBtn = ( verifyBtn = (
<NewTabLink className="btn btn-xs" href={blockExplorer.txUrl(txHash)}> <NewTabLink className="btn btn-xs" href={blockExplorer.txUrl(txHash)}>
Verify Transaction on {blockExplorer.name} {translate('VERIFY_TX', { $block_explorer: blockExplorer.name })}
</NewTabLink> </NewTabLink>
); );
} }

View File

@ -3,6 +3,7 @@ import Modal, { IButton } from 'components/ui/Modal';
import { HelpLink } from 'components/ui'; import { HelpLink } from 'components/ui';
import { HELP_ARTICLE } from 'config'; import { HELP_ARTICLE } from 'config';
import './DisclaimerModal.scss'; import './DisclaimerModal.scss';
import translate from 'translations';
interface Props { interface Props {
isOpen: boolean; isOpen: boolean;
@ -10,7 +11,9 @@ interface Props {
} }
const DisclaimerModal: React.SFC<Props> = ({ isOpen, handleClose }) => { const DisclaimerModal: React.SFC<Props> = ({ isOpen, handleClose }) => {
const buttons: IButton[] = [{ text: 'Okay', type: 'default', onClick: handleClose }]; const buttons: IButton[] = [
{ text: translate('ACTION_10'), type: 'default', onClick: handleClose }
];
return ( return (
<Modal isOpen={isOpen} title="Disclaimer" buttons={buttons} handleClose={handleClose}> <Modal isOpen={isOpen} title="Disclaimer" buttons={buttons} handleClose={handleClose}>
<p> <p>

View File

@ -1,5 +1,6 @@
import React from 'react'; import React from 'react';
import './PreFooter.scss'; import './PreFooter.scss';
import translate from 'translations';
interface Props { interface Props {
openModal(): void; openModal(): void;
@ -10,9 +11,8 @@ const PreFooter: React.SFC<Props> = ({ openModal }) => {
<section className="pre-footer"> <section className="pre-footer">
<div className="container"> <div className="container">
<p> <p>
MyCrypto.com does not hold your keys for you. We cannot access accounts, recover keys, {translate('PREFOOTER_WARNING')}{' '}
reset passwords, nor reverse transactions. Protect your keys & always check that you are <a onClick={openModal}>{translate('PREFOOTER_SECURITY_WARNING')}</a>
on correct URL. <a onClick={openModal}>You are responsible for your security.</a>
</p> </p>
</div> </div>
</section> </section>

View File

@ -14,6 +14,7 @@ import DisclaimerModal from './DisclaimerModal';
import { NewTabLink } from 'components/ui'; import { NewTabLink } from 'components/ui';
import OnboardModal from 'containers/OnboardModal'; import OnboardModal from 'containers/OnboardModal';
import './index.scss'; import './index.scss';
import { translateRaw } from 'translations';
const SocialMediaLink = ({ link, text }: Link) => { const SocialMediaLink = ({ link, text }: Link) => {
return ( return (
@ -58,39 +59,39 @@ const PRODUCT_INFO: Link[] = [
{ {
link: link:
'https://chrome.google.com/webstore/detail/etheraddresslookup/pdknmigbbbhmllnmgdfalmedcmcefdfn', 'https://chrome.google.com/webstore/detail/etheraddresslookup/pdknmigbbbhmllnmgdfalmedcmcefdfn',
text: 'Ether Address Lookup' text: translateRaw('ETHER_ADDRESS_LOOKUP')
}, },
{ {
link: link:
'https://chrome.google.com/webstore/detail/ethersecuritylookup/bhhfhgpgmifehjdghlbbijjaimhmcgnf', 'https://chrome.google.com/webstore/detail/ethersecuritylookup/bhhfhgpgmifehjdghlbbijjaimhmcgnf',
text: 'Ether Security Lookup' text: translateRaw('ETHER_SECURITY_LOOKUP')
}, },
{ {
link: 'https://etherscamdb.info/', link: 'https://etherscamdb.info/',
text: 'EtherScamDB' text: translateRaw('ETHERSCAMDB')
}, },
{ {
link: 'https://www.mycrypto.com/helpers.html', link: 'https://www.mycrypto.com/helpers.html',
text: 'Helpers & ENS Debugging' text: translateRaw('FOOTER_HELP_AND_DEBUGGING')
}, },
{ {
link: 'mailto:press@mycrypto.com', link: 'mailto:press@mycrypto.com',
text: 'Press Inquiries' text: translateRaw('FOOTER_PRESS')
} }
]; ];
const AFFILIATES: Link[] = [ const AFFILIATES: Link[] = [
{ {
link: ledgerReferralURL, link: ledgerReferralURL,
text: 'Buy a Ledger Wallet' text: translateRaw('LEDGER_REFERAL_1')
}, },
{ {
link: trezorReferralURL, link: trezorReferralURL,
text: 'Buy a TREZOR' text: translateRaw('TREZOR_REFERAL')
}, },
{ {
link: ethercardReferralURL, link: ethercardReferralURL,
text: 'Get an ether.card' text: translateRaw('ETHERCARD_REFERAL')
} }
]; ];
@ -165,51 +166,52 @@ export default class Footer extends React.PureComponent<Props, State> {
<div className="Footer-about-links"> <div className="Footer-about-links">
<a href="https://mycrypto.com">MyCrypto.com</a> <a href="https://mycrypto.com">MyCrypto.com</a>
<NewTabLink href={knowledgeBaseURL}>Help & Support</NewTabLink> <NewTabLink href={knowledgeBaseURL}>{translateRaw('FOOTER_SUPPORT')}</NewTabLink>
<NewTabLink href="https://about.mycrypto.com">Our Team</NewTabLink> <NewTabLink href="https://about.mycrypto.com">
{translateRaw('FOOTER_TEAM')}
</NewTabLink>
</div> </div>
<p className="Footer-about-text"> <p className="Footer-about-text">{translateRaw('FOOTER_ABOUT')}</p>
MyCrypto is an open-source, client-side tool for generating Ether Wallets, handling
ERC-20 tokens, and interacting with the blockchain more easily. Developed by and for
the community since 2015, were focused on building awesome products that put the
power in peoples hands.
</p>
<div className="Footer-about-legal"> <div className="Footer-about-legal">
<div className="Footer-about-legal-text"> <div className="Footer-about-legal-text">
© {new Date().getFullYear()} MyCrypto, Inc. © {new Date().getFullYear()} MyCrypto, Inc.
</div> </div>
<div className="Footer-about-legal-text"> <div className="Footer-about-legal-text">
<a onClick={this.toggleModal}>Disclaimer</a> <a onClick={this.toggleModal}>{translateRaw('DISCLAIMER')}</a>
</div> </div>
<div className="Footer-about-legal-text">v{VERSION}</div> <div className="Footer-about-legal-text">v{VERSION}</div>
</div> </div>
</div> </div>
<div className="Footer-support Footer-section"> <div className="Footer-support Footer-section">
<h5 className="Footer-support-title">Support Us & Our Friends</h5> <h5 className="Footer-support-title">{translateRaw('FOOTER_AFFILIATE_TITLE')}</h5>
<div className="Footer-support-affiliates"> <div className="Footer-support-affiliates">
{AFFILIATES.map(link => ( {AFFILIATES.map((link, i) => (
<NewTabLink key={link.text} href={link.link}> <NewTabLink key={i} href={link.link}>
{link.text} {link.text}
</NewTabLink> </NewTabLink>
))} ))}
</div> </div>
<div className="Footer-support-donate"> <div className="Footer-support-donate">
<div className="Footer-support-donate-currency">Donate ETH</div> <div className="Footer-support-donate-currency">
{translateRaw('DONATE_CURRENCY', { $currency: 'ETH' })}
</div>
<div className="Footer-support-donate-address">{donationAddressMap.ETH}</div> <div className="Footer-support-donate-address">{donationAddressMap.ETH}</div>
</div> </div>
<div className="Footer-support-donate"> <div className="Footer-support-donate">
<div className="Footer-support-donate-currency">Donate BTC</div> <div className="Footer-support-donate-currency">
{translateRaw('DONATE_CURRENCY', { $currency: 'BTC' })}
</div>
<div className="Footer-support-donate-address">{donationAddressMap.BTC}</div> <div className="Footer-support-donate-address">{donationAddressMap.BTC}</div>
</div> </div>
<div className="Footer-support-friends"> <div className="Footer-support-friends">
{FRIENDS.map(link => ( {FRIENDS.map((link, i) => (
<NewTabLink key={link.text} href={link.link}> <NewTabLink key={i} href={link.link}>
{link.text} {link.text}
</NewTabLink> </NewTabLink>
))} ))}

View File

@ -17,14 +17,14 @@ export const GasLimitField: React.SFC<Props> = ({ customLabel, disabled }) => (
<div className="input-group-wrapper AdvancedGas-gas-price"> <div className="input-group-wrapper AdvancedGas-gas-price">
<label className="input-group"> <label className="input-group">
<div className="input-group-header"> <div className="input-group-header">
{customLabel ? customLabel : translate('TRANS_gas')} {customLabel ? customLabel : translate('TRANS_GAS')}
<div className="flex-spacer" /> <div className="flex-spacer" />
<InlineSpinner active={gasEstimationPending} text="Calculating" /> <InlineSpinner active={gasEstimationPending} text="Calculating" />
</div> </div>
<Input <Input
className={gasLimitValidator(raw) ? 'is-valid' : 'is-invalid'} className={gasLimitValidator(raw) ? 'is-valid' : 'is-invalid'}
type="number" type="number"
placeholder="e.g. 21000" placeholder="21000"
readOnly={!!readOnly} readOnly={!!readOnly}
value={raw} value={raw}
onChange={onChange} onChange={onChange}

View File

@ -55,14 +55,14 @@ export default class GenerateKeystoreModal extends React.Component<Props, State>
return ( return (
<Modal <Modal
title={translateRaw('Generate Keystore File')} title={translateRaw('GENERATE_KEYSTORE_ACTION')}
isOpen={this.props.isOpen} isOpen={this.props.isOpen}
handleClose={this.handleClose} handleClose={this.handleClose}
> >
<form className="GenKeystore" onSubmit={this.handleSubmit}> <form className="GenKeystore" onSubmit={this.handleSubmit}>
<div className="input-group-wrapper GenKeystore-field"> <div className="input-group-wrapper GenKeystore-field">
<label className="input-group input-group-inline"> <label className="input-group input-group-inline">
<div className="input-group-header">Private Key</div> <div className="input-group-header">{translate('X_PRIVKEY2')}</div>
<TogglablePassword <TogglablePassword
name="privateKey" name="privateKey"
value={privateKey} value={privateKey}
@ -75,12 +75,14 @@ export default class GenerateKeystoreModal extends React.Component<Props, State>
</div> </div>
<div className="input-group-wrapper GenKeystore-field"> <div className="input-group-wrapper GenKeystore-field">
<label className="input-group input-group-inline"> <label className="input-group input-group-inline">
<div className="input-group-header">Password</div> <div className="input-group-header">{translate('INPUT_PASSWORD_LABEL')}</div>
<TogglablePassword <TogglablePassword
name="password" name="password"
value={password} value={password}
onChange={this.handleInput} onChange={this.handleInput}
placeholder={translateRaw('Minimum 9 characters')} placeholder={translateRaw('INPUT_PASSWORD_PLACEHOLDER', {
$pass_length: MINIMUM_PASSWORD_LENGTH.toString()
})}
isValid={isPasswordValid} isValid={isPasswordValid}
/> />
</label> </label>
@ -91,24 +93,20 @@ export default class GenerateKeystoreModal extends React.Component<Props, State>
className="GenKeystore-button btn btn-primary btn-block" className="GenKeystore-button btn btn-primary btn-block"
disabled={!isPrivateKeyValid || !isPasswordValid} disabled={!isPrivateKeyValid || !isPasswordValid}
> >
{translate('Generate Keystore File')} {translate('GENERATE_KEYSTORE_ACTION')}
</button> </button>
) : hasError ? ( ) : hasError ? (
<p className="alert alert-danger"> <p className="alert alert-danger">{translate('GENERATE_KEYSTORE_FAILED')}</p>
Keystore generation failed or was invalid. In order to prevent loss of funds, we
cannot provide you with a keystore file that may be corrupted. Refresh the page or use
a different browser, and try again.
</p>
) : ( ) : (
<a <a
onClick={this.handleClose} onClick={this.handleClose}
href={keystoreFile.blob} href={keystoreFile.blob}
className="GenKeystore-button btn btn-success btn-block" className="GenKeystore-button btn btn-success btn-block"
aria-label={translateRaw('x_Keystore')} aria-label={translateRaw('X_KEYSTORE')}
aria-describedby={translateRaw('x_KeystoreDesc')} aria-describedby={translateRaw('X_KEYSTOREDESC')}
download={keystoreFile.filename} download={keystoreFile.filename}
> >
{translate('Download Keystore File')} {translate('ACTION_12')}
</a> </a>
)} )}
</form> </form>

View File

@ -6,7 +6,7 @@ export const GenerateTransaction: React.SFC<{}> = () => (
<GenerateTransactionFactory <GenerateTransactionFactory
withProps={({ disabled, isWeb3Wallet, onClick }) => ( withProps={({ disabled, isWeb3Wallet, onClick }) => (
<button disabled={disabled} className="btn btn-info btn-block" onClick={onClick}> <button disabled={disabled} className="btn btn-info btn-block" onClick={onClick}>
{isWeb3Wallet ? translate('SEND_generate') : translate('DEP_signtx')} {isWeb3Wallet ? translate('SEND_GENERATE') : translate('DEP_SIGNTX')}
</button> </button>
)} )}
/> />

View File

@ -84,7 +84,7 @@ class CustomNodeModal extends React.Component<Props, State> {
}, },
{ {
type: 'default', type: 'default',
text: translate('x_Cancel'), text: translate('ACTION_2'),
onClick: handleClose onClick: handleClose
} }
]; ];
@ -105,19 +105,18 @@ class CustomNodeModal extends React.Component<Props, State> {
handleClose={handleClose} handleClose={handleClose}
maxWidth={580} maxWidth={580}
> >
{isHttps && <div className="alert alert-warning small">{translate('NODE_Warning')}</div>} {isHttps && <div className="alert alert-warning small">{translate('NODE_WARNING')}</div>}
{conflictedNode && ( {conflictedNode && (
<div className="alert alert-warning small"> <div className="alert alert-warning small">
You already have a node called '{conflictedNode.name}' that matches this one, saving {translate('CUSTOM_NODE_CONFLICT', { conflictedNode: conflictedNode.name })}
this will overwrite it
</div> </div>
)} )}
<form className="CustomNodeModal"> <form className="CustomNodeModal">
<div className="flex-wrapper"> <div className="flex-wrapper">
<label className="col-sm-9 input-group flex-grow-1"> <label className="col-sm-9 input-group flex-grow-1">
<div className="input-group-header">Node Name</div> <div className="input-group-header">{translate('CUSTOM_NODE_NAME')}</div>
<Input <Input
className={`input-group-input ${this.state.name && invalids.name ? 'invalid' : ''}`} className={`input-group-input ${this.state.name && invalids.name ? 'invalid' : ''}`}
type="text" type="text"
@ -143,7 +142,7 @@ class CustomNodeModal extends React.Component<Props, State> {
{network === CUSTOM.value && ( {network === CUSTOM.value && (
<div className="flex-wrapper"> <div className="flex-wrapper">
<label className="col-sm-6 input-group input-group-inline"> <label className="col-sm-6 input-group input-group-inline">
<div className="input-group-header">Network Name</div> <div className="input-group-header">{translate('CUSTOM_NETWORK_NAME')}</div>
<Input <Input
className={`input-group-input ${ className={`input-group-input ${
this.state.customNetworkId && invalids.customNetworkId ? 'invalid' : '' this.state.customNetworkId && invalids.customNetworkId ? 'invalid' : ''
@ -155,7 +154,7 @@ class CustomNodeModal extends React.Component<Props, State> {
/> />
</label> </label>
<label className="col-sm-3 input-group input-group-inline"> <label className="col-sm-3 input-group input-group-inline">
<div className="input-group-header">Currency</div> <div className="input-group-header">{translate('CUSTOM_NETWORK_CURRENCY')}</div>
<Input <Input
className={`input-group-input ${ className={`input-group-input ${
this.state.customNetworkUnit && invalids.customNetworkUnit ? 'invalid' : '' this.state.customNetworkUnit && invalids.customNetworkUnit ? 'invalid' : ''
@ -167,7 +166,7 @@ class CustomNodeModal extends React.Component<Props, State> {
/> />
</label> </label>
<label className="col-sm-3 input-group input-group-inline"> <label className="col-sm-3 input-group input-group-inline">
<div className="input-group-header">Chain ID</div> <div className="input-group-header">{translate('CUSTOM_NETWORK_CHAIN_ID')}</div>
<Input <Input
className={`input-group-input ${ className={`input-group-input ${
this.state.customNetworkChainId && invalids.customNetworkChainId this.state.customNetworkChainId && invalids.customNetworkChainId
@ -184,7 +183,7 @@ class CustomNodeModal extends React.Component<Props, State> {
)} )}
<label className="input-group input-group-inline"> <label className="input-group input-group-inline">
<div className="input-group-header">URL</div> <div className="input-group-header">{translate('CUSTOM_NETWORK_URL')}</div>
<Input <Input
className={`input-group-input ${this.state.url && invalids.url ? 'invalid' : ''}`} className={`input-group-input ${this.state.url && invalids.url ? 'invalid' : ''}`}
type="text" type="text"
@ -202,13 +201,13 @@ class CustomNodeModal extends React.Component<Props, State> {
checked={this.state.hasAuth} checked={this.state.hasAuth}
onChange={() => this.setState({ hasAuth: !this.state.hasAuth })} onChange={() => this.setState({ hasAuth: !this.state.hasAuth })}
/> />
<span>HTTP Basic Authentication</span> <span>{translate('CUSTOM_NETWORK_HTTP_AUTH')}</span>
</label> </label>
{this.state.hasAuth && ( {this.state.hasAuth && (
<div className="flex-wrapper "> <div className="flex-wrapper ">
<label className="col-sm-6 input-group input-group-inline"> <label className="col-sm-6 input-group input-group-inline">
<div className="input-group-header">Username</div> <div className="input-group-header">{translate('INPUT_USERNAME_LABEL')}</div>
<Input <Input
className={`input-group-input ${ className={`input-group-input ${
this.state.username && invalids.username ? 'invalid' : '' this.state.username && invalids.username ? 'invalid' : ''
@ -219,7 +218,7 @@ class CustomNodeModal extends React.Component<Props, State> {
/> />
</label> </label>
<label className="col-sm-6 input-group input-group-inline"> <label className="col-sm-6 input-group input-group-inline">
<div className="input-group-header">Password</div> <div className="input-group-header">{translate('INPUT_PASSWORD_LABEL')}</div>
<Input <Input
className={`input-group-input ${ className={`input-group-input ${
this.state.password && invalids.password ? 'invalid' : '' this.state.password && invalids.password ? 'invalid' : ''

View File

@ -11,19 +11,19 @@ export interface TabLink {
const tabs: TabLink[] = [ const tabs: TabLink[] = [
{ {
name: 'Account View & Send', name: 'NAV_VIEW',
to: '/account' to: '/account'
}, },
{ {
name: 'NAV_GenerateWallet', name: 'NAV_GENERATEWALLET',
to: '/generate' to: '/generate'
}, },
{ {
name: 'NAV_Swap', name: 'NAV_SWAP',
to: '/swap' to: '/swap'
}, },
{ {
name: 'NAV_Contracts', name: 'NAV_CONTRACTS',
to: '/contracts' to: '/contracts'
}, },
{ {
@ -31,19 +31,19 @@ const tabs: TabLink[] = [
to: '/ens' to: '/ens'
}, },
{ {
name: 'Sign & Verify Message', name: 'NAV_SIGN',
to: '/sign-and-verify-message' to: '/sign-and-verify-message'
}, },
{ {
name: 'NAV_TxStatus', name: 'NAV_TXSTATUS',
to: '/tx-status' to: '/tx-status'
}, },
{ {
name: 'Broadcast Transaction', name: 'NAV_BROADCAST',
to: '/pushTx' to: '/pushTx'
}, },
{ {
name: 'NAV_Help', name: 'NAV_HELP',
to: `${knowledgeBaseURL}`, to: `${knowledgeBaseURL}`,
external: true external: true
} }

View File

@ -1,4 +1,4 @@
@import "common/sass/variables"; @import 'common/sass/variables';
.NavigationLink { .NavigationLink {
display: inline-block; display: inline-block;
@ -14,7 +14,7 @@
min-height: 2.75rem; min-height: 2.75rem;
&:after { &:after {
content: ""; content: '';
background: $brand-primary; background: $brand-primary;
height: 2px; height: 2px;
width: 100%; width: 100%;
@ -45,10 +45,10 @@
} }
} }
#NAV_Swap a:before { #NAV_SWAP a:before {
content:""; content: '';
display: inline-block; display: inline-block;
margin-top: -.1rem; margin-top: -0.1rem;
width: 1.3rem; width: 1.3rem;
height: 1.3rem; height: 1.3rem;
background-image: url('~assets/images/logo-shapeshift-no-text.svg'); background-image: url('~assets/images/logo-shapeshift-no-text.svg');

View File

@ -4,6 +4,7 @@ import { withRouter, RouteComponentProps } from 'react-router-dom';
import Modal, { IButton } from 'components/ui/Modal'; import Modal, { IButton } from 'components/ui/Modal';
import { AppState } from 'reducers'; import { AppState } from 'reducers';
import { resetWallet, TResetWallet } from 'actions/wallet'; import { resetWallet, TResetWallet } from 'actions/wallet';
import translate, { translateRaw } from 'translations';
interface Props extends RouteComponentProps<{}> { interface Props extends RouteComponentProps<{}> {
// State // State
@ -42,17 +43,17 @@ class LogOutPromptClass extends React.Component<Props, State> {
public render() { public render() {
const buttons: IButton[] = [ const buttons: IButton[] = [
{ text: 'Log Out', type: 'primary', onClick: this.onConfirm }, { text: translate('ACTION_7'), type: 'primary', onClick: this.onConfirm },
{ text: 'Cancel', type: 'default', onClick: this.onCancel } { text: translate('ACTION_2'), type: 'default', onClick: this.onCancel }
]; ];
return ( return (
<Modal <Modal
title="You are about to log out" title={translateRaw('WALLET_LOGOUT_MODAL_TITLE')}
isOpen={this.state.openModal} isOpen={this.state.openModal}
handleClose={this.onCancel} handleClose={this.onCancel}
buttons={buttons} buttons={buttons}
> >
<p>Leaving this page will log you out. Are you sure you want to continue?</p> <p>{translate('WALLET_LOGOUT_MODAL_DESC')}</p>
</Modal> </Modal>
); );
} }

View File

@ -35,7 +35,7 @@ class NonceField extends React.Component<Props> {
<div className="input-group-wrapper Nonce-label"> <div className="input-group-wrapper Nonce-label">
<label className="input-group"> <label className="input-group">
<div className="input-group-header"> <div className="input-group-header">
{translate('OFFLINE_Step2_Label_5')} {translate('OFFLINE_STEP2_LABEL_5')}
<Help <Help
size="x1" size="x1"
link="https://support.mycrypto.com/transactions/what-is-nonce.html" link="https://support.mycrypto.com/transactions/what-is-nonce.html"
@ -44,7 +44,7 @@ class NonceField extends React.Component<Props> {
<Input <Input
className={`Nonce-field-input ${!!value ? 'is-valid' : 'is-invalid'}`} className={`Nonce-field-input ${!!value ? 'is-valid' : 'is-invalid'}`}
type="number" type="number"
placeholder="e.g. 7" placeholder="7"
value={raw} value={raw}
readOnly={readOnly} readOnly={readOnly}
onChange={onChange} onChange={onChange}

View File

@ -1,8 +1,8 @@
import { PaperWallet } from 'components'; import { PaperWallet } from 'components';
import React from 'react'; import React from 'react';
import { translateRaw } from 'translations';
import printElement from 'utils/printElement'; import printElement from 'utils/printElement';
import { stripHexPrefix } from 'libs/values'; import { stripHexPrefix } from 'libs/values';
import translate, { translateRaw } from 'translations';
export const print = (address: string, privateKey: string) => () => export const print = (address: string, privateKey: string) => () =>
address && address &&
@ -38,13 +38,13 @@ const PrintableWallet: React.SFC<Props> = ({ address, privateKey }) => {
<PaperWallet address={address} privateKey={pkey} /> <PaperWallet address={address} privateKey={pkey} />
<a <a
role="button" role="button"
aria-label={translateRaw('x_Print')} aria-label={translateRaw('X_PRINT')}
aria-describedby="x_PrintDesc" aria-describedby="x_PrintDesc"
className="btn btn-lg btn-primary btn-block" className="btn btn-lg btn-primary btn-block"
onClick={print(address, pkey)} onClick={print(address, pkey)}
style={{ margin: '10px auto 0', maxWidth: '260px' }} style={{ margin: '10px auto 0', maxWidth: '260px' }}
> >
{translateRaw('x_Print')} {translate('X_PRINT')}
</a> </a>
</div> </div>
); );

View File

@ -12,11 +12,11 @@ export const SendButton: React.SFC<{
onlyTransactionParameters={!!onlyTransactionParameters} onlyTransactionParameters={!!onlyTransactionParameters}
toggleDisabled={toggleDisabled} toggleDisabled={toggleDisabled}
Modal={customModal ? customModal : ConfirmationModal} Modal={customModal ? customModal : ConfirmationModal}
withProps={({ disabled, onClick }) => ( withProps={({ disabled, onClick }: { disabled: boolean; onClick(): void }) => (
<div className="row form-group"> <div className="row form-group">
<div className="col-xs-12"> <div className="col-xs-12">
<button disabled={disabled} className="btn btn-primary btn-block" onClick={onClick}> <button disabled={disabled} className="btn btn-primary btn-block" onClick={onClick}>
{translate('SEND_trans')} {translate('SEND_TRANS')}
</button> </button>
</div> </div>
</div> </div>

View File

@ -49,7 +49,7 @@ class SendButtonFactoryClass extends Component<Props> {
// shows the json representation of the transaction // shows the json representation of the transaction
const leftTxCompare = serializedTransaction && ( const leftTxCompare = serializedTransaction && (
<div className={`col-sm-${columnSize}`}> <div className={`col-sm-${columnSize}`}>
<label>{walletType.isWeb3Wallet ? 'Transaction Parameters' : translate('SEND_raw')}</label> <label>{walletType.isWeb3Wallet ? 'Transaction Parameters' : translate('SEND_RAW')}</label>
<TextArea value={getStringifiedTx(serializedTransaction)} rows={4} readOnly={true} /> <TextArea value={getStringifiedTx(serializedTransaction)} rows={4} readOnly={true} />
</div> </div>
); );
@ -63,7 +63,7 @@ class SendButtonFactoryClass extends Component<Props> {
<label> <label>
{walletType.isWeb3Wallet {walletType.isWeb3Wallet
? 'Serialized Transaction Parameters' ? 'Serialized Transaction Parameters'
: translate('SEND_signed')} : translate('SEND_SIGNED')}
</label> </label>
<TextArea <TextArea
value={addHexPrefix(serializedTransaction.toString('hex'))} value={addHexPrefix(serializedTransaction.toString('hex'))}

View File

@ -27,7 +27,7 @@ class SendEverythingClass extends Component<Props> {
!readOnly ? ( !readOnly ? (
<span className="help-block"> <span className="help-block">
<a onClick={this.onSendEverything}> <a onClick={this.onSendEverything}>
<span className="">{translate('SEND_TransferTotal')}</span> <span>{translate('SEND_TRANSFERTOTAL')}</span>
</a> </a>
</span> </span>
) : null ) : null

View File

@ -3,6 +3,7 @@ import { connect } from 'react-redux';
import { AppState } from 'reducers'; import { AppState } from 'reducers';
import { signaturePending } from 'selectors/transaction'; import { signaturePending } from 'selectors/transaction';
import { Spinner } from 'components/ui'; import { Spinner } from 'components/ui';
import translate from 'translations';
interface StateProps { interface StateProps {
isSignaturePending: boolean; isSignaturePending: boolean;
isHardwareWallet: boolean; isHardwareWallet: boolean;
@ -15,7 +16,7 @@ class SigningStatusClass extends Component<StateProps> {
const HWWalletPrompt: React.SFC<{}> = _ => const HWWalletPrompt: React.SFC<{}> = _ =>
isHardwareWallet ? ( isHardwareWallet ? (
<p> <p>
<b>Confirm transaction on hardware wallet</b> <b>{translate('CONFIRM_HARDWARE_WALLET_TRANSACTION')}</b>
</p> </p>
) : null; ) : null;

View File

@ -1,6 +1,5 @@
import React from 'react'; import React from 'react';
import BN from 'bn.js'; import BN from 'bn.js';
import { translateRaw } from 'translations';
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import { import {
inputGasPrice, inputGasPrice,
@ -22,6 +21,7 @@ import AdvancedGas, { AdvancedOptions } from './components/AdvancedGas';
import './TXMetaDataPanel.scss'; import './TXMetaDataPanel.scss';
import { getGasPrice } from 'selectors/transaction'; import { getGasPrice } from 'selectors/transaction';
import { NetworkConfig } from 'types/network'; import { NetworkConfig } from 'types/network';
import { translateRaw } from 'translations';
type SliderStates = 'simple' | 'advanced'; type SliderStates = 'simple' | 'advanced';
@ -114,8 +114,8 @@ class TXMetaDataPanel extends React.Component<Props, State> {
<div className="help-block"> <div className="help-block">
<a className="Gas-toggle" onClick={this.toggleAdvanced}> <a className="Gas-toggle" onClick={this.toggleAdvanced}>
{showAdvanced {showAdvanced
? `- ${translateRaw('Back to simple')}` ? `- ${translateRaw('TRANS_SIMPLE')}`
: `+ ${translateRaw('Advanced Settings')}`} : `+ ${translateRaw('TRANS_ADVANCED')}`}
</a> </a>
</div> </div>
)} )}

View File

@ -1,5 +1,5 @@
import React from 'react'; import React from 'react';
import translate, { translateRaw } from 'translations'; import { translateRaw } from 'translations';
import FeeSummary from './FeeSummary'; import FeeSummary from './FeeSummary';
import './AdvancedGas.scss'; import './AdvancedGas.scss';
import { TToggleAutoGasLimit, toggleAutoGasLimit } from 'actions/config'; import { TToggleAutoGasLimit, toggleAutoGasLimit } from 'actions/config';
@ -74,7 +74,7 @@ class AdvancedGas extends React.Component<Props, State> {
<div className="input-group-wrapper AdvancedGas-gas-price"> <div className="input-group-wrapper AdvancedGas-gas-price">
<label className="input-group"> <label className="input-group">
<div className="input-group-header"> <div className="input-group-header">
{translate('OFFLINE_Step2_Label_3')} (gwei) {translateRaw('OFFLINE_STEP2_LABEL_3')} (gwei)
</div> </div>
<Input <Input
className={!!gasPrice.raw && !validGasPrice ? 'is-invalid' : ''} className={!!gasPrice.raw && !validGasPrice ? 'is-invalid' : ''}
@ -89,7 +89,7 @@ class AdvancedGas extends React.Component<Props, State> {
{gasLimitField && ( {gasLimitField && (
<div className="AdvancedGas-gas-limit"> <div className="AdvancedGas-gas-limit">
<GasLimitField customLabel={translateRaw('OFFLINE_Step2_Label_4')} /> <GasLimitField customLabel={translateRaw('OFFLINE_STEP2_LABEL_4')} />
</div> </div>
)} )}
{nonceField && ( {nonceField && (

View File

@ -1,6 +1,6 @@
import React from 'react'; import React from 'react';
import Slider, { createSliderWithTooltip } from 'rc-slider'; import Slider, { createSliderWithTooltip } from 'rc-slider';
import translate, { translateRaw } from 'translations'; import translate from 'translations';
import FeeSummary from './FeeSummary'; import FeeSummary from './FeeSummary';
import './SimpleGas.scss'; import './SimpleGas.scss';
import { AppState } from 'reducers'; import { AppState } from 'reducers';
@ -80,7 +80,7 @@ class SimpleGas extends React.Component<Props> {
<div className="SimpleGas row form-group"> <div className="SimpleGas row form-group">
<div className="SimpleGas-title"> <div className="SimpleGas-title">
<div className="flex-wrapper"> <div className="flex-wrapper">
<label>{translateRaw('Transaction Fee')} </label> <label>{translate('CONFIRM_TX_FEE')} </label>
<div className="flex-spacer" /> <div className="flex-spacer" />
<InlineSpinner active={noncePending || gasLimitPending} text="Calculating" /> <InlineSpinner active={noncePending || gasLimitPending} text="Calculating" />
</div> </div>
@ -108,8 +108,8 @@ class SimpleGas extends React.Component<Props> {
disabled={isGasEstimating} disabled={isGasEstimating}
/> />
<div className="SimpleGas-slider-labels"> <div className="SimpleGas-slider-labels">
<span>{translate('Cheap')}</span> <span>{translate('TX_FEE_SCALE_LEFT')}</span>
<span>{translate('Fast')}</span> <span>{translate('TX_FEE_SCALE_RIGHT')}</span>
</div> </div>
</div> </div>
<FeeSummary <FeeSummary

View File

@ -17,7 +17,6 @@ interface Props {
toggleAriaLabel?: string; toggleAriaLabel?: string;
isValid?: boolean; isValid?: boolean;
isVisible?: boolean; isVisible?: boolean;
validity?: 'valid' | 'invalid' | 'semivalid';
readOnly?: boolean; readOnly?: boolean;
// Textarea-only props // Textarea-only props
@ -56,7 +55,6 @@ export default class TogglablePassword extends React.PureComponent<Props, State>
disabled, disabled,
ariaLabel, ariaLabel,
toggleAriaLabel, toggleAriaLabel,
validity,
isTextareaWhenVisible, isTextareaWhenVisible,
isValid, isValid,
onChange, onChange,
@ -68,10 +66,10 @@ export default class TogglablePassword extends React.PureComponent<Props, State>
const { isVisible } = this.state; const { isVisible } = this.state;
return ( return (
<div className={`TogglablePassword input-group input-group-inline ${className}`}> <div className={`TogglablePassword input-group input-group-inline`}>
{isTextareaWhenVisible && isVisible ? ( {isTextareaWhenVisible && isVisible ? (
<TextArea <TextArea
className={validity || !isValid ? 'invalid' : ''} className={`${className} ${!isValid ? 'invalid' : ''}`}
value={value} value={value}
name={name} name={name}
disabled={disabled} disabled={disabled}
@ -90,7 +88,7 @@ export default class TogglablePassword extends React.PureComponent<Props, State>
name={name} name={name}
disabled={disabled} disabled={disabled}
type={isVisible ? 'text' : 'password'} type={isVisible ? 'text' : 'password'}
className={`${validity || !isValid ? 'invalid' : ''} border-rad-right-0`} className={`${className} ${!isValid ? 'invalid' : ''} border-rad-right-0`}
placeholder={placeholder} placeholder={placeholder}
onChange={onChange} onChange={onChange}
onFocus={onFocus} onFocus={onFocus}

View File

@ -71,7 +71,7 @@ const TransactionDataTable: React.SFC<Props> = ({ data, receipt, network }) => {
const rows: TableRow[] = [ const rows: TableRow[] = [
{ {
label: 'Status', label: translate('TX_STATUS'),
data: ( data: (
<React.Fragment> <React.Fragment>
<strong className={`TxData-row-data-status is-${statusType}`}>{statusMsg}</strong> <strong className={`TxData-row-data-status is-${statusType}`}>{statusMsg}</strong>
@ -86,15 +86,15 @@ const TransactionDataTable: React.SFC<Props> = ({ data, receipt, network }) => {
) )
}, },
{ {
label: translate('x_TxHash'), label: translate('X_TXHASH'),
data: <MaybeLink href={explorer.tx}>{data.hash}</MaybeLink> data: <MaybeLink href={explorer.tx}>{data.hash}</MaybeLink>
}, },
{ {
label: 'Block Number', label: translate('TX_BLOCK_NUMB'),
data: receipt && <MaybeLink href={explorer.block}>{receipt.blockNumber}</MaybeLink> data: receipt && <MaybeLink href={explorer.block}>{receipt.blockNumber}</MaybeLink>
}, },
{ {
label: translate('OFFLINE_Step1_Label_1'), label: translate('OFFLINE_STEP1_LABEL_1'),
data: ( data: (
<MaybeLink href={explorer.from}> <MaybeLink href={explorer.from}>
<Identicon address={data.from} size="26px" /> <Identicon address={data.from} size="26px" />
@ -103,7 +103,7 @@ const TransactionDataTable: React.SFC<Props> = ({ data, receipt, network }) => {
) )
}, },
{ {
label: translate('OFFLINE_Step2_Label_1'), label: translate('OFFLINE_STEP2_LABEL_1'),
data: ( data: (
<MaybeLink href={explorer.to}> <MaybeLink href={explorer.to}>
<Identicon address={data.to} size="26px" /> <Identicon address={data.to} size="26px" />
@ -112,23 +112,23 @@ const TransactionDataTable: React.SFC<Props> = ({ data, receipt, network }) => {
) )
}, },
{ {
label: translate('SEND_amount_short'), label: translate('SEND_AMOUNT_SHORT'),
data: <UnitDisplay value={data.value} unit="ether" symbol={network.unit} /> data: <UnitDisplay value={data.value} unit="ether" symbol={network.unit} />
}, },
{ {
label: translate('OFFLINE_Step2_Label_3'), label: translate('OFFLINE_STEP2_LABEL_3'),
data: <UnitDisplay value={data.gasPrice} unit="gwei" symbol="Gwei" /> data: <UnitDisplay value={data.gasPrice} unit="gwei" symbol="Gwei" />
}, },
{ {
label: translate('OFFLINE_Step2_Label_4'), label: translate('OFFLINE_STEP2_LABEL_4'),
data: <UnitDisplay value={data.gas} unit="wei" /> data: <UnitDisplay value={data.gas} unit="wei" />
}, },
{ {
label: 'Gas Used', label: translate('TX_GAS_USED'),
data: receipt && <UnitDisplay value={receipt.gasUsed} unit="wei" /> data: receipt && <UnitDisplay value={receipt.gasUsed} unit="wei" />
}, },
{ {
label: 'Transaction Fee', label: translate('CONFIRM_TX_FEE'),
data: receipt && ( data: receipt && (
<UnitDisplay <UnitDisplay
value={receipt.gasUsed.mul(data.gasPrice)} value={receipt.gasUsed.mul(data.gasPrice)}
@ -138,7 +138,7 @@ const TransactionDataTable: React.SFC<Props> = ({ data, receipt, network }) => {
) )
}, },
{ {
label: translate('New contract address'), label: translate('NEW_CONTRACT_ADDR'),
data: receipt && data: receipt &&
receipt.contractAddress && ( receipt.contractAddress && (
<MaybeLink href={explorer.contract}> <MaybeLink href={explorer.contract}>
@ -147,11 +147,11 @@ const TransactionDataTable: React.SFC<Props> = ({ data, receipt, network }) => {
) )
}, },
{ {
label: translate('OFFLINE_Step2_Label_5'), label: translate('OFFLINE_STEP2_LABEL_5'),
data: data.nonce data: data.nonce
}, },
{ {
label: translate('TRANS_data'), label: translate('TRANS_DATA'),
data: hasInputData ? <TextArea value={data.input} disabled={true} /> : null data: hasInputData ? <TextArea value={data.input} disabled={true} /> : null
} }
]; ];

View File

@ -44,7 +44,6 @@ class TransactionStatus extends React.Component<Props> {
if (tx && tx.data) { if (tx && tx.data) {
content = ( content = (
<React.Fragment> <React.Fragment>
<h2 className="TxStatus-title">Transaction Found</h2>
<div className="TxStatus-data"> <div className="TxStatus-data">
<TransactionDataTable network={network} data={tx.data} receipt={tx.receipt} /> <TransactionDataTable network={network} data={tx.data} receipt={tx.receipt} />
</div> </div>
@ -53,13 +52,13 @@ class TransactionStatus extends React.Component<Props> {
} else if (tx && tx.error) { } else if (tx && tx.error) {
content = ( content = (
<div className="TxStatus-error"> <div className="TxStatus-error">
<h2 className="TxStatus-error-title">{translate('tx_notFound')}</h2> <h2 className="TxStatus-error-title">{translate('TX_NOTFOUND')}</h2>
<p className="TxStatus-error-desc">{translate('tx_notFound_1')}</p> <p className="TxStatus-error-desc">{translate('TX_NOTFOUND_1')}</p>
<ul className="TxStatus-error-list"> <ul className="TxStatus-error-list">
<li>Make sure you copied the Transaction Hash correctly</li> <li>{translate('TX_NOTFOUND_5')}</li>
<li>{translate('tx_notFound_2')}</li> <li>{translate('TX_NOTFOUND_2')}</li>
<li>{translate('tx_notFound_3')}</li> <li>{translate('TX_NOTFOUND_3')}</li>
<li>{translate('tx_notFound_4')}</li> <li>{translate('TX_NOTFOUND_4')}</li>
</ul> </ul>
</div> </div>
); );

View File

@ -1,22 +1,20 @@
import React from 'react'; import React from 'react';
import Markdown from 'react-markdown'; import Markdown from 'react-markdown';
import { translateRaw } from 'translations';
interface Props { interface Props {
translationKey: string; source: string;
} }
const Translate = ({ translationKey }: Props) => { const TranslateMarkdown = ({ source }: Props) => {
const source = translateRaw(translationKey);
return ( return (
<Markdown <Markdown
escapeHtml={true} escapeHtml={true}
unwrapDisallowed={true} unwrapDisallowed={true}
allowedTypes={['link', 'emphasis', 'strong', 'code', 'root', 'inlineCode']} allowedTypes={['link', 'emphasis', 'strong', 'code', 'root', 'inlineCode']}
renderers={{ root: 'span' }} renderers={{ root: React.Fragment }}
source={source} source={source}
/> />
); );
}; };
export default Translate; export default TranslateMarkdown;

View File

@ -18,7 +18,7 @@ import {
TResetWallet TResetWallet
} from 'actions/wallet'; } from 'actions/wallet';
import { reset, TReset, ResetAction } from 'actions/transaction'; import { reset, TReset, ResetAction } from 'actions/transaction';
import translate from 'translations'; import translate, { translateRaw } from 'translations';
import { import {
KeystoreDecrypt, KeystoreDecrypt,
LedgerNanoSDecrypt, LedgerNanoSDecrypt,
@ -50,6 +50,7 @@ import MetamaskIcon from 'assets/images/wallets/metamask.svg';
import MistIcon from 'assets/images/wallets/mist.svg'; import MistIcon from 'assets/images/wallets/mist.svg';
import TrezorIcon from 'assets/images/wallets/trezor.svg'; import TrezorIcon from 'assets/images/wallets/trezor.svg';
import './WalletDecrypt.scss'; import './WalletDecrypt.scss';
import { withRouter, RouteComponentProps } from 'react-router';
interface OwnProps { interface OwnProps {
hidden?: boolean; hidden?: boolean;
@ -75,7 +76,7 @@ interface StateProps {
isPasswordPending: AppState['wallet']['isPasswordPending']; isPasswordPending: AppState['wallet']['isPasswordPending'];
} }
type Props = OwnProps & StateProps & DispatchProps; type Props = OwnProps & StateProps & DispatchProps & RouteComponentProps<{}>;
type UnlockParams = {} | PrivateKeyValue; type UnlockParams = {} | PrivateKeyValue;
interface State { interface State {
@ -92,6 +93,7 @@ interface BaseWalletInfo {
helpLink: string; helpLink: string;
isReadOnly?: boolean; isReadOnly?: boolean;
attemptUnlock?: boolean; attemptUnlock?: boolean;
redirect?: string;
} }
export interface SecureWalletInfo extends BaseWalletInfo { export interface SecureWalletInfo extends BaseWalletInfo {
@ -108,15 +110,15 @@ interface MiscWalletInfo extends InsecureWalletInfo {}
const WEB3_TYPES = { const WEB3_TYPES = {
CipherProvider: { CipherProvider: {
lid: 'x_Cipher', lid: 'X_CIPHER',
icon: CipherIcon icon: CipherIcon
}, },
MetamaskInpageProvider: { MetamaskInpageProvider: {
lid: 'x_MetaMask', lid: 'X_METAMASK',
icon: MetamaskIcon icon: MetamaskIcon
}, },
EthereumProvider: { EthereumProvider: {
lid: 'x_Mist', lid: 'X_MIST',
icon: MistIcon icon: MistIcon
} }
}; };
@ -133,311 +135,319 @@ const SECURE_WALLETS = Object.values(SecureWalletName);
const INSECURE_WALLETS = Object.values(InsecureWalletName); const INSECURE_WALLETS = Object.values(InsecureWalletName);
const MISC_WALLETS = Object.values(MiscWalletName); const MISC_WALLETS = Object.values(MiscWalletName);
export class WalletDecrypt extends Component<Props, State> { const WalletDecrypt = withRouter<Props>(
// https://github.com/Microsoft/TypeScript/issues/13042 class WalletDecryptClass extends Component<RouteComponentProps<{}> & Props, State> {
// index signature should become [key: Wallets] (from config) once typescript bug is fixed // https://github.com/Microsoft/TypeScript/issues/13042
public WALLETS: Wallets = { // index signature should become [key: Wallets] (from config) once typescript bug is fixed
[SecureWalletName.WEB3]: { public WALLETS: Wallets = {
lid: WEB3_TYPE && WEB3_TYPES[WEB3_TYPE] ? WEB3_TYPES[WEB3_TYPE].lid : 'x_Web3', [SecureWalletName.WEB3]: {
icon: WEB3_TYPE && WEB3_TYPES[WEB3_TYPE] && WEB3_TYPES[WEB3_TYPE].icon, lid: WEB3_TYPE && WEB3_TYPES[WEB3_TYPE] ? WEB3_TYPES[WEB3_TYPE].lid : 'X_WEB3',
description: 'ADD_Web3Desc', icon: WEB3_TYPE && WEB3_TYPES[WEB3_TYPE] && WEB3_TYPES[WEB3_TYPE].icon,
component: Web3Decrypt, description: 'ADD_WEB3DESC',
initialParams: {}, component: Web3Decrypt,
unlock: this.props.unlockWeb3, initialParams: {},
attemptUnlock: true, unlock: this.props.unlockWeb3,
helpLink: `${knowledgeBaseURL}/migration/moving-from-private-key-to-metamask` attemptUnlock: true,
}, helpLink: `${knowledgeBaseURL}/migration/moving-from-private-key-to-metamask`
[SecureWalletName.LEDGER_NANO_S]: {
lid: 'x_Ledger',
icon: LedgerIcon,
description: 'ADD_HardwareDesc',
component: LedgerNanoSDecrypt,
initialParams: {},
unlock: this.props.setWallet,
helpLink: 'https://support.ledgerwallet.com/hc/en-us/articles/115005200009'
},
[SecureWalletName.TREZOR]: {
lid: 'x_Trezor',
icon: TrezorIcon,
description: 'ADD_HardwareDesc',
component: TrezorDecrypt,
initialParams: {},
unlock: this.props.setWallet,
helpLink: 'https://doc.satoshilabs.com/trezor-apps/mew.html'
},
[InsecureWalletName.KEYSTORE_FILE]: {
lid: 'x_Keystore2',
example: 'UTC--2017-12-15T17-35-22.547Z--6be6e49e82425a5aa56396db03512f2cc10e95e8',
component: KeystoreDecrypt,
initialParams: {
file: '',
password: ''
}, },
unlock: this.props.unlockKeystore, [SecureWalletName.LEDGER_NANO_S]: {
helpLink: `${knowledgeBaseURL}/private-keys-passwords/difference-beween-private-key-and-keystore-file.html` lid: 'X_LEDGER',
}, icon: LedgerIcon,
[InsecureWalletName.MNEMONIC_PHRASE]: { description: 'ADD_HARDWAREDESC',
lid: 'x_Mnemonic', component: LedgerNanoSDecrypt,
example: 'brain surround have swap horror cheese file distinct', initialParams: {},
component: MnemonicDecrypt, unlock: this.props.setWallet,
initialParams: {}, helpLink: 'https://support.ledgerwallet.com/hc/en-us/articles/115005200009'
unlock: this.props.unlockMnemonic,
helpLink: `${knowledgeBaseURL}/private-keys-passwords/difference-beween-private-key-and-keystore-file.html`
},
[InsecureWalletName.PRIVATE_KEY]: {
lid: 'x_PrivKey2',
example: 'f1d0e0789c6d40f399ca90cc674b7858de4c719e0d5752a60d5d2f6baa45d4c9',
component: PrivateKeyDecrypt,
initialParams: {
key: '',
password: ''
}, },
unlock: this.props.unlockPrivateKey, [SecureWalletName.TREZOR]: {
helpLink: `${knowledgeBaseURL}/private-keys-passwords/difference-beween-private-key-and-keystore-file.html` lid: 'X_TREZOR',
}, icon: TrezorIcon,
[MiscWalletName.VIEW_ONLY]: { description: 'ADD_HARDWAREDESC',
lid: 'View Address', component: TrezorDecrypt,
example: donationAddressMap.ETH, initialParams: {},
component: ViewOnlyDecrypt, unlock: this.props.setWallet,
initialParams: {}, helpLink: 'https://doc.satoshilabs.com/trezor-apps/mew.html'
unlock: this.props.setWallet, },
helpLink: '', [InsecureWalletName.KEYSTORE_FILE]: {
isReadOnly: true lid: 'X_KEYSTORE2',
} example: 'UTC--2017-12-15T17-35-22.547Z--6be6e49e82425a5aa56396db03512f2cc10e95e8',
}; component: KeystoreDecrypt,
initialParams: {
file: '',
password: ''
},
unlock: this.props.unlockKeystore,
helpLink: `${knowledgeBaseURL}/private-keys-passwords/difference-beween-private-key-and-keystore-file.html`
},
[InsecureWalletName.MNEMONIC_PHRASE]: {
lid: 'X_MNEMONIC',
example: 'brain surround have swap horror cheese file distinct',
component: MnemonicDecrypt,
initialParams: {},
unlock: this.props.unlockMnemonic,
helpLink: `${knowledgeBaseURL}/private-keys-passwords/difference-beween-private-key-and-keystore-file.html`
},
[InsecureWalletName.PRIVATE_KEY]: {
lid: 'X_PRIVKEY2',
example: 'f1d0e0789c6d40f399ca90cc674b7858de4c719e0d5752a60d5d2f6baa45d4c9',
component: PrivateKeyDecrypt,
initialParams: {
key: '',
password: ''
},
unlock: this.props.unlockPrivateKey,
helpLink: `${knowledgeBaseURL}/private-keys-passwords/difference-beween-private-key-and-keystore-file.html`
},
[MiscWalletName.VIEW_ONLY]: {
lid: 'VIEW_ADDR',
example: donationAddressMap.ETH,
component: ViewOnlyDecrypt,
initialParams: {},
unlock: this.props.setWallet,
helpLink: '',
isReadOnly: true,
redirect: '/account/info'
}
};
public state: State = { public state: State = {
selectedWalletKey: null, selectedWalletKey: null,
value: null, value: null,
hasAcknowledgedInsecure: false hasAcknowledgedInsecure: false
}; };
public componentWillReceiveProps(nextProps: Props) { public componentWillReceiveProps(nextProps: Props) {
// Reset state when unlock is hidden / revealed // Reset state when unlock is hidden / revealed
if (nextProps.hidden !== this.props.hidden) { if (nextProps.hidden !== this.props.hidden) {
this.setState({ this.setState({
value: null, value: null,
selectedWalletKey: null selectedWalletKey: null
}); });
} }
}
public getSelectedWallet() {
const { selectedWalletKey } = this.state;
if (!selectedWalletKey) {
return null;
} }
return this.WALLETS[selectedWalletKey]; public getSelectedWallet() {
} const { selectedWalletKey } = this.state;
if (!selectedWalletKey) {
return null;
}
public getDecryptionComponent() { return this.WALLETS[selectedWalletKey];
const { selectedWalletKey, hasAcknowledgedInsecure } = this.state;
const selectedWallet = this.getSelectedWallet();
if (!selectedWalletKey || !selectedWallet) {
return null;
} }
if (INSECURE_WALLETS.includes(selectedWalletKey) && !hasAcknowledgedInsecure) { public getDecryptionComponent() {
const { selectedWalletKey, hasAcknowledgedInsecure } = this.state;
const selectedWallet = this.getSelectedWallet();
if (!selectedWalletKey || !selectedWallet) {
return null;
}
if (INSECURE_WALLETS.includes(selectedWalletKey) && !hasAcknowledgedInsecure) {
return (
<div className="WalletDecrypt-decrypt">
<InsecureWalletWarning
walletType={translate(selectedWallet.lid)}
onContinue={this.handleAcknowledgeInsecure}
onCancel={this.clearWalletChoice}
/>
</div>
);
}
return ( return (
<div className="WalletDecrypt-decrypt"> <div className="WalletDecrypt-decrypt">
<InsecureWalletWarning <button className="WalletDecrypt-decrypt-back" onClick={this.clearWalletChoice}>
walletType={translate(selectedWallet.lid)} <i className="fa fa-arrow-left" /> {translate('CHANGE_WALLET')}
onContinue={this.handleAcknowledgeInsecure} </button>
onCancel={this.clearWalletChoice} <h2 className="WalletDecrypt-decrypt-title">
/> {!selectedWallet.isReadOnly && 'Unlock your'} {translate(selectedWallet.lid)}
</h2>
<section className="WalletDecrypt-decrypt-form">
<selectedWallet.component
value={this.state.value}
onChange={this.onChange}
onUnlock={(value: any) => {
if (selectedWallet.redirect) {
this.props.history.push(selectedWallet.redirect);
}
this.onUnlock(value);
}}
showNotification={this.props.showNotification}
isWalletPending={
this.state.selectedWalletKey === InsecureWalletName.KEYSTORE_FILE
? this.props.isWalletPending
: undefined
}
isPasswordPending={
this.state.selectedWalletKey === InsecureWalletName.KEYSTORE_FILE
? this.props.isPasswordPending
: undefined
}
/>
</section>
</div> </div>
); );
} }
return ( public handleAcknowledgeInsecure = () => {
<div className="WalletDecrypt-decrypt"> this.setState({ hasAcknowledgedInsecure: true });
<button className="WalletDecrypt-decrypt-back" onClick={this.clearWalletChoice}> };
<i className="fa fa-arrow-left" /> {translate('Change Wallet')}
</button>
<h2 className="WalletDecrypt-decrypt-title">
{!selectedWallet.isReadOnly && 'Unlock your'} {translate(selectedWallet.lid)}
</h2>
<section className="WalletDecrypt-decrypt-form">
<selectedWallet.component
value={this.state.value}
onChange={this.onChange}
onUnlock={this.onUnlock}
showNotification={this.props.showNotification}
isWalletPending={
this.state.selectedWalletKey === InsecureWalletName.KEYSTORE_FILE
? this.props.isWalletPending
: undefined
}
isPasswordPending={
this.state.selectedWalletKey === InsecureWalletName.KEYSTORE_FILE
? this.props.isPasswordPending
: undefined
}
/>
</section>
</div>
);
}
public handleAcknowledgeInsecure = () => { public buildWalletOptions() {
this.setState({ hasAcknowledgedInsecure: true }); const { computedDisabledWallets } = this.props;
}; const { reasons } = computedDisabledWallets;
public buildWalletOptions() { return (
const { computedDisabledWallets } = this.props; <div className="WalletDecrypt-wallets">
const { reasons } = computedDisabledWallets; <h2 className="WalletDecrypt-wallets-title">{translate('DECRYPT_ACCESS')}</h2>
return ( <div className="WalletDecrypt-wallets-row">
<div className="WalletDecrypt-wallets"> {SECURE_WALLETS.map((walletType: SecureWalletName) => {
<h2 className="WalletDecrypt-wallets-title">{translate('decrypt_Access')}</h2> const wallet = this.WALLETS[walletType];
return (
<div className="WalletDecrypt-wallets-row"> <WalletButton
{SECURE_WALLETS.map((walletType: SecureWalletName) => { key={walletType}
const wallet = this.WALLETS[walletType]; name={translateRaw(wallet.lid)}
return ( description={translateRaw(wallet.description)}
<WalletButton icon={wallet.icon}
key={walletType} helpLink={wallet.helpLink}
name={translate(wallet.lid)} walletType={walletType}
description={translate(wallet.description)} isSecure={true}
icon={wallet.icon} isDisabled={this.isWalletDisabled(walletType)}
helpLink={wallet.helpLink} disableReason={reasons[walletType]}
walletType={walletType} onClick={this.handleWalletChoice}
isSecure={true} />
isDisabled={this.isWalletDisabled(walletType)} );
disableReason={reasons[walletType]} })}
onClick={this.handleWalletChoice}
/>
);
})}
</div>
<div className="WalletDecrypt-wallets-row">
{INSECURE_WALLETS.map((walletType: InsecureWalletName) => {
const wallet = this.WALLETS[walletType];
return (
<WalletButton
key={walletType}
name={translate(wallet.lid)}
example={wallet.example}
helpLink={wallet.helpLink}
walletType={walletType}
isSecure={false}
isDisabled={this.isWalletDisabled(walletType)}
disableReason={reasons[walletType]}
onClick={this.handleWalletChoice}
/>
);
})}
{MISC_WALLETS.map((walletType: MiscWalletName) => {
const wallet = this.WALLETS[walletType];
return (
<WalletButton
key={walletType}
name={translate(wallet.lid)}
example={wallet.example}
helpLink={wallet.helpLink}
walletType={walletType}
isReadOnly={true}
isDisabled={this.isWalletDisabled(walletType)}
disableReason={reasons[walletType]}
onClick={this.handleWalletChoice}
/>
);
})}
</div>
{this.props.showGenerateLink && (
<div className="WalletDecrypt-wallets-generate">
Dont have an account yet? <Link to="/generate">Click here to get one</Link>.
</div> </div>
)} <div className="WalletDecrypt-wallets-row">
</div> {INSECURE_WALLETS.map((walletType: InsecureWalletName) => {
); const wallet = this.WALLETS[walletType];
} return (
<WalletButton
key={walletType}
name={translateRaw(wallet.lid)}
example={wallet.example}
helpLink={wallet.helpLink}
walletType={walletType}
isSecure={false}
isDisabled={this.isWalletDisabled(walletType)}
disableReason={reasons[walletType]}
onClick={this.handleWalletChoice}
/>
);
})}
public handleWalletChoice = async (walletType: WalletName) => { {MISC_WALLETS.map((walletType: MiscWalletName) => {
const wallet = this.WALLETS[walletType]; const wallet = this.WALLETS[walletType];
return (
<WalletButton
key={walletType}
name={translateRaw(wallet.lid)}
example={wallet.example}
helpLink={wallet.helpLink}
walletType={walletType}
isReadOnly={true}
isDisabled={this.isWalletDisabled(walletType)}
disableReason={reasons[walletType]}
onClick={this.handleWalletChoice}
/>
);
})}
</div>
if (!wallet) { {this.props.showGenerateLink && (
return; <div className="WalletDecrypt-wallets-generate">
<Link to="/generate">{translate('DONT_HAVE_WALLET_PROMPT')}</Link>
</div>
)}
</div>
);
} }
let timeout = 0; public handleWalletChoice = async (walletType: WalletName) => {
const web3Available = await isWeb3NodeAvailable(); const wallet = this.WALLETS[walletType];
if (wallet.attemptUnlock && web3Available) {
// timeout is only the maximum wait time before secondary view is shown
// send view will be shown immediately on web3 resolve
timeout = 1000;
wallet.unlock();
}
window.setTimeout(() => { if (!wallet) {
return;
}
let timeout = 0;
const web3Available = await isWeb3NodeAvailable();
if (wallet.attemptUnlock && web3Available) {
// timeout is only the maximum wait time before secondary view is shown
// send view will be shown immediately on web3 resolve
timeout = 1000;
wallet.unlock();
}
window.setTimeout(() => {
this.setState({
selectedWalletKey: walletType,
value: wallet.initialParams,
hasAcknowledgedInsecure: false
});
}, timeout);
};
public clearWalletChoice = () => {
this.setState({ this.setState({
selectedWalletKey: walletType, selectedWalletKey: null,
value: wallet.initialParams, value: null,
hasAcknowledgedInsecure: false hasAcknowledgedInsecure: false
}); });
}, timeout); };
};
public clearWalletChoice = () => { public render() {
this.setState({ const { hidden } = this.props;
selectedWalletKey: null, const selectedWallet = this.getSelectedWallet();
value: null, const decryptionComponent = this.getDecryptionComponent();
hasAcknowledgedInsecure: false return (
}); <div>
}; {!hidden && (
<article className="Tab-content-pane">
public render() { <div className="WalletDecrypt">
const { hidden } = this.props; <TransitionGroup>
const selectedWallet = this.getSelectedWallet(); {decryptionComponent && selectedWallet ? (
const decryptionComponent = this.getDecryptionComponent(); <CSSTransition classNames="DecryptContent" timeout={500} key="decrypt">
return ( {decryptionComponent}
<div> </CSSTransition>
{!hidden && ( ) : (
<article className="Tab-content-pane"> <CSSTransition classNames="DecryptContent" timeout={500} key="wallets">
<div className="WalletDecrypt"> {this.buildWalletOptions()}
<TransitionGroup> </CSSTransition>
{decryptionComponent && selectedWallet ? ( )}
<CSSTransition classNames="DecryptContent" timeout={500} key="decrypt"> </TransitionGroup>
{decryptionComponent} </div>
</CSSTransition> </article>
) : ( )}
<CSSTransition classNames="DecryptContent" timeout={500} key="wallets"> </div>
{this.buildWalletOptions()} );
</CSSTransition>
)}
</TransitionGroup>
</div>
</article>
)}
</div>
);
}
public onChange = (value: UnlockParams) => {
this.setState({ value });
};
public onUnlock = (payload: any) => {
const { value, selectedWalletKey } = this.state;
if (!selectedWalletKey) {
return;
} }
// some components (TrezorDecrypt) don't take an onChange prop, and thus public onChange = (value: UnlockParams) => {
// this.state.value will remain unpopulated. in this case, we can expect this.setState({ value });
// the payload to contain the unlocked wallet info. };
const unlockValue = value && !isEmpty(value) ? value : payload;
this.WALLETS[selectedWalletKey].unlock(unlockValue);
this.props.resetTransactionState(this.props.resetIncludeExcludeProperties);
};
private isWalletDisabled = (walletKey: WalletName) => { public onUnlock = (payload: any) => {
return this.props.computedDisabledWallets.wallets.indexOf(walletKey) !== -1; const { value, selectedWalletKey } = this.state;
}; if (!selectedWalletKey) {
} return;
}
// some components (TrezorDecrypt) don't take an onChange prop, and thus
// this.state.value will remain unpopulated. in this case, we can expect
// the payload to contain the unlocked wallet info.
const unlockValue = value && !isEmpty(value) ? value : payload;
this.WALLETS[selectedWalletKey].unlock(unlockValue);
this.props.resetTransactionState(this.props.resetIncludeExcludeProperties);
};
private isWalletDisabled = (walletKey: WalletName) => {
return this.props.computedDisabledWallets.wallets.indexOf(walletKey) !== -1;
};
}
);
function mapStateToProps(state: AppState, ownProps: Props) { function mapStateToProps(state: AppState, ownProps: Props) {
const { disabledWallets } = ownProps; const { disabledWallets } = ownProps;
@ -460,7 +470,7 @@ function mapStateToProps(state: AppState, ownProps: Props) {
}; };
} }
export default connect<StateProps, DispatchProps>(mapStateToProps, { export default connect(mapStateToProps, {
unlockKeystore, unlockKeystore,
unlockMnemonic, unlockMnemonic,
unlockPrivateKey, unlockPrivateKey,
@ -469,4 +479,4 @@ export default connect<StateProps, DispatchProps>(mapStateToProps, {
resetWallet, resetWallet,
resetTransactionState: reset, resetTransactionState: reset,
showNotification showNotification
})(WalletDecrypt); })(WalletDecrypt) as React.ComponentClass<OwnProps>;

View File

@ -1,7 +1,7 @@
import React from 'react'; import React from 'react';
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import Select, { Option } from 'react-select'; import Select, { Option } from 'react-select';
import translate from 'translations'; import translate, { translateRaw } from 'translations';
import { import {
DeterministicWalletData, DeterministicWalletData,
getDeterministicWallets, getDeterministicWallets,
@ -101,13 +101,13 @@ class DeterministicWalletsModalClass extends React.PureComponent<Props, State> {
const buttons: IButton[] = [ const buttons: IButton[] = [
{ {
text: 'Unlock this Address', text: translate('ACTION_3'),
type: 'primary', type: 'primary',
onClick: this.handleConfirmAddress, onClick: this.handleConfirmAddress,
disabled: !selectedAddress disabled: !selectedAddress
}, },
{ {
text: 'Cancel', text: translate('ACTION_2'),
type: 'default', type: 'default',
onClick: onCancel onClick: onCancel
} }
@ -115,7 +115,7 @@ class DeterministicWalletsModalClass extends React.PureComponent<Props, State> {
return ( return (
<Modal <Modal
title={`Unlock your ${walletType || ''} Wallet`} title={translateRaw(`DECRYPT_PROMPT_UNLOCK_${walletType}`)}
isOpen={this.props.isOpen} isOpen={this.props.isOpen}
buttons={buttons} buttons={buttons}
handleClose={onCancel} handleClose={onCancel}
@ -125,7 +125,7 @@ class DeterministicWalletsModalClass extends React.PureComponent<Props, State> {
className="DWModal-path form-group-sm flex-wrapper" className="DWModal-path form-group-sm flex-wrapper"
onSubmit={this.handleSubmitCustomPath} onSubmit={this.handleSubmitCustomPath}
> >
<span className="DWModal-path-label">Addresses </span> <span className="DWModal-path-label">{translate('DECRYPT_DROPDOWN_LABEL')} </span>
<div className="DWModal-path-select"> <div className="DWModal-path-select">
<Select <Select
name="fieldDPath" name="fieldDPath"
@ -180,7 +180,7 @@ class DeterministicWalletsModalClass extends React.PureComponent<Props, State> {
))} ))}
</select> </select>
</td> </td>
<td>More</td> <td>{translate('ACTION_5')}</td>
</tr> </tr>
</thead> </thead>
<tbody>{wallets.map(wallet => this.renderWalletRow(wallet))}</tbody> <tbody>{wallets.map(wallet => this.renderWalletRow(wallet))}</tbody>
@ -192,13 +192,13 @@ class DeterministicWalletsModalClass extends React.PureComponent<Props, State> {
disabled={page === 0} disabled={page === 0}
onClick={this.prevPage} onClick={this.prevPage}
> >
Back {translate('ACTION_4')}
</button> </button>
<button <button
className="DWModal-addresses-nav-btn btn btn-sm btn-default" className="DWModal-addresses-nav-btn btn btn-sm btn-default"
onClick={this.nextPage} onClick={this.nextPage}
> >
More {translate('ACTION_5')}
</button> </button>
</div> </div>
</div> </div>

View File

@ -1,7 +1,8 @@
import React from 'react'; import React from 'react';
import { HelpLink } from 'components/ui';
import { HELP_ARTICLE } from 'config'; import { HELP_ARTICLE } from 'config';
import './InsecureWalletWarning.scss'; import './InsecureWalletWarning.scss';
import translate from 'translations';
import { knowledgeBaseURL } from 'config/data';
interface Props { interface Props {
walletType: string | React.ReactElement<string>; walletType: string | React.ReactElement<string>;
@ -43,15 +44,15 @@ export class InsecureWalletWarning extends React.Component<Props, State> {
const checkboxes: Checkbox[] = [ const checkboxes: Checkbox[] = [
{ {
name: 'hasAcknowledgedWallets', name: 'hasAcknowledgedWallets',
label: 'I acknowledge that I can and should use MetaMask or a Hardware Wallet' label: translate('INSECURE_WALLET_WARNING_1')
}, },
{ {
name: 'hasAcknowledgedDownload', name: 'hasAcknowledgedDownload',
label: 'I acknowledge that I can and should download and run MyCrypto locally' label: translate('INSECURE_WALLET_WARNING_2')
}, },
{ {
name: 'hasConfirmedSite', name: 'hasConfirmedSite',
label: 'I have checked the URL and SSL certificate to make sure this is the real MyCrypto' label: translate('INSECURE_WALLET_WARNING_3')
} }
]; ];
const canContinue = checkboxes.reduce( const canContinue = checkboxes.reduce(
@ -61,38 +62,31 @@ export class InsecureWalletWarning extends React.Component<Props, State> {
return ( return (
<div className="WalletWarning"> <div className="WalletWarning">
<h2 className="WalletWarning-title"> <h2 className="WalletWarning-title">{translate('INSECURE_WALLET_TYPE_TITLE')}</h2>
This is <u>not</u> a recommended way to access your wallet
</h2>
<p className="WalletWarning-desc"> <p className="WalletWarning-desc">
Entering your {walletType} on a website is <strong>dangerous</strong>. If our website is {translate('INSECURE_WALLET_TYPE_DESC', { $wallet_type: walletType as string })}
compromised, or you accidentally visit a phishing website, you could{' '}
<strong>lose all of your funds</strong>. Before you continue, please consider:
</p> </p>
<ul className="WalletWarning-bullets"> <ul className="WalletWarning-bullets">
<li> <li>
Using <HelpLink article={HELP_ARTICLE.MIGRATE_TO_METAMASK}>MetaMask</HelpLink> or a{' '} {translate('INSECURE_WALLET_RECOMMEND_1', {
<HelpLink article={HELP_ARTICLE.HARDWARE_WALLET_RECOMMENDATIONS}> $metamask_article: knowledgeBaseURL + '/' + HELP_ARTICLE.MIGRATE_TO_METAMASK,
Hardware Wallet $hardware_wallet_article:
</HelpLink>{' '} knowledgeBaseURL + '/' + HELP_ARTICLE.HARDWARE_WALLET_RECOMMENDATIONS
to access your wallet })}
</li> </li>
<li> <li>
<HelpLink article={HELP_ARTICLE.RUNNING_LOCALLY}> {translate('INSECURE_WALLET_RECOMMEND_2', {
Downloading MyCrypto and running it offline & locally $run_local_article: knowledgeBaseURL + '/' + HELP_ARTICLE.RUNNING_LOCALLY
</HelpLink> })}
</li> </li>
<li> <li>
Reading{' '} {translate('INSECURE_WALLET_RECOMMEND_3', {
<HelpLink article={HELP_ARTICLE.SECURING_YOUR_ETH}> $secure_your_eth_article: knowledgeBaseURL + '/' + HELP_ARTICLE.SECURING_YOUR_ETH
How to Protect Yourself and Your Funds })}
</HelpLink>
</li> </li>
</ul> </ul>
<p className="WalletWarning-check"> <p className="WalletWarning-check">
If you must use your {walletType} online, please double-check the URL & SSL certificate. {translate('WALLET_WARNING_CHECK', { $wallet_type: walletType as string })}
It should say <code>{'https://www.mycrypto.com'}</code>
& <code>MyCrypto, Inc (US)</code> in your URL bar.
</p> </p>
<div className="WalletWarning-checkboxes">{checkboxes.map(this.makeCheckbox)}</div> <div className="WalletWarning-checkboxes">{checkboxes.map(this.makeCheckbox)}</div>

View File

@ -52,7 +52,7 @@ export class KeystoreDecrypt extends PureComponent {
/> />
<label htmlFor="fselector" style={{ width: '100%' }}> <label htmlFor="fselector" style={{ width: '100%' }}>
<a className="btn btn-default btn-block" id="aria1" tabIndex={0} role="button"> <a className="btn btn-default btn-block" id="aria1" tabIndex={0} role="button">
{translate('ADD_Radio_2_short')} {translate('ADD_RADIO_2_SHORT')}
</a> </a>
</label> </label>
{isWalletPending ? <Spinner /> : ''} {isWalletPending ? <Spinner /> : ''}
@ -63,13 +63,13 @@ export class KeystoreDecrypt extends PureComponent {
value={password} value={password}
onChange={this.onPasswordChange} onChange={this.onPasswordChange}
onKeyDown={this.onKeyDown} onKeyDown={this.onKeyDown}
placeholder={translateRaw('x_Password')} placeholder={translateRaw('INPUT_PASSWORD_LABEL')}
type="password" type="password"
/> />
</div> </div>
<button className="btn btn-primary btn-block" disabled={unlockDisabled}> <button className="btn btn-primary btn-block" disabled={unlockDisabled}>
{translate('ADD_Label_6_short')} {translate('ADD_LABEL_6_SHORT')}
</button> </button>
</form> </form>
); );

View File

@ -1,6 +1,6 @@
import './LedgerNano.scss'; import './LedgerNano.scss';
import React, { PureComponent } from 'react'; import React, { PureComponent } from 'react';
import translate, { translateRaw } from 'translations'; import translate from 'translations';
import DeterministicWalletsModal from './DeterministicWalletsModal'; import DeterministicWalletsModal from './DeterministicWalletsModal';
import { LedgerWallet } from 'libs/wallet'; import { LedgerWallet } from 'libs/wallet';
import ledger from 'ledgerco'; import ledger from 'ledgerco';
@ -83,23 +83,22 @@ class LedgerNanoSDecryptClass extends PureComponent<Props, State> {
{isLoading ? ( {isLoading ? (
<div className="LedgerDecrypt-message"> <div className="LedgerDecrypt-message">
<Spinner light={true} /> <Spinner light={true} />
Unlocking... {translate('WALLET_UNLOCKING')}
</div> </div>
) : ( ) : (
translate('ADD_Ledger_scan') translate('ADD_LEDGER_SCAN')
)} )}
</button> </button>
<NewTabLink className="LedgerDecrypt-buy btn btn-sm btn-default" href={ledgerReferralURL}> <NewTabLink className="LedgerDecrypt-buy btn btn-sm btn-default" href={ledgerReferralURL}>
{translate('Dont have a Ledger? Order one now!')} {translate('LEDGER_REFERAL_2')}
</NewTabLink> </NewTabLink>
<div className={`LedgerDecrypt-error alert alert-danger ${showErr}`}>{error || '-'}</div> <div className={`LedgerDecrypt-error alert alert-danger ${showErr}`}>{error || '-'}</div>
<div className="LedgerDecrypt-help"> <div className="LedgerDecrypt-help">
Guide:{' '}
<NewTabLink href="https://support.ledgerwallet.com/hc/en-us/articles/115005200009"> <NewTabLink href="https://support.ledgerwallet.com/hc/en-us/articles/115005200009">
How to use MyCrypto with your Nano S {translate('HELP_ARTICLE_1')}
</NewTabLink> </NewTabLink>
</div> </div>
@ -112,7 +111,7 @@ class LedgerNanoSDecryptClass extends PureComponent<Props, State> {
onCancel={this.handleCancel} onCancel={this.handleCancel}
onConfirmAddress={this.handleUnlock} onConfirmAddress={this.handleUnlock}
onPathChange={this.handlePathChange} onPathChange={this.handlePathChange}
walletType={translateRaw('x_Ledger')} walletType={'LEDGER'}
/> />
</div> </div>
); );

View File

@ -55,7 +55,7 @@ class MnemonicDecryptClass extends PureComponent<Props, State> {
<TogglablePassword <TogglablePassword
value={phrase} value={phrase}
rows={4} rows={4}
placeholder={translateRaw('x_Mnemonic')} placeholder={translateRaw('X_MNEMONIC')}
isValid={isValidMnemonic} isValid={isValidMnemonic}
isTextareaWhenVisible={true} isTextareaWhenVisible={true}
onChange={this.onMnemonicChange} onChange={this.onMnemonicChange}
@ -63,11 +63,11 @@ class MnemonicDecryptClass extends PureComponent<Props, State> {
/> />
</div> </div>
<div className="form-group"> <div className="form-group">
<p>Password (optional):</p> <p>{translate('ADD_LABEL_8')}</p>
<Input <Input
value={pass} value={pass}
onChange={this.onPasswordChange} onChange={this.onPasswordChange}
placeholder={translateRaw('x_Password')} placeholder={translateRaw('INPUT_PASSWORD_LABEL')}
type="password" type="password"
/> />
</div> </div>
@ -78,7 +78,7 @@ class MnemonicDecryptClass extends PureComponent<Props, State> {
className="btn btn-primary btn-lg" className="btn btn-primary btn-lg"
disabled={!isValidMnemonic} disabled={!isValidMnemonic}
> >
{translate('Choose Address')} {translate('MNEMONIC_CHOOSE_ADDR')}
</button> </button>
</div> </div>
</div> </div>
@ -91,7 +91,7 @@ class MnemonicDecryptClass extends PureComponent<Props, State> {
onCancel={this.handleCancel} onCancel={this.handleCancel}
onConfirmAddress={this.handleUnlock} onConfirmAddress={this.handleUnlock}
onPathChange={this.handlePathChange} onPathChange={this.handlePathChange}
walletType={translateRaw('x_Mnemonic')} walletType={'MNEMONIC'}
/> />
</div> </div>
); );

View File

@ -59,7 +59,7 @@ export class PrivateKeyDecrypt extends PureComponent<Props> {
<TogglablePassword <TogglablePassword
value={key} value={key}
rows={4} rows={4}
placeholder={translateRaw('x_PrivKey2')} placeholder={translateRaw('X_PRIVKEY2')}
isValid={isValidPkey} isValid={isValidPkey}
onChange={this.onPkeyChange} onChange={this.onPkeyChange}
onEnter={this.props.onUnlock} onEnter={this.props.onUnlock}
@ -70,20 +70,20 @@ export class PrivateKeyDecrypt extends PureComponent<Props> {
isPassRequired && ( isPassRequired && (
<div className="input-group-wrapper"> <div className="input-group-wrapper">
<label className="input-group"> <label className="input-group">
<div className="input-group-header">{translate('ADD_Label_3')}</div> <div className="input-group-header">{translate('ADD_LABEL_3')}</div>
<Input <Input
className={`form-control ${password.length > 0 ? 'is-valid' : 'is-invalid'}`} className={`form-control ${password.length > 0 ? 'is-valid' : 'is-invalid'}`}
value={password} value={password}
onChange={this.onPasswordChange} onChange={this.onPasswordChange}
onKeyDown={this.onKeyDown} onKeyDown={this.onKeyDown}
placeholder={translateRaw('x_Password')} placeholder={translateRaw('INPUT_PASSWORD_LABEL')}
type="password" type="password"
/> />
</label> </label>
</div> </div>
)} )}
<button className="btn btn-block btn-primary" disabled={unlockDisabled}> <button className="btn btn-block btn-primary" disabled={unlockDisabled}>
{translate('ADD_Label_6_short')} {translate('ADD_LABEL_6_SHORT')}
</button> </button>
</form> </form>
); );

View File

@ -1,6 +1,6 @@
import { TrezorWallet, TREZOR_MINIMUM_FIRMWARE } from 'libs/wallet'; import { TrezorWallet, TREZOR_MINIMUM_FIRMWARE } from 'libs/wallet';
import React, { PureComponent } from 'react'; import React, { PureComponent } from 'react';
import translate, { translateRaw } from 'translations'; import translate from 'translations';
import TrezorConnect from 'vendor/trezor-connect'; import TrezorConnect from 'vendor/trezor-connect';
import DeterministicWalletsModal from './DeterministicWalletsModal'; import DeterministicWalletsModal from './DeterministicWalletsModal';
import './Trezor.scss'; import './Trezor.scss';
@ -63,7 +63,7 @@ class TrezorDecryptClass extends PureComponent<Props, State> {
Unlocking... Unlocking...
</div> </div>
) : ( ) : (
translate('ADD_Trezor_scan') translate('ADD_TREZOR_SCAN')
)} )}
</button> </button>
@ -74,7 +74,6 @@ class TrezorDecryptClass extends PureComponent<Props, State> {
<div className={`TrezorDecrypt-error alert alert-danger ${showErr}`}>{error || '-'}</div> <div className={`TrezorDecrypt-error alert alert-danger ${showErr}`}>{error || '-'}</div>
<div className="TrezorDecrypt-help"> <div className="TrezorDecrypt-help">
Guide:{' '}
<NewTabLink href="https://blog.trezor.io/trezor-integration-with-myetherwallet-3e217a652e08"> <NewTabLink href="https://blog.trezor.io/trezor-integration-with-myetherwallet-3e217a652e08">
How to use TREZOR with MyCrypto How to use TREZOR with MyCrypto
</NewTabLink> </NewTabLink>
@ -89,7 +88,7 @@ class TrezorDecryptClass extends PureComponent<Props, State> {
onCancel={this.handleCancel} onCancel={this.handleCancel}
onConfirmAddress={this.handleUnlock} onConfirmAddress={this.handleUnlock}
onPathChange={this.handlePathChange} onPathChange={this.handlePathChange}
walletType={translateRaw('x_Trezor')} walletType={'TREZOR'}
/> />
</div> </div>
); );

View File

@ -35,7 +35,7 @@ export class ViewOnlyDecrypt extends PureComponent<Props, State> {
/> />
<button className="btn btn-primary btn-block" disabled={!isValid}> <button className="btn btn-primary btn-block" disabled={!isValid}>
{translate('NAV_ViewWallet')} {translate('NAV_VIEWWALLET')}
</button> </button>
</form> </form>
</div> </div>

View File

@ -1,15 +1,15 @@
import React from 'react'; import React from 'react';
import classnames from 'classnames'; import classnames from 'classnames';
import { translateRaw, TranslateType } from 'translations';
import { NewTabLink, Tooltip } from 'components/ui'; import { NewTabLink, Tooltip } from 'components/ui';
import './WalletButton.scss'; import './WalletButton.scss';
import { WalletName } from 'config'; import { WalletName } from 'config';
import { translateRaw } from 'translations';
interface OwnProps { interface OwnProps {
name: TranslateType; name: string;
description?: TranslateType; description?: string;
example?: TranslateType; example?: string;
icon?: string; icon?: string;
helpLink: string; helpLink: string;
walletType: WalletName; walletType: WalletName;
@ -51,20 +51,20 @@ export class WalletButton extends React.PureComponent<Props> {
if (isReadOnly) { if (isReadOnly) {
icons.push({ icons.push({
icon: 'eye', icon: 'eye',
tooltip: translateRaw('You cannot send using address only'), tooltip: translateRaw('TOOLTIP_READ_ONLY_WALLET'),
arialabel: 'Read Only' arialabel: 'Read Only'
}); });
} else { } else {
if (isSecure) { if (isSecure) {
icons.push({ icons.push({
icon: 'shield', icon: 'shield',
tooltip: translateRaw('This wallet type is secure'), tooltip: translateRaw('TOOLTIP_SECURE_WALLET_TYPE'),
arialabel: 'Secure wallet type' arialabel: 'Secure wallet type'
}); });
} else { } else {
icons.push({ icons.push({
icon: 'exclamation-triangle', icon: 'exclamation-triangle',
tooltip: translateRaw('This wallet type is insecure'), tooltip: translateRaw('TOOLTIP_INSECURE_WALLET_TYPE'),
arialabel: 'Insecure wallet type' arialabel: 'Insecure wallet type'
}); });
} }
@ -72,7 +72,7 @@ export class WalletButton extends React.PureComponent<Props> {
if (helpLink) { if (helpLink) {
icons.push({ icons.push({
icon: 'question-circle', icon: 'question-circle',
tooltip: translateRaw('NAV_Help'), tooltip: translateRaw('TOOLTIP_MORE_INFO'),
href: helpLink, href: helpLink,
arialabel: 'More info' arialabel: 'More info'
}); });

View File

@ -11,14 +11,14 @@ export const Web3Decrypt: React.SFC<Props> = ({ onUnlock }) => (
<div className="Web3Decrypt"> <div className="Web3Decrypt">
<div> <div>
<button className="Web3Decrypt-decrypt btn btn-primary btn-lg btn-block" onClick={onUnlock}> <button className="Web3Decrypt-decrypt btn btn-primary btn-lg btn-block" onClick={onUnlock}>
{translate('ADD_MetaMask')} {translate('ADD_METAMASK')}
</button> </button>
</div> </div>
<div> <div>
<NewTabLink <NewTabLink
className="Web3Decrypt-install btn btn-sm btn-default btn-block" className="Web3Decrypt-install btn btn-sm btn-default btn-block"
content={translate('Download MetaMask')} content={translate('ACTION_13', { $thing: 'MetaMask' })}
href="https://chrome.google.com/webstore/detail/metamask/nkbihfbeogaeaoehlefnkodbefgpgknn?hl=en" href="https://chrome.google.com/webstore/detail/metamask/nkbihfbeogaeaoehlefnkodbefgpgknn?hl=en"
/> />
</div> </div>

View File

@ -9,7 +9,7 @@ type ButtonType = 'default' | 'primary' | 'success' | 'info' | 'warning' | 'dang
type ButtonSize = 'lg' | 'sm' | 'xs'; type ButtonSize = 'lg' | 'sm' | 'xs';
interface Props { interface Props {
text: React.ReactElement<any> | string; text: string;
loading?: boolean; loading?: boolean;
disabled?: boolean; disabled?: boolean;
loadingText?: string; loadingText?: string;

View File

@ -1,14 +1,14 @@
import React from 'react'; import React from 'react';
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import { AppState } from 'reducers'; import { AppState } from 'reducers';
import translate, { TranslateType } from 'translations'; import translate from 'translations';
import WalletDecrypt, { DisabledWallets } from 'components/WalletDecrypt'; import WalletDecrypt, { DisabledWallets } from 'components/WalletDecrypt';
import { IWallet } from 'libs/wallet/IWallet'; import { IWallet } from 'libs/wallet/IWallet';
import closeIcon from 'assets/images/close.svg'; import closeIcon from 'assets/images/close.svg';
import './UnlockHeader.scss'; import './UnlockHeader.scss';
interface Props { interface Props {
title: TranslateType; title: string;
wallet: IWallet; wallet: IWallet;
disabledWallets?: DisabledWallets; disabledWallets?: DisabledWallets;
showGenerateLink?: boolean; showGenerateLink?: boolean;
@ -44,7 +44,7 @@ export class UnlockHeader extends React.PureComponent<Props, State> {
> >
<span> <span>
<span className="hidden-xs UnlockHeader-open-text"> <span className="hidden-xs UnlockHeader-open-text">
{translate('Change Wallet')} {translate('CHANGE_WALLET')}
</span> </span>
<i className="fa fa-refresh" /> <i className="fa fa-refresh" />
</span> </span>

View File

@ -4,15 +4,15 @@ import OnboardSlide from './OnboardSlide';
import onboardIconFour from 'assets/images/onboarding/slide-04.svg'; import onboardIconFour from 'assets/images/onboarding/slide-04.svg';
const BlockchainSlide = () => { const BlockchainSlide = () => {
const header = translate('ONBOARD_blockchain_title'); const header = translate('ONBOARD_BLOCKCHAIN_TITLE');
const content = ( const content = (
<ul> <ul>
<li>{translate('ONBOARD_blockchain_content__1')}</li> <li>{translate('ONBOARD_BLOCKCHAIN_CONTENT__1')}</li>
<li>{translate('ONBOARD_blockchain_content__2')}</li> <li>{translate('ONBOARD_BLOCKCHAIN_CONTENT__2')}</li>
<li>{translate('ONBOARD_blockchain_content__3')}</li> <li>{translate('ONBOARD_BLOCKCHAIN_CONTENT__3')}</li>
<li>{translate('ONBOARD_blockchain_content__4')}</li> <li>{translate('ONBOARD_BLOCKCHAIN_CONTENT__4')}</li>
<li>{translate('ONBOARD_blockchain_content__5')}</li> <li>{translate('ONBOARD_BLOCKCHAIN_CONTENT__5')}</li>
<li>{translate('ONBOARD_blockchain_content__6')}</li> <li>{translate('ONBOARD_BLOCKCHAIN_CONTENT__6')}</li>
</ul> </ul>
); );
return ( return (

View File

@ -11,49 +11,49 @@ interface Props {
} }
const FinalSlide: React.SFC<Props> = ({ closeModal }) => { const FinalSlide: React.SFC<Props> = ({ closeModal }) => {
const header = translate('ONBOARD_final_title'); const header = translate('ONBOARD_FINAL_TITLE');
const subheader = translate('ONBOARD_final_subtitle'); const subheader = translate('ONBOARD_FINAL_SUBTITLE');
const content = ( const content = (
<ul> <ul>
<li> <li>
<HelpLink article={HELP_ARTICLE.HARDWARE_WALLET_RECOMMENDATIONS} className="strong"> <HelpLink article={HELP_ARTICLE.HARDWARE_WALLET_RECOMMENDATIONS} className="strong">
{translate('ONBOARD_final_content__2')} {translate('ONBOARD_FINAL_CONTENT__2')}
</HelpLink> </HelpLink>
</li> </li>
<li> <li>
<HelpLink article={HELP_ARTICLE.MIGRATE_TO_METAMASK} className="strong"> <HelpLink article={HELP_ARTICLE.MIGRATE_TO_METAMASK} className="strong">
{translate('ONBOARD_final_content__3')} {translate('ONBOARD_FINAL_CONTENT__3')}
</HelpLink> </HelpLink>
</li> </li>
<li> <li>
<HelpLink article={HELP_ARTICLE.RUNNING_LOCALLY} className="strong"> <HelpLink article={HELP_ARTICLE.RUNNING_LOCALLY} className="strong">
{translate('ONBOARD_final_content__4')} {translate('ONBOARD_FINAL_CONTENT__4')}
</HelpLink> </HelpLink>
</li> </li>
<li> <li>
<HelpLink article={HELP_ARTICLE.MIGRATE_TO_LEDGER} className="strong"> <HelpLink article={HELP_ARTICLE.MIGRATE_TO_LEDGER} className="strong">
{translate('ONBOARD_final_content__5')} {translate('ONBOARD_FINAL_CONTENT__5')}
</HelpLink> </HelpLink>
</li> </li>
<li> <li>
<HelpLink article={HELP_ARTICLE.SENDING_TO_TREZOR} className="strong"> <HelpLink article={HELP_ARTICLE.SENDING_TO_TREZOR} className="strong">
{translate('ONBOARD_final_content__6')} {translate('ONBOARD_FINAL_CONTENT__6')}
</HelpLink> </HelpLink>
</li> </li>
<li> <li>
<HelpLink article={HELP_ARTICLE.MIGRATE_TO_METAMASK} className="strong"> <HelpLink article={HELP_ARTICLE.MIGRATE_TO_METAMASK} className="strong">
{translate('ONBOARD_final_content__7')} {translate('ONBOARD_FINAL_CONTENT__7')}
</HelpLink> </HelpLink>
</li> </li>
<li> <li>
<HelpLink article={HELP_ARTICLE.HOME} className="strong"> <HelpLink article={HELP_ARTICLE.HOME} className="strong">
{translate('ONBOARD_final_content__8')} {translate('ONBOARD_FINAL_CONTENT__8')}
</HelpLink> </HelpLink>
</li> </li>
<li> <li>
<Link onClick={closeModal} to="/account" className="strong"> <Link onClick={closeModal} to="/account" className="strong">
<span> {translate('ONBOARD_final_content__9')}</span> <span> {translate('ONBOARD_FINAL_CONTENT__9')}</span>
</Link> </Link>
</li> </li>
</ul> </ul>

View File

@ -4,17 +4,17 @@ import OnboardSlide from './OnboardSlide';
import onboardIconThree from 'assets/images/onboarding/slide-03.svg'; import onboardIconThree from 'assets/images/onboarding/slide-03.svg';
const InterfaceSlide = () => { const InterfaceSlide = () => {
const header = translate('ONBOARD_interface_title'); const header = translate('ONBOARD_INTERFACE_TITLE');
const content = ( const content = (
<ul> <ul>
<li>{translate('ONBOARD_interface_content__1')}</li> <li>{translate('ONBOARD_INTERFACE_CONTENT__1')}</li>
<li>{translate('ONBOARD_interface_content__2')}</li> <li>{translate('ONBOARD_INTERFACE_CONTENT__2')}</li>
<li>{translate('ONBOARD_interface_content__3')}</li> <li>{translate('ONBOARD_INTERFACE_CONTENT__3')}</li>
<li>{translate('ONBOARD_interface_content__4')}</li> <li>{translate('ONBOARD_INTERFACE_CONTENT__4')}</li>
<li>{translate('ONBOARD_interface_content__5')}</li> <li>{translate('ONBOARD_INTERFACE_CONTENT__5')}</li>
<li>{translate('ONBOARD_interface_content__6')}</li> <li>{translate('ONBOARD_INTERFACE_CONTENT__6')}</li>
<li>{translate('ONBOARD_interface_content__7')}</li> <li>{translate('ONBOARD_INTERFACE_CONTENT__7')}</li>
</ul> </ul>
); );
return ( return (

View File

@ -4,15 +4,15 @@ import OnboardSlide from './OnboardSlide';
import onboardIconTwo from 'assets/images/onboarding/slide-02.svg'; import onboardIconTwo from 'assets/images/onboarding/slide-02.svg';
const NotABankSlide = () => { const NotABankSlide = () => {
const header = translate('ONBOARD_bank_title'); const header = translate('ONBOARD_BANK_TITLE');
const content = ( const content = (
<ul> <ul>
<li>{translate('ONBOARD_bank_content__1')}</li> <li>{translate('ONBOARD_BANK_CONTENT__1')}</li>
<li>{translate('ONBOARD_bank_content__2')}</li> <li>{translate('ONBOARD_BANK_CONTENT__2')}</li>
<li>{translate('ONBOARD_bank_content__3')}</li> <li>{translate('ONBOARD_BANK_CONTENT__3')}</li>
<li>{translate('ONBOARD_bank_content__4')}</li> <li>{translate('ONBOARD_BANK_CONTENT__4')}</li>
<li>{translate('ONBOARD_bank_content__5')}</li> <li>{translate('ONBOARD_BANK_CONTENT__5')}</li>
</ul> </ul>
); );

View File

@ -4,18 +4,18 @@ import OnboardSlide from './OnboardSlide';
import onboardIconSeven from 'assets/images/onboarding/slide-07.svg'; import onboardIconSeven from 'assets/images/onboarding/slide-07.svg';
const SecureSlideOne = () => { const SecureSlideOne = () => {
const header = translate('ONBOARD_secure_1_title'); const header = translate('ONBOARD_SECURE_1_TITLE');
const content = ( const content = (
<div> <div>
<p>{translate('ONBOARD_secure_1_content__1')}</p> <p>{translate('ONBOARD_SECURE_1_CONTENT__1')}</p>
<ul> <ul>
<li>{translate('ONBOARD_secure_1_content__2')}</li> <li>{translate('ONBOARD_SECURE_1_CONTENT__2')}</li>
<li>{translate('ONBOARD_secure_1_content__3')} </li> <li>{translate('ONBOARD_SECURE_1_CONTENT__3')}</li>
<li>{translate('ONBOARD_secure_1_content__4')}</li> <li>{translate('ONBOARD_SECURE_1_CONTENT__4')}</li>
<li>{translate('ONBOARD_secure_1_content__5')}</li> <li>{translate('ONBOARD_SECURE_1_CONTENT__5')}</li>
<li>{translate('ONBOARD_secure_1_content__6')}</li> <li>{translate('ONBOARD_SECURE_1_CONTENT__6')}</li>
<li>{translate('ONBOARD_secure_1_content__7')}</li> <li>{translate('ONBOARD_SECURE_1_CONTENT__7')}</li>
</ul> </ul>
</div> </div>
); );

View File

@ -8,19 +8,19 @@ interface Props {
} }
const SecureSlideThree: React.SFC<Props> = ({ site }) => { const SecureSlideThree: React.SFC<Props> = ({ site }) => {
const header = translate('ONBOARD_secure_3_title'); const header = translate('ONBOARD_SECURE_3_TITLE');
const subheader = translate('ONBOARD_secure_3_content__1'); const subheader = translate('ONBOARD_SECURE_3_CONTENT__1');
const content = ( const content = (
<div> <div>
<ul> <ul>
<li>{translate('ONBOARD_secure_3_content__2')}</li> <li>{translate('ONBOARD_SECURE_3_CONTENT__2')}</li>
<li>{translate('ONBOARD_secure_3_content__3')}</li> <li>{translate('ONBOARD_SECURE_3_CONTENT__3')}</li>
<li>{translate('ONBOARD_secure_3_content__4')}</li> <li>{translate('ONBOARD_SECURE_3_CONTENT__4')}</li>
<li>{translate('ONBOARD_secure_3_content__5')}</li> <li>{translate('ONBOARD_SECURE_3_CONTENT__5')}</li>
{site === 'cx' && <li>{translate('CX_Warning_1')}</li>} {site === 'cx' && <li>{translate('CX_WARNING_1')}</li>}
</ul> </ul>
<h5 className="text-center">{translate('ONBOARD_secure_3_content__6')} </h5> <h5 className="text-center">{translate('ONBOARD_SECURE_3_CONTENT__6')} </h5>
</div> </div>
); );

View File

@ -4,15 +4,15 @@ import OnboardSlide from './OnboardSlide';
import onboardIconEight from 'assets/images/onboarding/slide-08.svg'; import onboardIconEight from 'assets/images/onboarding/slide-08.svg';
const SecureSlideTwo = () => { const SecureSlideTwo = () => {
const header = translate('ONBOARD_secure_2_title'); const header = translate('ONBOARD_SECURE_2_TITLE');
const subheader = translate('ONBOARD_secure_2_content__1'); const subheader = translate('ONBOARD_SECURE_2_CONTENT__1');
const content = ( const content = (
<ul> <ul>
<li>{translate('ONBOARD_secure_2_content__2')}</li> <li>{translate('ONBOARD_SECURE_2_CONTENT__2')}</li>
<li>{translate('ONBOARD_secure_2_content__3')}</li> <li>{translate('ONBOARD_SECURE_2_CONTENT__3')}</li>
<li>{translate('ONBOARD_secure_2_content__4')}</li> <li>{translate('ONBOARD_SECURE_2_CONTENT__4')}</li>
<li>{translate('ONBOARD_secure_2_content__5')}</li> <li>{translate('ONBOARD_SECURE_2_CONTENT__5')}</li>
</ul> </ul>
); );

View File

@ -6,8 +6,8 @@ import onboardIconOne from 'assets/images/onboarding/slide-01.svg';
import './WelcomeSlide.scss'; import './WelcomeSlide.scss';
const WelcomeSlide = () => { const WelcomeSlide = () => {
const header = translate('ONBOARD_welcome_title'); const header = translate('ONBOARD_WELCOME_TITLE');
const subheader = <small>{translate('ONBOARD_welcome_content__3')}</small>; const subheader = <small>{translate('ONBOARD_WELCOME_CONTENT__3')}</small>;
const content = ( const content = (
<div> <div>
@ -16,21 +16,21 @@ const WelcomeSlide = () => {
<i className="fa fa-exclamation-triangle" /> <i className="fa fa-exclamation-triangle" />
</div> </div>
<span> <span>
{translate('ONBOARD_welcome_content__1')} {translate('ONBOARD_WELCOME_CONTENT__1')}
{translate('ONBOARD_welcome_content__2')} {translate('ONBOARD_WELCOME_CONTENT__2')}
</span> </span>
</div> </div>
<div className="WelcomeSlide-alert"> <div className="WelcomeSlide-alert">
<div className="WelcomeSlide-alert-icon"> <div className="WelcomeSlide-alert-icon">
<i className="fa fa-exclamation-triangle" /> <i className="fa fa-exclamation-triangle" />
</div> </div>
<span>{translate('ONBOARD_welcome_content__8')}</span> {translate('ONBOARD_WELCOME_CONTENT__8')}
</div> </div>
<h5>{translate('ONBOARD_welcome_content__4')}</h5> <h5>{translate('ONBOARD_WELCOME_CONTENT__4')}</h5>
<ul> <ul>
<li>{translate('ONBOARD_welcome_content__5')}</li> <li>{translate('ONBOARD_WELCOME_CONTENT__5')}</li>
<li>{translate('ONBOARD_welcome_content__6')}</li> <li>{translate('ONBOARD_WELCOME_CONTENT__6')}</li>
<li>{translate('ONBOARD_welcome_content__7')}</li> <li>{translate('ONBOARD_WELCOME_CONTENT__7')}</li>
</ul> </ul>
</div> </div>
); );

View File

@ -4,16 +4,16 @@ import OnboardSlide from './OnboardSlide';
import onboardIconSix from 'assets/images/onboarding/slide-06.svg'; import onboardIconSix from 'assets/images/onboarding/slide-06.svg';
const WhyMewSlide = () => { const WhyMewSlide = () => {
const header = translate('ONBOARD_whymyc_title'); const header = translate('ONBOARD_WHYMYC_TITLE');
const content = ( const content = (
<ul> <ul>
<li>{translate('ONBOARD_whymyc_content__1')}</li> <li>{translate('ONBOARD_WHYMYC_CONTENT__1')}</li>
<li>{translate('ONBOARD_whymyc_content__2')}</li> <li>{translate('ONBOARD_WHYMYC_CONTENT__2')}</li>
<li>{translate('ONBOARD_whymyc_content__3')}</li> <li>{translate('ONBOARD_WHYMYC_CONTENT__3')}</li>
<li>{translate('ONBOARD_whymyc_content__4')}</li> <li>{translate('ONBOARD_WHYMYC_CONTENT__4')}</li>
<li>{translate('ONBOARD_whymyc_content__5')}</li> <li>{translate('ONBOARD_WHYMYC_CONTENT__5')}</li>
<li>{translate('ONBOARD_whymyc_content__6')}</li> <li>{translate('ONBOARD_WHYMYC_CONTENT__6')}</li>
</ul> </ul>
); );
return <OnboardSlide header={header} content={content} image={onboardIconSix} imageSide="left" />; return <OnboardSlide header={header} content={content} image={onboardIconSix} imageSide="left" />;

View File

@ -4,23 +4,23 @@ import OnboardSlide from './OnboardSlide';
import onboardIconFive from 'assets/images/onboarding/slide-05.svg'; import onboardIconFive from 'assets/images/onboarding/slide-05.svg';
const WhySlide = () => { const WhySlide = () => {
const header = translate('ONBOARD_why_title'); const header = translate('ONBOARD_WHY_TITLE');
const content = ( const content = (
<div> <div>
<h5>{translate('ONBOARD_why_content__1')}</h5> <h5>{translate('ONBOARD_WHY_CONTENT__1')}</h5>
<ul> <ul>
<li className="text-danger">{translate('ONBOARD_why_content__2')}</li> <li className="text-danger">{translate('ONBOARD_WHY_CONTENT__2')}</li>
<li className="text-danger">{translate('ONBOARD_why_content__3')}</li> <li className="text-danger">{translate('ONBOARD_WHY_CONTENT__3')}</li>
<li className="text-danger">{translate('ONBOARD_why_content__4')}</li> <li className="text-danger">{translate('ONBOARD_WHY_CONTENT__4')}</li>
<li className="text-danger">{translate('ONBOARD_why_content__5')}</li> <li className="text-danger">{translate('ONBOARD_WHY_CONTENT__5')}</li>
<li className="text-danger">{translate('ONBOARD_why_content__6')}</li> <li className="text-danger">{translate('ONBOARD_WHY_CONTENT__6')}</li>
</ul> </ul>
<h5>{translate('ONBOARD_why_content__7')}</h5> <h5>{translate('ONBOARD_WHY_CONTENT__7')}</h5>
<ul> <ul>
<li>{translate('ONBOARD_why_content__8')}</li> <li>{translate('ONBOARD_WHY_CONTENT__8')}</li>
<li>{translate('ONBOARD_why_content__9')}</li> <li>{translate('ONBOARD_WHY_CONTENT__9')}</li>
<li>{translate('ONBOARD_why_content__10')}</li> <li>{translate('ONBOARD_WHY_CONTENT__10')}</li>
</ul> </ul>
</div> </div>
); );

View File

@ -74,7 +74,7 @@ class OnboardModal extends React.Component<Props, State> {
isOpen: true isOpen: true
}); });
const onboardResumeMessage = translate('ONBOARD_resume'); const onboardResumeMessage = translate('ONBOARD_RESUME');
// Wait a sec so it doesn't get lost in the page-load // Wait a sec so it doesn't get lost in the page-load
setTimeout(() => { setTimeout(() => {
@ -91,25 +91,25 @@ class OnboardModal extends React.Component<Props, State> {
const firstButtons: IButton[] = [ const firstButtons: IButton[] = [
{ {
disabled: slideNumber === NUMBER_OF_SLIDES, disabled: slideNumber === NUMBER_OF_SLIDES,
text: 'Next', text: translate('ACTION_6'),
type: 'primary', type: 'primary',
onClick: this.handleNextSlide onClick: this.handleNextSlide
}, },
{ {
disabled: slideNumber === 1, disabled: slideNumber === 1,
text: 'Back', text: translate('ACTION_4'),
type: 'default', type: 'default',
onClick: this.handlePreviousSlide onClick: this.handlePreviousSlide
} }
]; ];
const lastButtons: IButton[] = [ const lastButtons: IButton[] = [
{ {
text: 'Finish', text: translate('ACTION_10'),
type: 'primary', type: 'primary',
onClick: this.closeModal onClick: this.closeModal
}, },
{ {
text: 'Back', text: translate('ACTION_4'),
type: 'default', type: 'default',
onClick: this.handlePreviousSlide onClick: this.handlePreviousSlide
} }

View File

@ -1,7 +1,7 @@
import React, { Component } from 'react'; import React, { Component } from 'react';
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import TabSection from 'containers/TabSection'; import TabSection from 'containers/TabSection';
import { translateRaw } from 'translations'; import translate from 'translations';
import { import {
signLocalTransactionSucceeded, signLocalTransactionSucceeded,
TSignLocalTransactionSucceeded, TSignLocalTransactionSucceeded,
@ -49,14 +49,12 @@ class BroadcastTx extends Component<Props> {
path={currentPath} path={currentPath}
render={() => ( render={() => (
<div className="BroadcastTx"> <div className="BroadcastTx">
<h1 className="BroadcastTx-title">Broadcast Signed Transaction</h1> <h1 className="BroadcastTx-title">{translate('BROADCAST_TX_TITLE')}</h1>
<p className="BroadcastTx-help"> <p className="BroadcastTx-help">{translate('BROADCAST_TX_DESCRIPTION')}</p>
Paste a signed transaction and press the "SEND TRANSACTION" button.
</p>
<div className="input-group-wrapper InteractForm-interface"> <div className="input-group-wrapper InteractForm-interface">
<label className="input-group"> <label className="input-group">
<div className="input-group-header">{translateRaw('SEND_signed')}</div> <div className="input-group-header">{translate('SEND_SIGNED')}</div>
<TextArea <TextArea
className={stateTransaction ? '' : 'invalid'} className={stateTransaction ? '' : 'invalid'}
rows={7} rows={7}

View File

@ -66,10 +66,10 @@ class TxHashInput extends React.Component<Props, State> {
value={hash} value={hash}
onChange={this.handleSelectTx} onChange={this.handleSelectTx}
options={selectOptions} options={selectOptions}
placeholder="Select a recent transaction..." placeholder={translate('SELECT_RECENT_TX')}
searchable={false} searchable={false}
/> />
<em className="TxHashInput-recent-separator">or</em> <em className="TxHashInput-recent-separator">{translate('OR')}</em>
</div> </div>
)} )}
@ -82,12 +82,12 @@ class TxHashInput extends React.Component<Props, State> {
{isValidETHAddress(hash) && ( {isValidETHAddress(hash) && (
<p className="TxHashInput-message help-block is-invalid"> <p className="TxHashInput-message help-block is-invalid">
You cannot use an address, you must use a transaction hash {translate('SELECT_RECENT_TX_BY_TXHASH')}
</p> </p>
)} )}
<button className="TxHashInput-submit btn btn-primary btn-block"> <button className="TxHashInput-submit btn btn-primary btn-block">
{translate('NAV_CheckTxStatus')} {translate('NAV_CHECKTXSTATUS')}
</button> </button>
</form> </form>
); );

View File

@ -4,12 +4,12 @@ import { RouteComponentProps } from 'react-router';
import TabSection from 'containers/TabSection'; import TabSection from 'containers/TabSection';
import TxHashInput from './components/TxHashInput'; import TxHashInput from './components/TxHashInput';
import { TransactionStatus as TransactionStatusComponent } from 'components'; import { TransactionStatus as TransactionStatusComponent } from 'components';
import { NewTabLink } from 'components/ui';
import { getNetworkConfig } from 'selectors/config'; import { getNetworkConfig } from 'selectors/config';
import { getParamFromURL } from 'utils/helpers'; import { getParamFromURL } from 'utils/helpers';
import { AppState } from 'reducers'; import { AppState } from 'reducers';
import { NetworkConfig } from 'types/network'; import { NetworkConfig } from 'types/network';
import './index.scss'; import './index.scss';
import translate from 'translations';
interface StateProps { interface StateProps {
network: NetworkConfig; network: NetworkConfig;
@ -48,18 +48,14 @@ class CheckTransaction extends React.Component<Props, State> {
<TabSection> <TabSection>
<div className="CheckTransaction Tab-content"> <div className="CheckTransaction Tab-content">
<section className="CheckTransaction-form Tab-content-pane"> <section className="CheckTransaction-form Tab-content-pane">
<h1 className="CheckTransaction-form-title">Check Transaction Status</h1> <h1 className="CheckTransaction-form-title">{translate('CHECK_TX_STATUS_TITLE')}</h1>
<p className="CheckTransaction-form-desc"> <p className="CheckTransaction-form-desc">
Enter your Transaction Hash to check on its status.{' '} {translate('CHECK_TX_STATUS_DESCRIPTION_1')}
{!network.isCustom && ( {!network.isCustom &&
<React.Fragment> translate('CHECK_TX_STATUS_DESCRIPTION_2', {
If you dont know your Transaction Hash, you can look it up on the{' '} $block_explorer: network.blockExplorer.name,
<NewTabLink href={network.blockExplorer.origin}> $block_explorer_link: network.blockExplorer.origin
{network.blockExplorer.name} explorer })}
</NewTabLink>{' '}
by looking up your address.
</React.Fragment>
)}
</p> </p>
<TxHashInput hash={hash} onSubmit={this.handleHashSubmit} /> <TxHashInput hash={hash} onSubmit={this.handleHashSubmit} />
</section> </section>

View File

@ -26,12 +26,12 @@ class DeployClass extends Component<DispatchProps> {
<main className="Deploy Tab-content-pane" role="main"> <main className="Deploy Tab-content-pane" role="main">
<button className="Deploy-field-reset btn btn-default btn-sm" onClick={this.changeWallet}> <button className="Deploy-field-reset btn btn-default btn-sm" onClick={this.changeWallet}>
<i className="fa fa-refresh" /> <i className="fa fa-refresh" />
{translate('Change Wallet')} {translate('CHANGE_WALLET')}
</button> </button>
<div className="input-group-wrapper Deploy-field"> <div className="input-group-wrapper Deploy-field">
<label className="input-group"> <label className="input-group">
<div className="input-group-header">{translate('CONTRACT_ByteCode')}</div> <div className="input-group-header">{translate('CONTRACT_BYTECODE')}</div>
<DataFieldFactory <DataFieldFactory
withProps={({ data: { raw, value }, onChange, readOnly }) => ( withProps={({ data: { raw, value }, onChange, readOnly }) => (
<TextArea <TextArea
@ -76,7 +76,7 @@ class DeployClass extends Component<DispatchProps> {
Modal={ConfirmationModal} Modal={ConfirmationModal}
withProps={({ onClick }) => ( withProps={({ onClick }) => (
<button className="Deploy-submit btn btn-primary" onClick={onClick}> <button className="Deploy-submit btn btn-primary" onClick={onClick}>
{translate('NAV_DeployContract')} {translate('NAV_DEPLOYCONTRACT')}
</button> </button>
)} )}
/> />

View File

@ -78,7 +78,7 @@ class InteractExplorerClass extends Component<Props, State> {
className="InteractExplorer-func-submit btn btn-primary" className="InteractExplorer-func-submit btn btn-primary"
onClick={this.handleFunctionSend} onClick={this.handleFunctionSend}
> >
{translate('CONTRACT_Write')} {translate('CONTRACT_WRITE')}
</button> </button>
); );
@ -87,14 +87,14 @@ class InteractExplorerClass extends Component<Props, State> {
<div className="input-group-wrapper"> <div className="input-group-wrapper">
<label className="input-group"> <label className="input-group">
<div className="input-group-header"> <div className="input-group-header">
{translate('CONTRACT_Interact_Title')} {translate('CONTRACT_INTERACT_TITLE')}
<div className="flex-spacer" /> <div className="flex-spacer" />
<span className="small">{to.raw}</span> <span className="small">{to.raw}</span>
</div> </div>
<Dropdown <Dropdown
name="exploreContract" name="exploreContract"
value={selectedFunction as any} value={selectedFunction as any}
placeholder="Please select a function..." placeholder={translate('SELECT_A_THING', { $thing: 'function' })}
onChange={this.handleFunctionSelect} onChange={this.handleFunctionSelect}
options={contractFunctionsOptions} options={contractFunctionsOptions}
clearable={false} clearable={false}
@ -147,7 +147,7 @@ class InteractExplorerClass extends Component<Props, State> {
className="InteractExplorer-func-submit btn btn-primary" className="InteractExplorer-func-submit btn btn-primary"
onClick={this.handleFunctionCall} onClick={this.handleFunctionCall}
> >
{translate('CONTRACT_Read')} {translate('CONTRACT_READ')}
</button> </button>
) : ( ) : (
<React.Fragment> <React.Fragment>

View File

@ -1,5 +1,5 @@
import React, { Component } from 'react'; import React, { Component } from 'react';
import translate from 'translations'; import translate, { translateRaw } from 'translations';
import { getNetworkContracts } from 'selectors/config'; import { getNetworkContracts } from 'selectors/config';
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import { AppState } from 'reducers'; import { AppState } from 'reducers';
@ -52,8 +52,8 @@ class InteractForm extends Component<Props, State> {
abiJson: '', abiJson: '',
contract: null, contract: null,
contractPlaceholder: this.isContractsValid() contractPlaceholder: this.isContractsValid()
? 'Please select a contract...' ? translateRaw('SELECT_A_THING', { $thing: 'contract' })
: 'No contracts available' : translateRaw('NO_CONTRACTS_AVAILABLE')
}; };
} }
@ -86,7 +86,7 @@ class InteractForm extends Component<Props, State> {
<div className="InteractForm-address row"> <div className="InteractForm-address row">
<div className="input-group-wrapper InteractForm-address-field col-sm-6"> <div className="input-group-wrapper InteractForm-address-field col-sm-6">
<label className="input-group"> <label className="input-group">
<div className="input-group-header">{translate('CONTRACT_Title')}</div> <div className="input-group-header">{translate('CONTRACT_TITLE')}</div>
<Input <Input
placeholder={`ensdomain.eth or ${donationAddressMap.ETH}`} placeholder={`ensdomain.eth or ${donationAddressMap.ETH}`}
name="contract_address" name="contract_address"
@ -102,7 +102,7 @@ class InteractForm extends Component<Props, State> {
<div className="input-group-wrapper InteractForm-address-field col-sm-6"> <div className="input-group-wrapper InteractForm-address-field col-sm-6">
<label className="input-group"> <label className="input-group">
<div className="input-group-header">{translate('CONTRACT_Title_2')}</div> <div className="input-group-header">{translate('CONTRACT_TITLE_2')}</div>
<Dropdown <Dropdown
className={`${!contract ? 'invalid' : ''}`} className={`${!contract ? 'invalid' : ''}`}
value={contract as any} value={contract as any}
@ -118,7 +118,7 @@ class InteractForm extends Component<Props, State> {
<div className="input-group-wrapper InteractForm-interface"> <div className="input-group-wrapper InteractForm-interface">
<label className="input-group"> <label className="input-group">
<div className="input-group-header">{translate('CONTRACT_Json')}</div> <div className="input-group-header">{translate('CONTRACT_JSON')}</div>
<TextArea <TextArea
placeholder={this.abiJsonPlaceholder} placeholder={this.abiJsonPlaceholder}
className={`InteractForm-interface-field-input ${validAbiJson ? '' : 'invalid'}`} className={`InteractForm-interface-field-input ${validAbiJson ? '' : 'invalid'}`}
@ -134,7 +134,7 @@ class InteractForm extends Component<Props, State> {
disabled={!showContractAccessButton} disabled={!showContractAccessButton}
onClick={accessContract(abiJson, address)} onClick={accessContract(abiJson, address)}
> >
{translate('x_Access')} {translate('X_ACCESS')}
</button> </button>
</div> </div>
); );

View File

@ -18,11 +18,11 @@ interface Props {
const tabs = [ const tabs = [
{ {
path: 'interact', path: 'interact',
name: translate('Interact') name: translate('CONTRACTS_INTERACT')
}, },
{ {
path: 'deploy', path: 'deploy',
name: translate('Deploy') name: translate('CONTRACTS_DEPLOY')
} }
]; ];

View File

@ -5,6 +5,7 @@ import { resolveDomainRequested, TResolveDomainRequested } from 'actions/ens';
import { isValidENSName } from 'libs/validators'; import { isValidENSName } from 'libs/validators';
import './NameInput.scss'; import './NameInput.scss';
import { Input } from 'components/ui'; import { Input } from 'components/ui';
import translate from 'translations';
interface State { interface State {
domainToCheck: string; domainToCheck: string;
@ -26,7 +27,7 @@ class NameInput extends Component<Props, State> {
public render() { public render() {
const { domainRequests } = this.props; const { domainRequests } = this.props;
const { isValidDomain, domainToCheck, isFocused } = this.state; const { isValidDomain, domainToCheck } = this.state;
const req = domainRequests[domainToCheck]; const req = domainRequests[domainToCheck];
const isLoading = req && !req.data && !req.error; const isLoading = req && !req.data && !req.error;
@ -48,19 +49,16 @@ class NameInput extends Component<Props, State> {
/> />
<span className="input-group-addon">.eth</span> <span className="input-group-addon">.eth</span>
</label> </label>
{domainToCheck &&
!isValidDomain && (
<p className="help-block is-invalid">{translate('ENS_INVALID_INPUT')}</p>
)}
</div> </div>
{domainToCheck &&
!isValidDomain &&
!isFocused && (
<p className="help-block is-invalid">
Must be at least 7 characters, no special characters
</p>
)}
<button <button
className="ENSInput-button btn btn-primary btn-block" className="ENSInput-button btn btn-primary btn-block"
disabled={!isValidDomain || isLoading} disabled={!isValidDomain || isLoading}
> >
Check Availability {translate('ACTION_9')}
</button> </button>
</form> </form>
); );

View File

@ -4,6 +4,7 @@ import ENSTime from './components/ENSTime';
import moment from 'moment'; import moment from 'moment';
import { NewTabLink } from 'components/ui'; import { NewTabLink } from 'components/ui';
import { ensV3Url } from 'utils/formatters'; import { ensV3Url } from 'utils/formatters';
import translate from 'translations';
const getDeadlines = (registrationDate: string) => { const getDeadlines = (registrationDate: string) => {
// Get the time to reveal bids, and the time when the action closes // Get the time to reveal bids, and the time when the action closes
@ -20,9 +21,7 @@ export const NameAuction: React.SFC<IBaseDomainRequest> = props => {
<section className="row"> <section className="row">
<div className="auction-info text-center"> <div className="auction-info text-center">
<div className="ens-title"> <div className="ens-title">
<h1> <h1>{translate('ENS_DOMAIN_AUCTION', { $name: name + '.eth' })}</h1>
An auction has started for <strong>{name}.eth</strong>
</h1>
</div> </div>
<div className="ens-panel-wrapper"> <div className="ens-panel-wrapper">
@ -35,11 +34,9 @@ export const NameAuction: React.SFC<IBaseDomainRequest> = props => {
</div> </div>
<p> <p>
Do you want to place a bid on {name}.eth?{' '} {translate('NAME_AUCTION_PROMPT_BID')}
<strong> <strong>
<NewTabLink href={ensV3Url(name)}> <NewTabLink href={ensV3Url(name)}>{translate('NAME_AUCTION_PROMPT_BID_2')}</NewTabLink>
You can do that on MyCrypto V3 by clicking here!
</NewTabLink>
</strong> </strong>
</p> </p>
</div> </div>

View File

@ -1,6 +1,7 @@
import React from 'react'; import React from 'react';
import { IBaseDomainRequest } from 'libs/ens'; import { IBaseDomainRequest } from 'libs/ens';
import translate from 'translations';
export const NameForbidden: React.SFC<IBaseDomainRequest> = props => ( export const NameForbidden: React.SFC<IBaseDomainRequest> = props => (
<h1>{props.name}.eth is forbidden</h1> <h1>{translate('ENS_DOMAIN_FORBIDDEN', { $name: props.name + '.eth' })}</h1>
); );

View File

@ -2,21 +2,19 @@ import React from 'react';
import { IBaseDomainRequest } from 'libs/ens'; import { IBaseDomainRequest } from 'libs/ens';
import { NewTabLink } from 'components/ui'; import { NewTabLink } from 'components/ui';
import { ensV3Url } from 'utils/formatters'; import { ensV3Url } from 'utils/formatters';
import translate from 'translations';
export const NameOpen: React.SFC<IBaseDomainRequest> = props => ( export const NameOpen: React.SFC<IBaseDomainRequest> = props => (
<section className="row"> <section className="row">
<section className="auction-info text-center"> <section className="auction-info text-center">
<div className="ens-title"> <div className="ens-title">
<h1> <h1>{translate('ENS_DOMAIN_OPEN', { $name: props.name + '.eth' })}</h1>
<strong>{props.name}.eth</strong> is available
</h1>
</div> </div>
<p> <p>
Do you want {props.name}.eth?{' '} {translate('OPEN_AUCTION_PROMPT_1', { $name: props.name })}
<strong> <strong>
<NewTabLink className="text-center" href={ensV3Url(props.name)}> <NewTabLink className="text-center" href={ensV3Url(props.name)}>
Open an auction on MyCrypto v3! {translate('OPEN_AUCTION_PROMPT_2')}
</NewTabLink> </NewTabLink>
</strong> </strong>
</p> </p>

View File

@ -1,6 +1,7 @@
import React from 'react'; import React from 'react';
import { IOwnedDomainRequest } from 'libs/ens'; import { IOwnedDomainRequest } from 'libs/ens';
import { NewTabLink, Address } from 'components/ui'; import { NewTabLink, Address } from 'components/ui';
import translate from 'translations';
const lookupLink = (name: string) => `https://etherscan.io/enslookup?q=${name}`; const lookupLink = (name: string) => `https://etherscan.io/enslookup?q=${name}`;
type ChildrenProps = any; type ChildrenProps = any;
@ -17,41 +18,39 @@ export const NameOwned: React.SFC<IOwnedDomainRequest> = ({
}) => ( }) => (
<section> <section>
<div className="ens-title"> <div className="ens-title">
<h1 className="text-center"> <h1 className="text-center">{translate('ENS_DOMAIN_OWNED', { $name: name + '.eth' })}</h1>
<strong>{name}.eth</strong> is already owned
</h1>
</div> </div>
<div className="ens-table-wrapper"> <div className="ens-table-wrapper">
<table className="table table-striped"> <table className="table table-striped">
<tbody> <tbody>
<tr> <tr>
<td>Name: </td> <td>{translate('NAME_OWNED_NAME')}:</td>
<MonoTd> <MonoTd>
<NewTabLink content={`${name}.eth`} href={lookupLink(`${name}.eth`)} /> <NewTabLink content={`${name}.eth`} href={lookupLink(`${name}.eth`)} />
</MonoTd> </MonoTd>
</tr> </tr>
<tr> <tr>
<td>Labelhash ({name}): </td> <td>{translate('NAME_OWNED_LABELHASH', { name })}:</td>
<MonoTd>{labelHash}</MonoTd> <MonoTd>{labelHash}</MonoTd>
</tr> </tr>
<tr> <tr>
<td>Namehash ({name}.eth): </td> <td>{translate('NAME_OWNED_NAMEHASH', { name })} </td>
<MonoTd>{nameHash}</MonoTd> <MonoTd>{nameHash}</MonoTd>
</tr> </tr>
<tr> <tr>
<td>Owner:</td> <td>{translate('NAME_OWNED_OWNER')}:</td>
<MonoTd> <MonoTd>
<Address address={ownerAddress} /> <Address address={ownerAddress} />
</MonoTd> </MonoTd>
</tr> </tr>
<tr> <tr>
<td>Highest Bidder (Deed Owner): </td> <td>{translate('NAME_OWNED_HIGHEST_BIDDER')}</td>
<MonoTd> <MonoTd>
<span>{highestBid}</span> <span>{highestBid}</span>
</MonoTd> </MonoTd>
</tr> </tr>
<tr> <tr>
<td>Resolved Address: </td> <td>{translate('NAME_OWNED_RESOLVED_ADDR')}:</td>
<MonoTd> <MonoTd>
<Address address={resolvedAddress} /> <Address address={resolvedAddress} />
</MonoTd> </MonoTd>

View File

@ -1,18 +1,19 @@
import React from 'react'; import React from 'react';
import { IRevealDomainRequest } from 'libs/ens'; import { IRevealDomainRequest } from 'libs/ens';
import ENSTime from './components/ENSTime'; import ENSTime from './components/ENSTime';
import { UnitDisplay, NewTabLink } from 'components/ui'; import { UnitDisplay } from 'components/ui';
import { Wei } from 'libs/units'; import { Wei } from 'libs/units';
import { ensV3Url } from 'utils/formatters'; import { ensV3Url } from 'utils/formatters';
import translate from 'translations';
export const NameReveal: React.SFC<IRevealDomainRequest> = props => ( export const NameReveal: React.SFC<IRevealDomainRequest> = props => (
<section className="row text-center"> <section className="row text-center">
<div className="auction-info text-center"> <div className="auction-info text-center">
<div className="ens-title"> <div className="ens-title">
<h2> <h2>
It's time to reveal the bids for <strong>{props.name}.eth</strong> {translate('ENS_DOMAIN_REVEAL', { $name: props.name + '.eth' })}
<br /> <br />
The current highest bid is{' '} {translate('ENS_DOMAIN_HIGHEST_BID')}
<strong> <strong>
<UnitDisplay <UnitDisplay
value={Wei(props.highestBid)} value={Wei(props.highestBid)}
@ -33,12 +34,10 @@ export const NameReveal: React.SFC<IRevealDomainRequest> = props => (
</div> </div>
<p> <p>
Did you bid on {props.name}.eth? You must reveal your bid now.{' '} {translate('ENS_DOMAIN_PROMPT_REVEAL', {
<strong> $name: props.name + '.eth',
<NewTabLink href={ensV3Url(props.name)}> $link: ensV3Url(props.name)
You can do that on MyCrypto v3 by clicking here! })}
</NewTabLink>
</strong>
</p> </p>
</section> </section>
); );

View File

@ -1,16 +1,9 @@
import React from 'react'; import React from 'react';
import { NameInput, NameResolve } from './components'; import { NameInput, NameResolve } from './components';
import TabSection from 'containers/TabSection'; import TabSection from 'containers/TabSection';
import { NewTabLink } from 'components/ui';
import { donationAddressMap } from 'config'; import { donationAddressMap } from 'config';
import './index.scss'; import './index.scss';
import translate from 'translations';
const ENSDocsLink = () => (
<NewTabLink
href="https://ens.readthedocs.io/en/latest/introduction.html"
content="Ethereum Name Service"
/>
);
export default class ENSClass extends React.Component<{}> { export default class ENSClass extends React.Component<{}> {
public render() { public render() {
@ -21,16 +14,14 @@ export default class ENSClass extends React.Component<{}> {
<div className="ENS"> <div className="ENS">
<h1 className="ENS-title">Ethereum Name Service</h1> <h1 className="ENS-title">Ethereum Name Service</h1>
<p className="ENS-description"> <p className="ENS-description">
The <ENSDocsLink /> is a distributed, open, and extensible naming system based on {translate('ENS_DESCRIPTION', {
the Ethereum blockchain. Once you have a name, you can tell your friends to send ETH $ens_docs: 'https://ens.readthedocs.io/en/latest/introduction.html',
to <code>ensdomain.eth</code> instead of $example_donation_addr: donationAddressMap.ETH.substr(0, 8)
<code>{donationAddressMap.ETH.substr(0, 12)}...</code> })}
</p> </p>
<NameInput /> <NameInput />
</div> </div>
</section> </section>
<NameResolve /> <NameResolve />
</div> </div>
</TabSection> </TabSection>

View File

@ -17,45 +17,42 @@ interface Props {
const FinalSteps: React.SFC<Props> = ({ walletType }) => { const FinalSteps: React.SFC<Props> = ({ walletType }) => {
const steps = [ const steps = [
{ {
name: 'Open MyCrypto', name: translate('MNEMONIC_FINAL_STEP_1'),
image: SiteImage image: SiteImage
}, },
{ {
name: 'Go to the account tab', name: translate('MNEMONIC_FINAL_STEP_2'),
image: TabImage image: TabImage
} }
]; ];
if (walletType === WalletType.Keystore) { if (walletType === WalletType.Keystore) {
steps.push({ steps.push({
name: 'Select your wallet type', name: translate('MNEMONIC_FINAL_STEP_3'),
image: SelectKeystoreImage image: SelectKeystoreImage
}); });
steps.push({ steps.push({
name: 'Provide file & password', name: translate('MNEMONIC_FINAL_STEP_5'),
image: ProvideKeystoreImage image: ProvideKeystoreImage
}); });
} else if (walletType === WalletType.Mnemonic) { } else if (walletType === WalletType.Mnemonic) {
steps.push({ steps.push({
name: 'Select your wallet type', name: translate('MNEMONIC_FINAL_STEP_3'),
image: SelectMnemonicImage image: SelectMnemonicImage
}); });
steps.push({ steps.push({
name: 'Enter your phrase', name: translate('MNEMONIC_FINAL_STEP_4'),
image: ProvideMnemonicImage image: ProvideMnemonicImage
}); });
} }
return ( return (
<div className="FinalSteps"> <div className="FinalSteps">
<h1 className="FinalSteps-title">{translate('ADD_Label_6')}</h1> <h1 className="FinalSteps-title">{translate('ADD_LABEL_6')}</h1>
<p className="FinalSteps-help"> <p className="FinalSteps-help">{translate('MNEMONIC_FINAL_DESCRIPTION')}</p>
All done, youre now ready to access your wallet. Just follow these 4 steps whenever you
want to access your wallet.
</p>
<div className="FinalSteps-steps row"> <div className="FinalSteps-steps row">
{steps.map((step, index) => ( {steps.map((step, index) => (
<div key={step.name} className="StepBox col-lg-3 col-sm-6 col-xs-12"> <div key={index} className="StepBox col-lg-3 col-sm-6 col-xs-12">
<h4 className="StepBox-title">{step.name}</h4> <h4 className="StepBox-title">{step.name}</h4>
<div className="StepBox-screen"> <div className="StepBox-screen">
<img className="StepBox-screen-img" src={step.image} /> <img className="StepBox-screen-img" src={step.image} />
@ -66,7 +63,7 @@ const FinalSteps: React.SFC<Props> = ({ walletType }) => {
</div> </div>
<div className="FinalSteps-buttons"> <div className="FinalSteps-buttons">
<Link to="/account" className="FinalSteps-buttons-btn btn btn-primary btn-lg"> <Link to="/account" className="FinalSteps-buttons-btn btn btn-primary btn-lg">
Go to Account {translate('GO_TO_ACCOUNT')}
</Link> </Link>
</div> </div>
</div> </div>

View File

@ -1,6 +1,6 @@
import { IV3Wallet } from 'ethereumjs-wallet'; import { IV3Wallet } from 'ethereumjs-wallet';
import React, { Component } from 'react'; import React, { Component } from 'react';
import translate from 'translations'; import translate, { translateRaw } from 'translations';
import { makeBlob } from 'utils/blob'; import { makeBlob } from 'utils/blob';
import './DownloadWallet.scss'; import './DownloadWallet.scss';
import Template from '../Template'; import Template from '../Template';
@ -27,32 +27,24 @@ export default class DownloadWallet extends Component<Props, State> {
return ( return (
<Template> <Template>
<div className="DlWallet"> <div className="DlWallet">
<h1 className="DlWallet-title">{translate('GEN_Label_2')}</h1> <h1 className="DlWallet-title">{translate('GEN_LABEL_2')}</h1>
<a <a
role="button" role="button"
className="DlWallet-download btn btn-primary btn-lg" className="DlWallet-download btn btn-primary btn-lg"
aria-label="Download Keystore File (UTC / JSON · Recommended · Encrypted)" aria-label="Download Keystore File (UTC / JSON · Recommended · Encrypted)"
aria-describedby={translate('x_KeystoreDesc', true)} aria-describedby={translateRaw('X_KEYSTOREDESC')}
download={filename} download={filename}
href={this.getBlob()} href={this.getBlob()}
onClick={this.handleDownloadKeystore} onClick={this.handleDownloadKeystore}
> >
{translate('x_Download')} {translate('x_Keystore2')} {translate('ACTION_13', { $thing: translateRaw('X_KEYSTORE2') })}
</a> </a>
<div className="DlWallet-warning"> <div className="DlWallet-warning">
<p> <p>{translate('DL_WALLET_WARNING_1')}</p>
<strong>Do not lose it!</strong> It cannot be recovered if you lose it. <p>{translate('DL_WALLET_WARNING_2')}</p>
</p> <p>{translate('DL_WALLET_WARNING_3')}</p>
<p>
<strong>Do not share it!</strong> Your funds will be stolen if you use this file on a
malicious/phishing site.
</p>
<p>
<strong>Make a backup!</strong> Secure it like the millions of dollars it may one day
be worth.
</p>
</div> </div>
<button <button
@ -61,7 +53,7 @@ export default class DownloadWallet extends Component<Props, State> {
onClick={this.handleContinue} onClick={this.handleContinue}
disabled={!hasDownloadedWallet} disabled={!hasDownloadedWallet}
> >
I understand. Continue. {translate('ACTION_14')}
</button> </button>
</div> </div>
</Template> </Template>

View File

@ -33,21 +33,22 @@ export default class EnterPassword extends Component<Props, State> {
const isPasswordValid = passwordValidity === 'valid'; const isPasswordValid = passwordValidity === 'valid';
const isConfirmValid = confirmedPassword ? password === confirmedPassword : undefined; const isConfirmValid = confirmedPassword ? password === confirmedPassword : undefined;
const canSubmit = isPasswordValid && isConfirmValid && !isGenerating; const canSubmit = isPasswordValid && isConfirmValid && !isGenerating;
return ( return (
<Template> <Template>
<form className="EnterPw" onSubmit={canSubmit ? this.handleSubmit : undefined}> <form className="EnterPw" onSubmit={canSubmit ? this.handleSubmit : undefined}>
<h1 className="EnterPw-title" aria-live="polite"> <h1 className="EnterPw-title" aria-live="polite">
Generate a {translate('x_Keystore2')} {translate('GENERATE_KEYSTORE_TITLE')}
</h1> </h1>
<div className="input-group-wrapper EnterPw-password"> <div className="input-group-wrapper EnterPw-password">
<label className="input-group"> <label className="input-group">
<div className="input-group-header">{translate('GEN_Label_1')}</div> <div className="input-group-header">{translate('INPUT_PASSWORD_LABEL')}</div>
<TogglablePassword <TogglablePassword
className={!isPasswordValid && password.length > 0 ? 'invalid' : ''} isValid={isPasswordValid && password.length > 0}
value={password} value={password}
placeholder={`Password must be uncommon and ${MINIMUM_PASSWORD_LENGTH}+ characters long`} placeholder={translateRaw('INPUT_PASSWORD_PLACEHOLDER', {
$pass_length: MINIMUM_PASSWORD_LENGTH.toString()
})}
onChange={this.onPasswordChange} onChange={this.onPasswordChange}
onBlur={this.showFeedback} onBlur={this.showFeedback}
/> />
@ -62,21 +63,21 @@ export default class EnterPassword extends Component<Props, State> {
<div className="input-group-wrapper EnterPw-password"> <div className="input-group-wrapper EnterPw-password">
<label className="input-group"> <label className="input-group">
<div className="input-group-header">Confirm password</div> <div className="input-group-header">{translate('INPUT_CONFIRM_PASSWORD_LABEL')}</div>
<TogglablePassword <TogglablePassword
className={!isConfirmValid && password.length > 0 ? 'invalid' : ''} isValid={isConfirmValid && password.length > 0}
value={confirmedPassword} value={confirmedPassword}
placeholder={translateRaw('GEN_Placeholder_1')} placeholder={translateRaw('GEN_PLACEHOLDER_1')}
onChange={this.onConfirmChange} onChange={this.onConfirmChange}
/> />
</label> </label>
</div> </div>
<button disabled={!canSubmit} className="EnterPw-submit btn btn-primary btn-lg btn-block"> <button disabled={!canSubmit} className="EnterPw-submit btn btn-primary btn-lg btn-block">
{isGenerating ? <Spinner light={true} /> : translate('NAV_GenerateWallet')} {isGenerating ? <Spinner light={true} /> : translate('NAV_GENERATEWALLET')}
</button> </button>
<p className="EnterPw-warning">{translate('x_PasswordDesc')}</p> <p className="EnterPw-warning">{translate('X_PASSWORDDESC')}</p>
</form> </form>
</Template> </Template>
); );
@ -101,18 +102,20 @@ export default class EnterPassword extends Component<Props, State> {
} }
private getFeedback() { private getFeedback() {
let feedback = ''; let feedback: string = '';
const validity = this.getPasswordValidity(); const validity = this.getPasswordValidity();
if (validity !== 'valid') { if (validity !== 'valid') {
const { password, passwordValidation } = this.state; const { password, passwordValidation } = this.state;
if (password.length < MINIMUM_PASSWORD_LENGTH) { if (password.length < MINIMUM_PASSWORD_LENGTH) {
feedback = `Password must be ${MINIMUM_PASSWORD_LENGTH}+ characters`; feedback = translateRaw('INPUT_PASSWORD_PLACEHOLDER', {
$pass_length: MINIMUM_PASSWORD_LENGTH.toString()
});
} else if (passwordValidation && passwordValidation.feedback) { } else if (passwordValidation && passwordValidation.feedback) {
feedback = `This password is not strong enough. ${passwordValidation.feedback.warning}.`; feedback = translateRaw('WEAK_PASSWORD') + ' ' + passwordValidation.feedback.warning;
} else { } else {
feedback = 'There is something invalid about your password. Please try another.'; feedback = translateRaw('INVALID_PASSWORD');
} }
} }

View File

@ -18,11 +18,10 @@ const PaperWallet: React.SFC<Props> = props => (
<div className="GenPaper"> <div className="GenPaper">
{/* Private Key */} {/* Private Key */}
<label className="input-group GenPaper-private"> <label className="input-group GenPaper-private">
{/* translateRaw isn't used here because it wont properly render the ` characters as a string of code in markdown*/} <h1 className="GenPaper-title">{translate('GEN_LABEL_5')}</h1>
<h1 className="input-group-header">{translate('GEN_Label_5')}</h1>
<Input <Input
value={stripHexPrefix(props.privateKey)} value={stripHexPrefix(props.privateKey)}
aria-label={translateRaw('x_PrivKey')} aria-label={translateRaw('X_PRIVKEY')}
aria-describedby="x_PrivKeyDesc" aria-describedby="x_PrivKeyDesc"
type="text" type="text"
readOnly={true} readOnly={true}
@ -30,29 +29,21 @@ const PaperWallet: React.SFC<Props> = props => (
</label> </label>
{/* Download Paper Wallet */} {/* Download Paper Wallet */}
<h2 className="GenPaper-title">{translate('x_Print')}</h2> <h2 className="GenPaper-title">{translate('X_PRINT')}</h2>
<div className="GenPaper-paper"> <div className="GenPaper-paper">
<PrintableWallet address={props.keystore.address} privateKey={props.privateKey} /> <PrintableWallet address={props.keystore.address} privateKey={props.privateKey} />
</div> </div>
{/* Warning */} {/* Warning */}
<div className="GenPaper-warning"> <div className="GenPaper-warning">
<p> <p>{translate('DL_WALLET_WARNING_1')}</p>
<strong>Do not lose it!</strong> It cannot be recovered if you lose it. <p>{translate('DL_WALLET_WARNING_2')}</p>
</p> <p>{translate('DL_WALLET_WARNING_3')}</p>
<p>
<strong>Do not share it!</strong> Your funds will be stolen if you use this file on a
malicious/phishing site.
</p>
<p>
<strong>Make a backup!</strong> Secure it like the millions of dollars it may one day be
worth.
</p>
</div> </div>
{/* Continue button */} {/* Continue button */}
<button className="GenPaper-continue btn btn-default" onClick={props.continue}> <button className="GenPaper-continue btn btn-default" onClick={props.continue}>
{translate('NAV_ViewWallet')} {translate('NAV_VIEWWALLET')}
</button> </button>
</div> </div>
</Template> </Template>

View File

@ -51,19 +51,12 @@ export default class GenerateMnemonic extends React.Component<{}, State> {
content = ( content = (
<div className="GenerateMnemonic"> <div className="GenerateMnemonic">
<h1 className="GenerateMnemonic-title">Generate a {translate('x_Mnemonic')}</h1> <h1 className="GenerateMnemonic-title">{translate('GENERATE_MNEMONIC_TITLE')}</h1>
<p className="GenerateMnemonic-help"> <p className="GenerateMnemonic-help">
{isConfirming {isConfirming
? ` ? translate('MNEMONIC_DESCRIPTOION_1')
Re-enter your phrase to confirm you copied it correctly. If you : translate('MNEMONIC_DESCRIPTOION_2')}
forgot one of your words, just click the button beside the input
to reveal it.
`
: `
Write these words down. Do not copy them to your clipboard, or save
them anywhere online.
`}
</p> </p>
<div className="GenerateMnemonic-words"> <div className="GenerateMnemonic-words">
@ -80,7 +73,7 @@ export default class GenerateMnemonic extends React.Component<{}, State> {
className="GenerateMnemonic-buttons-btn btn btn-default" className="GenerateMnemonic-buttons-btn btn btn-default"
onClick={this.regenerateWordArray} onClick={this.regenerateWordArray}
> >
<i className="fa fa-refresh" /> Regenerate Phrase <i className="fa fa-refresh" /> {translate('REGENERATE_MNEMONIC')}
</button> </button>
)} )}
<button <button
@ -88,7 +81,7 @@ export default class GenerateMnemonic extends React.Component<{}, State> {
disabled={!canContinue} disabled={!canContinue}
onClick={this.goToNextStep} onClick={this.goToNextStep}
> >
Confirm Phrase {translate('CONFIRM_MNEMONIC')}
</button> </button>
</div> </div>

View File

@ -39,7 +39,7 @@ export default class MnemonicWord extends React.Component<Props, State> {
{!isReadOnly && ( {!isReadOnly && (
<span <span
onClick={this.toggleShow} onClick={this.toggleShow}
aria-label={translateRaw('GEN_Aria_2')} aria-label={translateRaw('GEN_ARIA_2')}
role="button" role="button"
className="MnemonicWord-word-toggle input-group-addon" className="MnemonicWord-word-toggle input-group-addon"
> >

View File

@ -1,6 +1,7 @@
import React from 'react'; import React from 'react';
import { Link } from 'react-router-dom'; import { Link } from 'react-router-dom';
import './Template.scss'; import './Template.scss';
import translate from 'translations';
interface Props { interface Props {
children: React.ReactElement<any>; children: React.ReactElement<any>;
@ -10,7 +11,7 @@ const GenerateWalletTemplate: React.SFC<Props> = ({ children }) => (
<div className="GenerateWallet Tab-content-pane"> <div className="GenerateWallet Tab-content-pane">
{children} {children}
<Link className="GenerateWallet-back" to="/generate"> <Link className="GenerateWallet-back" to="/generate">
<i className="fa fa-arrow-left" /> Back <i className="fa fa-arrow-left" /> {translate('MODAL_BACK')}
</Link> </Link>
</div> </div>
); );

View File

@ -1,15 +1,15 @@
import React from 'react'; import React from 'react';
import translate from 'translations'; import translate, { translateRaw } from 'translations';
import { WalletType } from '../GenerateWallet'; import { WalletType } from '../GenerateWallet';
import { NewTabLink, HelpLink } from 'components/ui';
import { HELP_ARTICLE, trezorReferralURL, ledgerReferralURL } from 'config';
import { Link } from 'react-router-dom'; import { Link } from 'react-router-dom';
import './WalletTypes.scss'; import './WalletTypes.scss';
import { HelpLink } from 'components/ui';
import { HELP_ARTICLE, ledgerReferralURL, trezorReferralURL } from 'config';
const WalletTypes: React.SFC<{}> = () => { const WalletTypes: React.SFC<{}> = () => {
const typeInfo = { const typeInfo = {
[WalletType.Keystore]: { [WalletType.Keystore]: {
name: 'x_Keystore2', name: 'X_KEYSTORE2',
bullets: [ bullets: [
'An encrypted JSON file, protected by a password', 'An encrypted JSON file, protected by a password',
'Back it up on a USB drive', 'Back it up on a USB drive',
@ -19,7 +19,7 @@ const WalletTypes: React.SFC<{}> = () => {
] ]
}, },
[WalletType.Mnemonic]: { [WalletType.Mnemonic]: {
name: 'x_Mnemonic', name: 'X_MNEMONIC',
bullets: [ bullets: [
'A 12-word private seed phrase', 'A 12-word private seed phrase',
'Back it up on paper or USB drive', 'Back it up on paper or USB drive',
@ -32,15 +32,16 @@ const WalletTypes: React.SFC<{}> = () => {
return ( return (
<div className="WalletTypes Tab-content-pane"> <div className="WalletTypes Tab-content-pane">
<h1 className="WalletTypes-title">{translate('NAV_GenerateWallet')}</h1> <h1 className="WalletTypes-title">{translate('NAV_GENERATEWALLET')}</h1>
<p className="WalletTypes-subtitle alert alert-warning"> <p className="WalletTypes-subtitle alert alert-warning">
<strong>Warning</strong>: Managing your own keys can be risky and a single mistake can lead <strong>{translate('NOTIFICATION_TYPE_WARNING')}</strong>:{' '}
to irrecoverable loss. If you are new to cryptocurrencies, we strongly recommend using{' '} {translate('GENERATE_WALLET_WARNING', {
<NewTabLink href="https://metamask.io/">MetaMask</NewTabLink>, or purchasing a{' '} $metamask_link: 'https://metamask.io/',
<NewTabLink href={ledgerReferralURL}>Ledger</NewTabLink> or{' '} $ledger_link: ledgerReferralURL,
<NewTabLink href={trezorReferralURL}>TREZOR</NewTabLink> hardware wallet.{' '} $trezor_link: trezorReferralURL
})}
<HelpLink article={HELP_ARTICLE.DIFFERENCE_BETWEEN_PKEY_AND_KEYSTORE}> <HelpLink article={HELP_ARTICLE.DIFFERENCE_BETWEEN_PKEY_AND_KEYSTORE}>
Learn more about different wallet types & staying secure. {translate('GENERATE_WALLET_HELPLINK_1')}
</HelpLink> </HelpLink>
</p> </p>
@ -61,7 +62,7 @@ const WalletTypes: React.SFC<{}> = () => {
className="WalletType-select-btn btn btn-primary btn-block" className="WalletType-select-btn btn btn-primary btn-block"
to={`/generate/${type}`} to={`/generate/${type}`}
> >
Generate a {translate(typeInfo[type].name)} {translate('GENERATE_THING', { $thing: translateRaw(typeInfo[type].name) })}
</Link> </Link>
</div> </div>
</div> </div>

View File

@ -0,0 +1,35 @@
import { donationAddressMap } from 'config';
import React from 'react';
import translate from 'translations';
interface Props {
onDonate(address: string, amount: string, unit: string): void;
}
interface State {
clicked: boolean;
}
export default class Donate extends React.Component<Props, State> {
public state = {
clicked: false
};
public render() {
return (
<div className="well">
<p>{translate('SIDEBAR_DONATION')}</p>
<a className="btn btn-primary btn-block" onClick={this.onClick}>
{translate('SIDEBAR_DONATE')}
</a>
{this.state.clicked && (
<div className="text-success text-center marg-v-sm">{translate('SIDEBAR_THANKS')}</div>
)}
</div>
);
}
public onClick = () => {
// FIXME move to config
this.props.onDonate(donationAddressMap.ETH, '1', 'ETH');
this.setState({ clicked: true });
};
}

View File

@ -52,7 +52,7 @@ const QueryWarning: React.SFC<{}> = () => (
<WhenQueryExists <WhenQueryExists
whenQueryExists={ whenQueryExists={
<div className="alert alert-info"> <div className="alert alert-info">
<p>{translate('WARN_Send_Link')}</p> <p>{translate('WARN_SEND_LINK')}</p>
</div> </div>
} }
/> />

View File

@ -1,9 +1,8 @@
import React from 'react'; import React from 'react';
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import translate from 'translations'; import translate, { translateRaw } from 'translations';
import { getRecentWalletTransactions } from 'selectors/transactions'; import { getRecentWalletTransactions } from 'selectors/transactions';
import { getNetworkConfig } from 'selectors/config'; import { getNetworkConfig } from 'selectors/config';
import { NewTabLink } from 'components/ui';
import RecentTransaction from './RecentTransaction'; import RecentTransaction from './RecentTransaction';
import { TransactionStatus } from 'components'; import { TransactionStatus } from 'components';
import { IWallet } from 'libs/wallet'; import { IWallet } from 'libs/wallet';
@ -39,7 +38,7 @@ class RecentTransactions extends React.Component<Props> {
<React.Fragment> <React.Fragment>
<TransactionStatus txHash={activeTxHash} /> <TransactionStatus txHash={activeTxHash} />
<button className="RecentTxs-back btn btn-default" onClick={this.clearActiveTxHash}> <button className="RecentTxs-back btn btn-default" onClick={this.clearActiveTxHash}>
<i className="fa fa-arrow-left" /> Back to Recent Transactions <i className="fa fa-arrow-left" /> {translate('BACK_TO_RECENT_TXS')}
</button> </button>
</React.Fragment> </React.Fragment>
); );
@ -53,15 +52,13 @@ class RecentTransactions extends React.Component<Props> {
private renderTxList() { private renderTxList() {
const { wallet, recentTransactions, network } = this.props; const { wallet, recentTransactions, network } = this.props;
let explorer: React.ReactElement<string>; let explorer: string;
if (network.isCustom) { if (network.isCustom) {
explorer = <span>an explorer for the {network.name} network</span>; explorer = translateRaw('RECENT_TX_NETWORK_EXPLORER', { $network_name: network.name });
} else { } else {
explorer = ( explorer = `[${network.blockExplorer.name}](${network.blockExplorer.addressUrl(
<NewTabLink href={network.blockExplorer.addressUrl(wallet.getAddressString())}> wallet.getAddressString()
{network.blockExplorer.name} )})`;
</NewTabLink>
);
} }
return ( return (
@ -69,9 +66,9 @@ class RecentTransactions extends React.Component<Props> {
{recentTransactions.length ? ( {recentTransactions.length ? (
<table className="RecentTxs-txs"> <table className="RecentTxs-txs">
<thead> <thead>
<td>{translate('SEND_addr')}</td> <td>{translate('SEND_ADDR')}</td>
<td>{translate('SEND_amount_short')}</td> <td>{translate('SEND_AMOUNT_SHORT')}</td>
<td>{translate('Sent')}</td> <td>{translate('SENT')}</td>
<td /> <td />
</thead> </thead>
<tbody> <tbody>
@ -88,13 +85,12 @@ class RecentTransactions extends React.Component<Props> {
) : ( ) : (
<div className="RecentTxs-empty well"> <div className="RecentTxs-empty well">
<h2 className="RecentTxs-empty-text"> <h2 className="RecentTxs-empty-text">
No recent MyCrypto transactions found, try checking on {explorer}. {translate('NO_RECENT_TX_FOUND', { $explorer: explorer })}
</h2> </h2>
</div> </div>
)} )}
<p className="RecentTxs-help"> <p className="RecentTxs-help">
Only recent transactions sent from this address via MyCrypto on the {network.name} network {translate('RECENT_TX_HELP', { $network: network.name, $explorer: explorer })}
are listed here. If you don't see your transaction, you can view all of them on {explorer}.
</p> </p>
</React.Fragment> </React.Fragment>
); );

View File

@ -123,7 +123,9 @@ class RequestPayment extends React.Component<Props, {}> {
{!!eip681String.length && ( {!!eip681String.length && (
<div className="row form-group"> <div className="row form-group">
<label className="RequestPayment-title">{translate('Payment QR & Code')}</label> <label className="RequestPayment-title">
{translate('REQUEST_PAYMENT_QR_TITLE')}
</label>
<div className="col-xs-6"> <div className="col-xs-6">
<div className="RequestPayment-qr well well-lg"> <div className="RequestPayment-qr well well-lg">
<QRCode data={eip681String} /> <QRCode data={eip681String} />

View File

@ -46,7 +46,7 @@ export default class WalletInfo extends React.PureComponent<Props, State> {
<div className="col-xs-11"> <div className="col-xs-11">
<div className="input-group-wrapper"> <div className="input-group-wrapper">
<label className="input-group"> <label className="input-group">
<div className="input-group-header">{translate('x_Address')}</div> <div className="input-group-header">{translate('X_ADDRESS')}</div>
<Input readOnly={true} value={address} /> <Input readOnly={true} value={address} />
</label> </label>
</div> </div>
@ -59,12 +59,12 @@ export default class WalletInfo extends React.PureComponent<Props, State> {
{privateKey && ( {privateKey && (
<div className="row form-group"> <div className="row form-group">
<div className="col-xs-12"> <div className="col-xs-12">
<label>{translate('x_PrivKey')}</label> <label>{translate('X_PRIVKEY')}</label>
<TogglablePassword <TogglablePassword
disabled={true} disabled={true}
value={privateKey} value={privateKey}
isVisible={isPrivateKeyVisible} isVisible={isPrivateKeyVisible}
toggleAriaLabel={translateRaw('GEN_Aria_2')} toggleAriaLabel={translateRaw('GEN_ARIA_2')}
handleToggleVisibility={this.togglePrivateKey} handleToggleVisibility={this.togglePrivateKey}
/> />
</div> </div>
@ -75,7 +75,7 @@ export default class WalletInfo extends React.PureComponent<Props, State> {
<div className="Tab-content-pane"> <div className="Tab-content-pane">
<div className="row"> <div className="row">
<div className="col-xs-6"> <div className="col-xs-6">
<label>Public Address</label> <label>{translate('TOKEN_ADDR')}</label>
<div className="WalletInfo-qr well well-lg"> <div className="WalletInfo-qr well well-lg">
<QRCode data={address} /> <QRCode data={address} />
</div> </div>
@ -83,7 +83,7 @@ export default class WalletInfo extends React.PureComponent<Props, State> {
{privateKey && ( {privateKey && (
<div> <div>
<div className="col-xs-6"> <div className="col-xs-6">
<label>Private Key</label> <label>{translate('X_PRIVKEY2')}</label>
<div className="WalletInfo-qr well well-lg" onClick={this.togglePrivateKey}> <div className="WalletInfo-qr well well-lg" onClick={this.togglePrivateKey}>
<QRCode data={isPrivateKeyVisible ? privateKey : '0'} /> <QRCode data={isPrivateKeyVisible ? privateKey : '0'} />
{!isPrivateKeyVisible && ( {!isPrivateKeyVisible && (
@ -95,14 +95,14 @@ export default class WalletInfo extends React.PureComponent<Props, State> {
</div> </div>
<div className="col-xs-6"> <div className="col-xs-6">
<label>Utilities</label> <label>{translate('WALLET_INFO_UTILITIES')}</label>
<button className="btn btn-info btn-block" onClick={print(address, privateKey)}> <button className="btn btn-info btn-block" onClick={print(address, privateKey)}>
{translate('x_Print')} {translate('X_PRINT')}
</button> </button>
<button className="btn btn-info btn-block" onClick={this.toggleKeystoreModal}> <button className="btn btn-info btn-block" onClick={this.toggleKeystoreModal}>
Generate Keystore File {translate('GENERATE_KEYSTORE_TITLE')}
</button> </button>
</div> </div>
</div> </div>

View File

@ -1,6 +1,6 @@
import React from 'react'; import React from 'react';
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import translate from 'translations'; import translate, { translateRaw } from 'translations';
import TabSection from 'containers/TabSection'; import TabSection from 'containers/TabSection';
import { UnlockHeader } from 'components/ui'; import { UnlockHeader } from 'components/ui';
import { getWalletInst } from 'selectors/wallet'; import { getWalletInst } from 'selectors/wallet';
@ -40,28 +40,28 @@ class SendTransaction extends React.Component<Props> {
const tabs: Tab[] = [ const tabs: Tab[] = [
{ {
path: 'send', path: 'send',
name: translate('NAV_SendEther'), name: translate('NAV_SENDETHER'),
disabled: !!wallet && !!wallet.isReadOnly disabled: !!wallet && !!wallet.isReadOnly
}, },
{ {
path: 'request', path: 'request',
name: translate('Request Payment'), name: translate('NAV_REQUESTPAYMENT'),
disabled: this.props.requestDisabled disabled: this.props.requestDisabled
}, },
{ {
path: 'info', path: 'info',
name: translate('NAV_ViewWallet') name: translate('NAV_VIEWWALLET')
}, },
{ {
path: 'recent-txs', path: 'recent-txs',
name: translate('Recent Transactions') name: translate('NAV_RECENT_TX')
} }
]; ];
return ( return (
<TabSection> <TabSection>
<section className="Tab-content"> <section className="Tab-content">
<UnlockHeader title={translate('Account')} showGenerateLink={true} /> <UnlockHeader title={translateRaw('ACCOUNT')} showGenerateLink={true} />
{wallet && ( {wallet && (
<div className="SubTabs row"> <div className="SubTabs row">
<div className="col-sm-8"> <div className="col-sm-8">

View File

@ -15,7 +15,7 @@ export default class SignMessageButton extends React.Component<Props, {}> {
public render() { public render() {
return ( return (
<button className="SignMessage-sign btn btn-primary btn-lg" onClick={this.handleSignMessage}> <button className="SignMessage-sign btn btn-primary btn-lg" onClick={this.handleSignMessage}>
{translate('NAV_SignMsg')} {translate('NAV_SIGNMSG')}
</button> </button>
); );
} }
@ -34,10 +34,10 @@ export default class SignMessageButton extends React.Component<Props, {}> {
onSignMessage(signedMessage); onSignMessage(signedMessage);
showNotification( showNotification(
'success', 'success',
`Successfully signed message with address ${signedMessage.address}.` translate('SIGN_MSG_SUCCESS', { $address: signedMessage.address })
); );
} catch (err) { } catch (err) {
showNotification('danger', `Error signing message: ${err.message}`); showNotification('danger', translate('SIGN_MSG_FAIL', { $err: err.message }));
} }
}; };
} }

View File

@ -1,7 +1,7 @@
import React, { Component } from 'react'; import React, { Component } from 'react';
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import WalletDecrypt, { DISABLE_WALLETS } from 'components/WalletDecrypt'; import WalletDecrypt, { DISABLE_WALLETS } from 'components/WalletDecrypt';
import translate from 'translations'; import translate, { translateRaw } from 'translations';
import { showNotification, TShowNotification } from 'actions/notifications'; import { showNotification, TShowNotification } from 'actions/notifications';
import { resetWallet, TResetWallet } from 'actions/wallet'; import { resetWallet, TResetWallet } from 'actions/wallet';
import { ISignedMessage } from 'libs/signing'; import { ISignedMessage } from 'libs/signing';
@ -29,8 +29,7 @@ const initialState: State = {
signedMessage: null signedMessage: null
}; };
const messagePlaceholder = const messagePlaceholder = translateRaw('SIGN_MSG_PLACEHOLDER');
'This is a sweet message that you are signing to prove that you own the address you say you own.';
export class SignMessage extends Component<Props, State> { export class SignMessage extends Component<Props, State> {
public state: State = initialState; public state: State = initialState;
@ -52,12 +51,12 @@ export class SignMessage extends Component<Props, State> {
onClick={this.changeWallet} onClick={this.changeWallet}
> >
<i className="fa fa-refresh" /> <i className="fa fa-refresh" />
{translate('Change Wallet')} {translate('CHANGE_WALLET')}
</button> </button>
<div className="input-group-wrapper Deploy-field"> <div className="input-group-wrapper Deploy-field">
<label className="input-group"> <label className="input-group">
<div className="input-group-header">{translate('MSG_message')}</div> <div className="input-group-header">{translate('MSG_MESSAGE')}</div>
<TextArea <TextArea
className={`SignMessage-inputBox ${message ? 'is-valid' : 'is-invalid'}`} className={`SignMessage-inputBox ${message ? 'is-valid' : 'is-invalid'}`}
placeholder={messagePlaceholder} placeholder={messagePlaceholder}
@ -65,7 +64,7 @@ export class SignMessage extends Component<Props, State> {
onChange={this.handleMessageChange} onChange={this.handleMessageChange}
/> />
</label> </label>
<div className="SignMessage-help">{translate('MSG_info2')}</div> <div className="SignMessage-help">{translate('MSG_INFO2')}</div>
</div> </div>
<SignButton <SignButton
@ -78,7 +77,7 @@ export class SignMessage extends Component<Props, State> {
{!!signedMessage && ( {!!signedMessage && (
<div className="input-group-wrapper SignMessage-inputBox"> <div className="input-group-wrapper SignMessage-inputBox">
<label className="input-group"> <label className="input-group">
<div className="input-group-header">{translate('MSG_signature')}</div> <div className="input-group-header">{translate('MSG_SIGNATURE')}</div>
<TextArea <TextArea
className="SignMessage-inputBox" className="SignMessage-inputBox"
value={JSON.stringify(signedMessage, null, 2)} value={JSON.stringify(signedMessage, null, 2)}

View File

@ -39,7 +39,7 @@ export class VerifyMessage extends Component<Props, State> {
<div className="Tab-content-pane"> <div className="Tab-content-pane">
<div className="input-group-wrapper "> <div className="input-group-wrapper ">
<label className="input-group"> <label className="input-group">
<div className="input-group-header">{translate('MSG_signature')}</div> <div className="input-group-header">{translate('MSG_SIGNATURE')}</div>
<TextArea <TextArea
className={`VerifyMessage-inputBox ${signature ? 'is-valid' : 'is-invalid'}`} className={`VerifyMessage-inputBox ${signature ? 'is-valid' : 'is-invalid'}`}
placeholder={signaturePlaceholder} placeholder={signaturePlaceholder}
@ -55,13 +55,13 @@ export class VerifyMessage extends Component<Props, State> {
onClick={this.handleVerifySignedMessage} onClick={this.handleVerifySignedMessage}
disabled={false} disabled={false}
> >
{translate('MSG_verify')} {translate('MSG_VERIFY')}
</button> </button>
{!!verifiedAddress && {!!verifiedAddress &&
!!verifiedMessage && ( !!verifiedMessage && (
<div className="VerifyMessage-success alert alert-success"> <div className="VerifyMessage-success alert alert-success">
<strong>{verifiedAddress}</strong> did sign the message{' '} <strong>{verifiedAddress}</strong> {translate('SIGNED')}
<strong>{verifiedMessage}</strong>. <strong>{verifiedMessage}</strong>.
</div> </div>
)} )}

View File

@ -25,11 +25,11 @@ export default class SignAndVerifyMessage extends Component<RouteComponentProps<
const tabs = [ const tabs = [
{ {
path: 'sign', path: 'sign',
name: translate('NAV_SignMsg') name: translate('NAV_SIGNMSG')
}, },
{ {
path: 'verify', path: 'verify',
name: translate('MSG_verify') name: translate('MSG_VERIFY')
} }
]; ];

View File

@ -1,4 +1,5 @@
import React, { PureComponent } from 'react'; import React, { PureComponent } from 'react';
import translate from 'translations';
import QRCode from 'qrcode.react'; import QRCode from 'qrcode.react';
import './BitcoinQR.scss'; import './BitcoinQR.scss';
@ -13,19 +14,15 @@ export default class BitcoinQR extends PureComponent<Props, {}> {
return ( return (
<div className="BitcoinQR"> <div className="BitcoinQR">
<section className="row block swap-address text-center"> <section className="row block swap-address text-center">
<label> Your Address </label> <label>{translate('X_ADDRESS')}</label>
<div className="BitcoinQR-qr"> <div className="BitcoinQR-qr">
<QRCode value={`bitcoin:${paymentAddress}amount=${destinationAmount}`} /> <QRCode value={`bitcoin:${paymentAddress}amount=${destinationAmount}`} />
</div> </div>
<br /> <br />
<p className="text-danger"> <p className="text-danger">{translate('SWAP_TIME_LIMIT_WARNING')}</p>
Orders that take too long will have to be processed manually &amp; and may delay the {translate('SWAP_RECOMMENDED_TX_FEES', {
amount of time it takes to receive your coins. $link: 'https://shapeshift.io/#/btcfee'
<br /> })}
<a href="https://shapeshift.io/#/btcfee" target="_blank" rel="noopener noreferrer">
Please use the recommended TX fees seen here.
</a>
</p>
</section> </section>
</div> </div>
); );

View File

@ -8,7 +8,7 @@ import {
import SimpleButton from 'components/ui/SimpleButton'; import SimpleButton from 'components/ui/SimpleButton';
import { generateKindMax, generateKindMin, WhitelistedCoins, bityConfig } from 'config/bity'; import { generateKindMax, generateKindMin, WhitelistedCoins, bityConfig } from 'config/bity';
import React, { PureComponent } from 'react'; import React, { PureComponent } from 'react';
import translate from 'translations'; import translate, { translateRaw } from 'translations';
import { combineAndUpper } from 'utils/formatters'; import { combineAndUpper } from 'utils/formatters';
import { SwapDropdown, Input } from 'components/ui'; import { SwapDropdown, Input } from 'components/ui';
import Spinner from 'components/ui/Spinner'; import Spinner from 'components/ui/Spinner';
@ -81,9 +81,15 @@ export default class CurrencySwap extends PureComponent<Props, State> {
const rate = this.getMinMax(originKind, destKind); const rate = this.getMinMax(originKind, destKind);
let errString; let errString;
if (amount > rate.max) { if (amount > rate.max) {
errString = `Maximum ${rate.max} ${originKind}`; errString = translateRaw('SWAP_MAX_ERROR', {
$rate_max: rate.max.toString(),
$origin_id: originKind
});
} else { } else {
errString = `Minimum ${rate.min} ${originKind}`; errString = translateRaw('SWAP_MIN_ERROR', {
$rate_max: rate.min.toString(),
$origin_id: originKind
});
} }
return errString; return errString;
}; };
@ -340,7 +346,7 @@ export default class CurrencySwap extends PureComponent<Props, State> {
<div className="CurrencySwap-inner-wrap"> <div className="CurrencySwap-inner-wrap">
<div className="flex-spacer" /> <div className="flex-spacer" />
<div className="input-group-wrapper"> <div className="input-group-wrapper">
<div className="input-group-header">Deposit</div> <div className="input-group-header">{translate('SWAP_DEPOSIT_INPUT_LABEL')}</div>
<label className="input-group input-group-inline"> <label className="input-group input-group-inline">
<Input <Input
id="origin-swap-input" id="origin-swap-input"
@ -351,7 +357,7 @@ export default class CurrencySwap extends PureComponent<Props, State> {
: 'invalid' : 'invalid'
}`} }`}
type="number" type="number"
placeholder="Amount" placeholder={translateRaw('SEND_AMOUNT_SHORT')}
value={isNaN(origin.amount) ? '' : origin.amount} value={isNaN(origin.amount) ? '' : origin.amount}
onChange={this.onChangeAmount} onChange={this.onChangeAmount}
/> />
@ -366,7 +372,7 @@ export default class CurrencySwap extends PureComponent<Props, State> {
<div className="input-group-wrapper"> <div className="input-group-wrapper">
<label className="input-group input-group-inline"> <label className="input-group input-group-inline">
<div className="input-group-header">Recieve</div> <div className="input-group-header">{translate('SWAP_RECIEVE_INPUT_LABEL')}</div>
<Input <Input
id="destination-swap-input" id="destination-swap-input"
className={`${ className={`${
@ -376,7 +382,7 @@ export default class CurrencySwap extends PureComponent<Props, State> {
: 'invalid' : 'invalid'
}`} }`}
type="number" type="number"
placeholder="Amount" placeholder={translateRaw('SEND_AMOUNT_SHORT')}
value={isNaN(destination.amount) ? '' : destination.amount} value={isNaN(destination.amount) ? '' : destination.amount}
onChange={this.onChangeAmount} onChange={this.onChangeAmount}
/> />
@ -395,7 +401,7 @@ export default class CurrencySwap extends PureComponent<Props, State> {
<div className="CurrencySwap-submit"> <div className="CurrencySwap-submit">
<SimpleButton <SimpleButton
onClick={this.onClickStartSwap} onClick={this.onClickStartSwap}
text={translate('SWAP_init_CTA')} text={translateRaw('SWAP_INIT_CTA')}
disabled={this.state.disabled} disabled={this.state.disabled}
type="primary" type="primary"
/> />

View File

@ -122,7 +122,7 @@ class CurrentRates extends PureComponent<Props> {
public swapEl = (providerURL: string, providerLogo: string, children: any) => { public swapEl = (providerURL: string, providerLogo: string, children: any) => {
return ( return (
<article className="SwapRates"> <article className="SwapRates">
<h3 className="SwapRates-title">{translate('SWAP_rates')}</h3> <h3 className="SwapRates-title">{translate('SWAP_RATES')}</h3>
<section className="SwapRates-panel row"> <section className="SwapRates-panel row">
{children} {children}

View File

@ -31,7 +31,7 @@ class FieldsClass extends Component<Props> {
onClick={this.changeWallet} onClick={this.changeWallet}
> >
<i className="fa fa-refresh" /> <i className="fa fa-refresh" />
{translate('Change Wallet')} {translate('CHANGE_WALLET')}
</button> </button>
</div> </div>
<div className="col-xs-12"> <div className="col-xs-12">
@ -46,7 +46,7 @@ class FieldsClass extends Component<Props> {
<div className="row form-group"> <div className="row form-group">
<div className="col-xs-12"> <div className="col-xs-12">
<label>{translate('SEND_amount')}</label> <label>{translate('SEND_AMOUNT')}</label>
{currentBalance === null ? ( {currentBalance === null ? (
<div className="row text-center"> <div className="row text-center">
<Spinner /> <Spinner />
@ -56,10 +56,7 @@ class FieldsClass extends Component<Props> {
withProps={({ currentValue, isValid }) => ( withProps={({ currentValue, isValid }) => (
<React.Fragment> <React.Fragment>
{!isValid && ( {!isValid && (
<h5 style={{ color: 'red' }}> <h5 style={{ color: 'red' }}>{translate('INSUFFICIENT_FUNDS')}</h5>
WARNING: Your ether or token balance is not high enough to complete this
transaction! Please send more funds or switch to a different wallet
</h5>
)} )}
{isValid && ( {isValid && (
<Input <Input

View File

@ -14,19 +14,17 @@ export default class PaymentInfo extends PureComponent<Props, {}> {
const { origin } = this.props; const { origin } = this.props;
return ( return (
<section className="SwapPayment"> <section className="SwapPayment">
<h1> <h2>
<span>{translate('SWAP_order_CTA')}</span> {translate('SWAP_SEND_TO', {
<strong> $origin_amount: origin.amount.toString(),
{' '} $origin_label: origin.label
{origin.amount} {origin.label} })}
</strong>
<span> {translate('SENDModal_Content_2')}</span>
<Input <Input
className="SwapPayment-address" className="SwapPayment-address"
value={this.props.paymentAddress || undefined} value={this.props.paymentAddress || undefined}
disabled={true} disabled={true}
/> />
</h1> </h2>
</section> </section>
); );
} }

View File

@ -10,7 +10,7 @@ import SimpleButton from 'components/ui/SimpleButton';
import { donationAddressMap } from 'config'; import { donationAddressMap } from 'config';
import { isValidBTCAddress, isValidETHAddress } from 'libs/validators'; import { isValidBTCAddress, isValidETHAddress } from 'libs/validators';
import React, { PureComponent } from 'react'; import React, { PureComponent } from 'react';
import translate from 'translations'; import translate, { translateRaw } from 'translations';
import { combineAndUpper } from 'utils/formatters'; import { combineAndUpper } from 'utils/formatters';
import './ReceivingAddress.scss'; import './ReceivingAddress.scss';
import { Input } from 'components/ui'; import { Input } from 'components/ui';
@ -75,7 +75,7 @@ export default class ReceivingAddress extends PureComponent<StateProps & ActionP
<div className="col-sm-8 col-sm-offset-2 col-xs-12"> <div className="col-sm-8 col-sm-offset-2 col-xs-12">
<label className="SwapAddress-address"> <label className="SwapAddress-address">
<h4 className="SwapAddress-address-label"> <h4 className="SwapAddress-address-label">
{translate('SWAP_rec_add')} ({destinationId}) {translate('SWAP_REC_ADD')} ({destinationId})
</h4> </h4>
<Input <Input
@ -95,7 +95,7 @@ export default class ReceivingAddress extends PureComponent<StateProps & ActionP
<section className="SwapAddress-submit row"> <section className="SwapAddress-submit row">
<SimpleButton <SimpleButton
text={translate('SWAP_start_CTA')} text={translateRaw('SWAP_START_CTA')}
onClick={this.onClickPartTwoComplete} onClick={this.onClickPartTwoComplete}
disabled={!validAddress} disabled={!validAddress}
loading={isPostingOrder} loading={isPostingOrder}

View File

@ -3,6 +3,7 @@ import './SupportFooter.scss';
import { SwapInput } from 'actions/swap'; import { SwapInput } from 'actions/swap';
import { NormalizedBityRates, NormalizedShapeshiftRates } from 'reducers/swap/types'; import { NormalizedBityRates, NormalizedShapeshiftRates } from 'reducers/swap/types';
import { TextArea } from 'components/ui'; import { TextArea } from 'components/ui';
import translate from 'translations';
interface Props { interface Props {
origin: SwapInput; origin: SwapInput;
@ -75,11 +76,11 @@ Rate: ${rates[pair].rate} ${origin.label}/${destination.label}`;
target="_blank" target="_blank"
rel="noopener noreferrer" rel="noopener noreferrer"
> >
Issue with your Swap? Contact support {translate('SWAP_SUPPORT')}
</a> </a>
<div className="SupportFooter-fallback"> <div className="SupportFooter-fallback">
<p onClick={this.toggleFallback}> <p onClick={this.toggleFallback}>
<small>Click here if link doesn't work</small> <small>{translate('SWAP_SUPPORT_LINK_BROKEN')}</small>
</p> </p>
{open ? ( {open ? (
<TextArea defaultValue={fallbackBody} className="form-control input-sm" rows={9} /> <TextArea defaultValue={fallbackBody} className="form-control input-sm" rows={9} />

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