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 }) => (
<div className="input-group-wrapper">
<label className="input-group">
<div className="input-group-header">{translate('SEND_addr')}</div>
<div className="input-group-header">{translate('SEND_ADDR_SHORT')}</div>
<Input
className={`input-group-input ${isValid ? '' : 'invalid'}`}
type="text"

View File

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

View File

@ -98,7 +98,7 @@ class AccountInfo extends React.Component<Props, State> {
const wallet = this.props.wallet as LedgerWallet | TrezorWallet;
return (
<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-address-icon">
<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>
{confirmAddr ? (
<span className="AccountInfo-address-confirm">
@ -145,7 +147,7 @@ class AccountInfo extends React.Component<Props, State> {
)}
<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">
<li className="AccountInfo-list-item AccountInfo-balance">
<span
@ -182,7 +184,7 @@ class AccountInfo extends React.Component<Props, State> {
{(!!blockExplorer || !!tokenExplorer) && (
<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">
{!!blockExplorer && (
<li className="AccountInfo-list-item">

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -9,6 +9,7 @@ import { SerializedTransaction } from 'components/renderCbs';
import { AppState } from 'reducers';
import { getFrom, getUnit, isEtherTransaction } from 'selectors/transaction';
import { toChecksumAddress } from 'ethereumjs-util';
import translate from 'translations';
interface StateProps {
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} />
)}
<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>
</div>
</div>
@ -45,7 +46,9 @@ class AddressesClass extends Component<StateProps> {
<img src={arrow} alt="arrow" />
</div>
<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
className="small tx-modal-address-tkn-contract-link"
href={ETHAddressExplorer(to)}
@ -62,7 +65,7 @@ class AddressesClass extends Component<StateProps> {
address={toFormatted}
/>
<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>
</div>
</div>

View File

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

View File

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

View File

@ -9,7 +9,7 @@ export const DataField: React.SFC<{}> = () => (
withProps={({ data: { raw }, dataExists, onChange, readOnly }) => (
<div className="input-group-wrapper">
<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
className={dataExists ? 'is-valid' : 'is-invalid'}
type="text"

View File

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

View File

@ -3,6 +3,7 @@ import Modal, { IButton } from 'components/ui/Modal';
import { HelpLink } from 'components/ui';
import { HELP_ARTICLE } from 'config';
import './DisclaimerModal.scss';
import translate from 'translations';
interface Props {
isOpen: boolean;
@ -10,7 +11,9 @@ interface Props {
}
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 (
<Modal isOpen={isOpen} title="Disclaimer" buttons={buttons} handleClose={handleClose}>
<p>

View File

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

View File

@ -14,6 +14,7 @@ import DisclaimerModal from './DisclaimerModal';
import { NewTabLink } from 'components/ui';
import OnboardModal from 'containers/OnboardModal';
import './index.scss';
import { translateRaw } from 'translations';
const SocialMediaLink = ({ link, text }: Link) => {
return (
@ -58,39 +59,39 @@ const PRODUCT_INFO: Link[] = [
{
link:
'https://chrome.google.com/webstore/detail/etheraddresslookup/pdknmigbbbhmllnmgdfalmedcmcefdfn',
text: 'Ether Address Lookup'
text: translateRaw('ETHER_ADDRESS_LOOKUP')
},
{
link:
'https://chrome.google.com/webstore/detail/ethersecuritylookup/bhhfhgpgmifehjdghlbbijjaimhmcgnf',
text: 'Ether Security Lookup'
text: translateRaw('ETHER_SECURITY_LOOKUP')
},
{
link: 'https://etherscamdb.info/',
text: 'EtherScamDB'
text: translateRaw('ETHERSCAMDB')
},
{
link: 'https://www.mycrypto.com/helpers.html',
text: 'Helpers & ENS Debugging'
text: translateRaw('FOOTER_HELP_AND_DEBUGGING')
},
{
link: 'mailto:press@mycrypto.com',
text: 'Press Inquiries'
text: translateRaw('FOOTER_PRESS')
}
];
const AFFILIATES: Link[] = [
{
link: ledgerReferralURL,
text: 'Buy a Ledger Wallet'
text: translateRaw('LEDGER_REFERAL_1')
},
{
link: trezorReferralURL,
text: 'Buy a TREZOR'
text: translateRaw('TREZOR_REFERAL')
},
{
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">
<a href="https://mycrypto.com">MyCrypto.com</a>
<NewTabLink href={knowledgeBaseURL}>Help & Support</NewTabLink>
<NewTabLink href="https://about.mycrypto.com">Our Team</NewTabLink>
<NewTabLink href={knowledgeBaseURL}>{translateRaw('FOOTER_SUPPORT')}</NewTabLink>
<NewTabLink href="https://about.mycrypto.com">
{translateRaw('FOOTER_TEAM')}
</NewTabLink>
</div>
<p className="Footer-about-text">
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>
<p className="Footer-about-text">{translateRaw('FOOTER_ABOUT')}</p>
<div className="Footer-about-legal">
<div className="Footer-about-legal-text">
© {new Date().getFullYear()} MyCrypto, Inc.
</div>
<div className="Footer-about-legal-text">
<a onClick={this.toggleModal}>Disclaimer</a>
<a onClick={this.toggleModal}>{translateRaw('DISCLAIMER')}</a>
</div>
<div className="Footer-about-legal-text">v{VERSION}</div>
</div>
</div>
<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">
{AFFILIATES.map(link => (
<NewTabLink key={link.text} href={link.link}>
{AFFILIATES.map((link, i) => (
<NewTabLink key={i} href={link.link}>
{link.text}
</NewTabLink>
))}
</div>
<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>
<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>
<div className="Footer-support-friends">
{FRIENDS.map(link => (
<NewTabLink key={link.text} href={link.link}>
{FRIENDS.map((link, i) => (
<NewTabLink key={i} href={link.link}>
{link.text}
</NewTabLink>
))}

View File

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

View File

@ -55,14 +55,14 @@ export default class GenerateKeystoreModal extends React.Component<Props, State>
return (
<Modal
title={translateRaw('Generate Keystore File')}
title={translateRaw('GENERATE_KEYSTORE_ACTION')}
isOpen={this.props.isOpen}
handleClose={this.handleClose}
>
<form className="GenKeystore" onSubmit={this.handleSubmit}>
<div className="input-group-wrapper GenKeystore-field">
<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
name="privateKey"
value={privateKey}
@ -75,12 +75,14 @@ export default class GenerateKeystoreModal extends React.Component<Props, State>
</div>
<div className="input-group-wrapper GenKeystore-field">
<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
name="password"
value={password}
onChange={this.handleInput}
placeholder={translateRaw('Minimum 9 characters')}
placeholder={translateRaw('INPUT_PASSWORD_PLACEHOLDER', {
$pass_length: MINIMUM_PASSWORD_LENGTH.toString()
})}
isValid={isPasswordValid}
/>
</label>
@ -91,24 +93,20 @@ export default class GenerateKeystoreModal extends React.Component<Props, State>
className="GenKeystore-button btn btn-primary btn-block"
disabled={!isPrivateKeyValid || !isPasswordValid}
>
{translate('Generate Keystore File')}
{translate('GENERATE_KEYSTORE_ACTION')}
</button>
) : hasError ? (
<p className="alert alert-danger">
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>
<p className="alert alert-danger">{translate('GENERATE_KEYSTORE_FAILED')}</p>
) : (
<a
onClick={this.handleClose}
href={keystoreFile.blob}
className="GenKeystore-button btn btn-success btn-block"
aria-label={translateRaw('x_Keystore')}
aria-describedby={translateRaw('x_KeystoreDesc')}
aria-label={translateRaw('X_KEYSTORE')}
aria-describedby={translateRaw('X_KEYSTOREDESC')}
download={keystoreFile.filename}
>
{translate('Download Keystore File')}
{translate('ACTION_12')}
</a>
)}
</form>

View File

@ -6,7 +6,7 @@ export const GenerateTransaction: React.SFC<{}> = () => (
<GenerateTransactionFactory
withProps={({ disabled, isWeb3Wallet, 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>
)}
/>

View File

@ -84,7 +84,7 @@ class CustomNodeModal extends React.Component<Props, State> {
},
{
type: 'default',
text: translate('x_Cancel'),
text: translate('ACTION_2'),
onClick: handleClose
}
];
@ -105,19 +105,18 @@ class CustomNodeModal extends React.Component<Props, State> {
handleClose={handleClose}
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 && (
<div className="alert alert-warning small">
You already have a node called '{conflictedNode.name}' that matches this one, saving
this will overwrite it
{translate('CUSTOM_NODE_CONFLICT', { conflictedNode: conflictedNode.name })}
</div>
)}
<form className="CustomNodeModal">
<div className="flex-wrapper">
<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
className={`input-group-input ${this.state.name && invalids.name ? 'invalid' : ''}`}
type="text"
@ -143,7 +142,7 @@ class CustomNodeModal extends React.Component<Props, State> {
{network === CUSTOM.value && (
<div className="flex-wrapper">
<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
className={`input-group-input ${
this.state.customNetworkId && invalids.customNetworkId ? 'invalid' : ''
@ -155,7 +154,7 @@ class CustomNodeModal extends React.Component<Props, State> {
/>
</label>
<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
className={`input-group-input ${
this.state.customNetworkUnit && invalids.customNetworkUnit ? 'invalid' : ''
@ -167,7 +166,7 @@ class CustomNodeModal extends React.Component<Props, State> {
/>
</label>
<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
className={`input-group-input ${
this.state.customNetworkChainId && invalids.customNetworkChainId
@ -184,7 +183,7 @@ class CustomNodeModal extends React.Component<Props, State> {
)}
<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
className={`input-group-input ${this.state.url && invalids.url ? 'invalid' : ''}`}
type="text"
@ -202,13 +201,13 @@ class CustomNodeModal extends React.Component<Props, State> {
checked={this.state.hasAuth}
onChange={() => this.setState({ hasAuth: !this.state.hasAuth })}
/>
<span>HTTP Basic Authentication</span>
<span>{translate('CUSTOM_NETWORK_HTTP_AUTH')}</span>
</label>
{this.state.hasAuth && (
<div className="flex-wrapper ">
<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
className={`input-group-input ${
this.state.username && invalids.username ? 'invalid' : ''
@ -219,7 +218,7 @@ class CustomNodeModal extends React.Component<Props, State> {
/>
</label>
<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
className={`input-group-input ${
this.state.password && invalids.password ? 'invalid' : ''

View File

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

View File

@ -1,4 +1,4 @@
@import "common/sass/variables";
@import 'common/sass/variables';
.NavigationLink {
display: inline-block;
@ -14,7 +14,7 @@
min-height: 2.75rem;
&:after {
content: "";
content: '';
background: $brand-primary;
height: 2px;
width: 100%;
@ -45,10 +45,10 @@
}
}
#NAV_Swap a:before {
content:"";
#NAV_SWAP a:before {
content: '';
display: inline-block;
margin-top: -.1rem;
margin-top: -0.1rem;
width: 1.3rem;
height: 1.3rem;
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 { AppState } from 'reducers';
import { resetWallet, TResetWallet } from 'actions/wallet';
import translate, { translateRaw } from 'translations';
interface Props extends RouteComponentProps<{}> {
// State
@ -42,17 +43,17 @@ class LogOutPromptClass extends React.Component<Props, State> {
public render() {
const buttons: IButton[] = [
{ text: 'Log Out', type: 'primary', onClick: this.onConfirm },
{ text: 'Cancel', type: 'default', onClick: this.onCancel }
{ text: translate('ACTION_7'), type: 'primary', onClick: this.onConfirm },
{ text: translate('ACTION_2'), type: 'default', onClick: this.onCancel }
];
return (
<Modal
title="You are about to log out"
title={translateRaw('WALLET_LOGOUT_MODAL_TITLE')}
isOpen={this.state.openModal}
handleClose={this.onCancel}
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>
);
}

View File

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

View File

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

View File

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

View File

@ -49,7 +49,7 @@ class SendButtonFactoryClass extends Component<Props> {
// shows the json representation of the transaction
const leftTxCompare = serializedTransaction && (
<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} />
</div>
);
@ -63,7 +63,7 @@ class SendButtonFactoryClass extends Component<Props> {
<label>
{walletType.isWeb3Wallet
? 'Serialized Transaction Parameters'
: translate('SEND_signed')}
: translate('SEND_SIGNED')}
</label>
<TextArea
value={addHexPrefix(serializedTransaction.toString('hex'))}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -71,7 +71,7 @@ const TransactionDataTable: React.SFC<Props> = ({ data, receipt, network }) => {
const rows: TableRow[] = [
{
label: 'Status',
label: translate('TX_STATUS'),
data: (
<React.Fragment>
<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>
},
{
label: 'Block Number',
label: translate('TX_BLOCK_NUMB'),
data: receipt && <MaybeLink href={explorer.block}>{receipt.blockNumber}</MaybeLink>
},
{
label: translate('OFFLINE_Step1_Label_1'),
label: translate('OFFLINE_STEP1_LABEL_1'),
data: (
<MaybeLink href={explorer.from}>
<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: (
<MaybeLink href={explorer.to}>
<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} />
},
{
label: translate('OFFLINE_Step2_Label_3'),
label: translate('OFFLINE_STEP2_LABEL_3'),
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" />
},
{
label: 'Gas Used',
label: translate('TX_GAS_USED'),
data: receipt && <UnitDisplay value={receipt.gasUsed} unit="wei" />
},
{
label: 'Transaction Fee',
label: translate('CONFIRM_TX_FEE'),
data: receipt && (
<UnitDisplay
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 &&
receipt.contractAddress && (
<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
},
{
label: translate('TRANS_data'),
label: translate('TRANS_DATA'),
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) {
content = (
<React.Fragment>
<h2 className="TxStatus-title">Transaction Found</h2>
<div className="TxStatus-data">
<TransactionDataTable network={network} data={tx.data} receipt={tx.receipt} />
</div>
@ -53,13 +52,13 @@ class TransactionStatus extends React.Component<Props> {
} else if (tx && tx.error) {
content = (
<div className="TxStatus-error">
<h2 className="TxStatus-error-title">{translate('tx_notFound')}</h2>
<p className="TxStatus-error-desc">{translate('tx_notFound_1')}</p>
<h2 className="TxStatus-error-title">{translate('TX_NOTFOUND')}</h2>
<p className="TxStatus-error-desc">{translate('TX_NOTFOUND_1')}</p>
<ul className="TxStatus-error-list">
<li>Make sure you copied the Transaction Hash correctly</li>
<li>{translate('tx_notFound_2')}</li>
<li>{translate('tx_notFound_3')}</li>
<li>{translate('tx_notFound_4')}</li>
<li>{translate('TX_NOTFOUND_5')}</li>
<li>{translate('TX_NOTFOUND_2')}</li>
<li>{translate('TX_NOTFOUND_3')}</li>
<li>{translate('TX_NOTFOUND_4')}</li>
</ul>
</div>
);

View File

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

View File

@ -18,7 +18,7 @@ import {
TResetWallet
} from 'actions/wallet';
import { reset, TReset, ResetAction } from 'actions/transaction';
import translate from 'translations';
import translate, { translateRaw } from 'translations';
import {
KeystoreDecrypt,
LedgerNanoSDecrypt,
@ -50,6 +50,7 @@ import MetamaskIcon from 'assets/images/wallets/metamask.svg';
import MistIcon from 'assets/images/wallets/mist.svg';
import TrezorIcon from 'assets/images/wallets/trezor.svg';
import './WalletDecrypt.scss';
import { withRouter, RouteComponentProps } from 'react-router';
interface OwnProps {
hidden?: boolean;
@ -75,7 +76,7 @@ interface StateProps {
isPasswordPending: AppState['wallet']['isPasswordPending'];
}
type Props = OwnProps & StateProps & DispatchProps;
type Props = OwnProps & StateProps & DispatchProps & RouteComponentProps<{}>;
type UnlockParams = {} | PrivateKeyValue;
interface State {
@ -92,6 +93,7 @@ interface BaseWalletInfo {
helpLink: string;
isReadOnly?: boolean;
attemptUnlock?: boolean;
redirect?: string;
}
export interface SecureWalletInfo extends BaseWalletInfo {
@ -108,15 +110,15 @@ interface MiscWalletInfo extends InsecureWalletInfo {}
const WEB3_TYPES = {
CipherProvider: {
lid: 'x_Cipher',
lid: 'X_CIPHER',
icon: CipherIcon
},
MetamaskInpageProvider: {
lid: 'x_MetaMask',
lid: 'X_METAMASK',
icon: MetamaskIcon
},
EthereumProvider: {
lid: 'x_Mist',
lid: 'X_MIST',
icon: MistIcon
}
};
@ -133,311 +135,319 @@ const SECURE_WALLETS = Object.values(SecureWalletName);
const INSECURE_WALLETS = Object.values(InsecureWalletName);
const MISC_WALLETS = Object.values(MiscWalletName);
export class WalletDecrypt extends Component<Props, State> {
// https://github.com/Microsoft/TypeScript/issues/13042
// index signature should become [key: Wallets] (from config) once typescript bug is fixed
public WALLETS: Wallets = {
[SecureWalletName.WEB3]: {
lid: WEB3_TYPE && WEB3_TYPES[WEB3_TYPE] ? WEB3_TYPES[WEB3_TYPE].lid : 'x_Web3',
icon: WEB3_TYPE && WEB3_TYPES[WEB3_TYPE] && WEB3_TYPES[WEB3_TYPE].icon,
description: 'ADD_Web3Desc',
component: Web3Decrypt,
initialParams: {},
unlock: this.props.unlockWeb3,
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: ''
const WalletDecrypt = withRouter<Props>(
class WalletDecryptClass extends Component<RouteComponentProps<{}> & Props, State> {
// https://github.com/Microsoft/TypeScript/issues/13042
// index signature should become [key: Wallets] (from config) once typescript bug is fixed
public WALLETS: Wallets = {
[SecureWalletName.WEB3]: {
lid: WEB3_TYPE && WEB3_TYPES[WEB3_TYPE] ? WEB3_TYPES[WEB3_TYPE].lid : 'X_WEB3',
icon: WEB3_TYPE && WEB3_TYPES[WEB3_TYPE] && WEB3_TYPES[WEB3_TYPE].icon,
description: 'ADD_WEB3DESC',
component: Web3Decrypt,
initialParams: {},
unlock: this.props.unlockWeb3,
attemptUnlock: true,
helpLink: `${knowledgeBaseURL}/migration/moving-from-private-key-to-metamask`
},
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: ''
[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'
},
unlock: this.props.unlockPrivateKey,
helpLink: `${knowledgeBaseURL}/private-keys-passwords/difference-beween-private-key-and-keystore-file.html`
},
[MiscWalletName.VIEW_ONLY]: {
lid: 'View Address',
example: donationAddressMap.ETH,
component: ViewOnlyDecrypt,
initialParams: {},
unlock: this.props.setWallet,
helpLink: '',
isReadOnly: true
}
};
[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,
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 = {
selectedWalletKey: null,
value: null,
hasAcknowledgedInsecure: false
};
public state: State = {
selectedWalletKey: null,
value: null,
hasAcknowledgedInsecure: false
};
public componentWillReceiveProps(nextProps: Props) {
// Reset state when unlock is hidden / revealed
if (nextProps.hidden !== this.props.hidden) {
this.setState({
value: null,
selectedWalletKey: null
});
}
}
public getSelectedWallet() {
const { selectedWalletKey } = this.state;
if (!selectedWalletKey) {
return null;
public componentWillReceiveProps(nextProps: Props) {
// Reset state when unlock is hidden / revealed
if (nextProps.hidden !== this.props.hidden) {
this.setState({
value: null,
selectedWalletKey: null
});
}
}
return this.WALLETS[selectedWalletKey];
}
public getSelectedWallet() {
const { selectedWalletKey } = this.state;
if (!selectedWalletKey) {
return null;
}
public getDecryptionComponent() {
const { selectedWalletKey, hasAcknowledgedInsecure } = this.state;
const selectedWallet = this.getSelectedWallet();
if (!selectedWalletKey || !selectedWallet) {
return null;
return this.WALLETS[selectedWalletKey];
}
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 (
<div className="WalletDecrypt-decrypt">
<InsecureWalletWarning
walletType={translate(selectedWallet.lid)}
onContinue={this.handleAcknowledgeInsecure}
onCancel={this.clearWalletChoice}
/>
<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={(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>
);
}
return (
<div className="WalletDecrypt-decrypt">
<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 = () => {
this.setState({ hasAcknowledgedInsecure: true });
};
public handleAcknowledgeInsecure = () => {
this.setState({ hasAcknowledgedInsecure: true });
};
public buildWalletOptions() {
const { computedDisabledWallets } = this.props;
const { reasons } = computedDisabledWallets;
public buildWalletOptions() {
const { computedDisabledWallets } = this.props;
const { reasons } = computedDisabledWallets;
return (
<div className="WalletDecrypt-wallets">
<h2 className="WalletDecrypt-wallets-title">{translate('DECRYPT_ACCESS')}</h2>
return (
<div className="WalletDecrypt-wallets">
<h2 className="WalletDecrypt-wallets-title">{translate('decrypt_Access')}</h2>
<div className="WalletDecrypt-wallets-row">
{SECURE_WALLETS.map((walletType: SecureWalletName) => {
const wallet = this.WALLETS[walletType];
return (
<WalletButton
key={walletType}
name={translate(wallet.lid)}
description={translate(wallet.description)}
icon={wallet.icon}
helpLink={wallet.helpLink}
walletType={walletType}
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 className="WalletDecrypt-wallets-row">
{SECURE_WALLETS.map((walletType: SecureWalletName) => {
const wallet = this.WALLETS[walletType];
return (
<WalletButton
key={walletType}
name={translateRaw(wallet.lid)}
description={translateRaw(wallet.description)}
icon={wallet.icon}
helpLink={wallet.helpLink}
walletType={walletType}
isSecure={true}
isDisabled={this.isWalletDisabled(walletType)}
disableReason={reasons[walletType]}
onClick={this.handleWalletChoice}
/>
);
})}
</div>
)}
</div>
);
}
<div className="WalletDecrypt-wallets-row">
{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) => {
const wallet = this.WALLETS[walletType];
{MISC_WALLETS.map((walletType: MiscWalletName) => {
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) {
return;
{this.props.showGenerateLink && (
<div className="WalletDecrypt-wallets-generate">
<Link to="/generate">{translate('DONT_HAVE_WALLET_PROMPT')}</Link>
</div>
)}
</div>
);
}
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();
}
public handleWalletChoice = async (walletType: WalletName) => {
const wallet = this.WALLETS[walletType];
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({
selectedWalletKey: walletType,
value: wallet.initialParams,
selectedWalletKey: null,
value: null,
hasAcknowledgedInsecure: false
});
}, timeout);
};
};
public clearWalletChoice = () => {
this.setState({
selectedWalletKey: null,
value: null,
hasAcknowledgedInsecure: false
});
};
public render() {
const { hidden } = this.props;
const selectedWallet = this.getSelectedWallet();
const decryptionComponent = this.getDecryptionComponent();
return (
<div>
{!hidden && (
<article className="Tab-content-pane">
<div className="WalletDecrypt">
<TransitionGroup>
{decryptionComponent && selectedWallet ? (
<CSSTransition classNames="DecryptContent" timeout={500} key="decrypt">
{decryptionComponent}
</CSSTransition>
) : (
<CSSTransition classNames="DecryptContent" timeout={500} key="wallets">
{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;
public render() {
const { hidden } = this.props;
const selectedWallet = this.getSelectedWallet();
const decryptionComponent = this.getDecryptionComponent();
return (
<div>
{!hidden && (
<article className="Tab-content-pane">
<div className="WalletDecrypt">
<TransitionGroup>
{decryptionComponent && selectedWallet ? (
<CSSTransition classNames="DecryptContent" timeout={500} key="decrypt">
{decryptionComponent}
</CSSTransition>
) : (
<CSSTransition classNames="DecryptContent" timeout={500} key="wallets">
{this.buildWalletOptions()}
</CSSTransition>
)}
</TransitionGroup>
</div>
</article>
)}
</div>
);
}
// 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);
};
public onChange = (value: UnlockParams) => {
this.setState({ value });
};
private isWalletDisabled = (walletKey: WalletName) => {
return this.props.computedDisabledWallets.wallets.indexOf(walletKey) !== -1;
};
}
public onUnlock = (payload: any) => {
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) {
const { disabledWallets } = ownProps;
@ -460,7 +470,7 @@ function mapStateToProps(state: AppState, ownProps: Props) {
};
}
export default connect<StateProps, DispatchProps>(mapStateToProps, {
export default connect(mapStateToProps, {
unlockKeystore,
unlockMnemonic,
unlockPrivateKey,
@ -469,4 +479,4 @@ export default connect<StateProps, DispatchProps>(mapStateToProps, {
resetWallet,
resetTransactionState: reset,
showNotification
})(WalletDecrypt);
})(WalletDecrypt) as React.ComponentClass<OwnProps>;

View File

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

View File

@ -1,7 +1,8 @@
import React from 'react';
import { HelpLink } from 'components/ui';
import { HELP_ARTICLE } from 'config';
import './InsecureWalletWarning.scss';
import translate from 'translations';
import { knowledgeBaseURL } from 'config/data';
interface Props {
walletType: string | React.ReactElement<string>;
@ -43,15 +44,15 @@ export class InsecureWalletWarning extends React.Component<Props, State> {
const checkboxes: Checkbox[] = [
{
name: 'hasAcknowledgedWallets',
label: 'I acknowledge that I can and should use MetaMask or a Hardware Wallet'
label: translate('INSECURE_WALLET_WARNING_1')
},
{
name: 'hasAcknowledgedDownload',
label: 'I acknowledge that I can and should download and run MyCrypto locally'
label: translate('INSECURE_WALLET_WARNING_2')
},
{
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(
@ -61,38 +62,31 @@ export class InsecureWalletWarning extends React.Component<Props, State> {
return (
<div className="WalletWarning">
<h2 className="WalletWarning-title">
This is <u>not</u> a recommended way to access your wallet
</h2>
<h2 className="WalletWarning-title">{translate('INSECURE_WALLET_TYPE_TITLE')}</h2>
<p className="WalletWarning-desc">
Entering your {walletType} on a website is <strong>dangerous</strong>. If our website is
compromised, or you accidentally visit a phishing website, you could{' '}
<strong>lose all of your funds</strong>. Before you continue, please consider:
{translate('INSECURE_WALLET_TYPE_DESC', { $wallet_type: walletType as string })}
</p>
<ul className="WalletWarning-bullets">
<li>
Using <HelpLink article={HELP_ARTICLE.MIGRATE_TO_METAMASK}>MetaMask</HelpLink> or a{' '}
<HelpLink article={HELP_ARTICLE.HARDWARE_WALLET_RECOMMENDATIONS}>
Hardware Wallet
</HelpLink>{' '}
to access your wallet
{translate('INSECURE_WALLET_RECOMMEND_1', {
$metamask_article: knowledgeBaseURL + '/' + HELP_ARTICLE.MIGRATE_TO_METAMASK,
$hardware_wallet_article:
knowledgeBaseURL + '/' + HELP_ARTICLE.HARDWARE_WALLET_RECOMMENDATIONS
})}
</li>
<li>
<HelpLink article={HELP_ARTICLE.RUNNING_LOCALLY}>
Downloading MyCrypto and running it offline & locally
</HelpLink>
{translate('INSECURE_WALLET_RECOMMEND_2', {
$run_local_article: knowledgeBaseURL + '/' + HELP_ARTICLE.RUNNING_LOCALLY
})}
</li>
<li>
Reading{' '}
<HelpLink article={HELP_ARTICLE.SECURING_YOUR_ETH}>
How to Protect Yourself and Your Funds
</HelpLink>
{translate('INSECURE_WALLET_RECOMMEND_3', {
$secure_your_eth_article: knowledgeBaseURL + '/' + HELP_ARTICLE.SECURING_YOUR_ETH
})}
</li>
</ul>
<p className="WalletWarning-check">
If you must use your {walletType} online, please double-check the URL & SSL certificate.
It should say <code>{'https://www.mycrypto.com'}</code>
& <code>MyCrypto, Inc (US)</code> in your URL bar.
{translate('WALLET_WARNING_CHECK', { $wallet_type: walletType as string })}
</p>
<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%' }}>
<a className="btn btn-default btn-block" id="aria1" tabIndex={0} role="button">
{translate('ADD_Radio_2_short')}
{translate('ADD_RADIO_2_SHORT')}
</a>
</label>
{isWalletPending ? <Spinner /> : ''}
@ -63,13 +63,13 @@ export class KeystoreDecrypt extends PureComponent {
value={password}
onChange={this.onPasswordChange}
onKeyDown={this.onKeyDown}
placeholder={translateRaw('x_Password')}
placeholder={translateRaw('INPUT_PASSWORD_LABEL')}
type="password"
/>
</div>
<button className="btn btn-primary btn-block" disabled={unlockDisabled}>
{translate('ADD_Label_6_short')}
{translate('ADD_LABEL_6_SHORT')}
</button>
</form>
);

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -11,14 +11,14 @@ export const Web3Decrypt: React.SFC<Props> = ({ onUnlock }) => (
<div className="Web3Decrypt">
<div>
<button className="Web3Decrypt-decrypt btn btn-primary btn-lg btn-block" onClick={onUnlock}>
{translate('ADD_MetaMask')}
{translate('ADD_METAMASK')}
</button>
</div>
<div>
<NewTabLink
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"
/>
</div>

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -4,16 +4,16 @@ import OnboardSlide from './OnboardSlide';
import onboardIconSix from 'assets/images/onboarding/slide-06.svg';
const WhyMewSlide = () => {
const header = translate('ONBOARD_whymyc_title');
const header = translate('ONBOARD_WHYMYC_TITLE');
const content = (
<ul>
<li>{translate('ONBOARD_whymyc_content__1')}</li>
<li>{translate('ONBOARD_whymyc_content__2')}</li>
<li>{translate('ONBOARD_whymyc_content__3')}</li>
<li>{translate('ONBOARD_whymyc_content__4')}</li>
<li>{translate('ONBOARD_whymyc_content__5')}</li>
<li>{translate('ONBOARD_whymyc_content__6')}</li>
<li>{translate('ONBOARD_WHYMYC_CONTENT__1')}</li>
<li>{translate('ONBOARD_WHYMYC_CONTENT__2')}</li>
<li>{translate('ONBOARD_WHYMYC_CONTENT__3')}</li>
<li>{translate('ONBOARD_WHYMYC_CONTENT__4')}</li>
<li>{translate('ONBOARD_WHYMYC_CONTENT__5')}</li>
<li>{translate('ONBOARD_WHYMYC_CONTENT__6')}</li>
</ul>
);
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';
const WhySlide = () => {
const header = translate('ONBOARD_why_title');
const header = translate('ONBOARD_WHY_TITLE');
const content = (
<div>
<h5>{translate('ONBOARD_why_content__1')}</h5>
<h5>{translate('ONBOARD_WHY_CONTENT__1')}</h5>
<ul>
<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__4')}</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__2')}</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__5')}</li>
<li className="text-danger">{translate('ONBOARD_WHY_CONTENT__6')}</li>
</ul>
<h5>{translate('ONBOARD_why_content__7')}</h5>
<h5>{translate('ONBOARD_WHY_CONTENT__7')}</h5>
<ul>
<li>{translate('ONBOARD_why_content__8')}</li>
<li>{translate('ONBOARD_why_content__9')}</li>
<li>{translate('ONBOARD_why_content__10')}</li>
<li>{translate('ONBOARD_WHY_CONTENT__8')}</li>
<li>{translate('ONBOARD_WHY_CONTENT__9')}</li>
<li>{translate('ONBOARD_WHY_CONTENT__10')}</li>
</ul>
</div>
);

View File

@ -74,7 +74,7 @@ class OnboardModal extends React.Component<Props, State> {
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
setTimeout(() => {
@ -91,25 +91,25 @@ class OnboardModal extends React.Component<Props, State> {
const firstButtons: IButton[] = [
{
disabled: slideNumber === NUMBER_OF_SLIDES,
text: 'Next',
text: translate('ACTION_6'),
type: 'primary',
onClick: this.handleNextSlide
},
{
disabled: slideNumber === 1,
text: 'Back',
text: translate('ACTION_4'),
type: 'default',
onClick: this.handlePreviousSlide
}
];
const lastButtons: IButton[] = [
{
text: 'Finish',
text: translate('ACTION_10'),
type: 'primary',
onClick: this.closeModal
},
{
text: 'Back',
text: translate('ACTION_4'),
type: 'default',
onClick: this.handlePreviousSlide
}

View File

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

View File

@ -66,10 +66,10 @@ class TxHashInput extends React.Component<Props, State> {
value={hash}
onChange={this.handleSelectTx}
options={selectOptions}
placeholder="Select a recent transaction..."
placeholder={translate('SELECT_RECENT_TX')}
searchable={false}
/>
<em className="TxHashInput-recent-separator">or</em>
<em className="TxHashInput-recent-separator">{translate('OR')}</em>
</div>
)}
@ -82,12 +82,12 @@ class TxHashInput extends React.Component<Props, State> {
{isValidETHAddress(hash) && (
<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>
)}
<button className="TxHashInput-submit btn btn-primary btn-block">
{translate('NAV_CheckTxStatus')}
{translate('NAV_CHECKTXSTATUS')}
</button>
</form>
);

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -33,21 +33,22 @@ export default class EnterPassword extends Component<Props, State> {
const isPasswordValid = passwordValidity === 'valid';
const isConfirmValid = confirmedPassword ? password === confirmedPassword : undefined;
const canSubmit = isPasswordValid && isConfirmValid && !isGenerating;
return (
<Template>
<form className="EnterPw" onSubmit={canSubmit ? this.handleSubmit : undefined}>
<h1 className="EnterPw-title" aria-live="polite">
Generate a {translate('x_Keystore2')}
{translate('GENERATE_KEYSTORE_TITLE')}
</h1>
<div className="input-group-wrapper EnterPw-password">
<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
className={!isPasswordValid && password.length > 0 ? 'invalid' : ''}
isValid={isPasswordValid && password.length > 0}
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}
onBlur={this.showFeedback}
/>
@ -62,21 +63,21 @@ export default class EnterPassword extends Component<Props, State> {
<div className="input-group-wrapper EnterPw-password">
<label className="input-group">
<div className="input-group-header">Confirm password</div>
<div className="input-group-header">{translate('INPUT_CONFIRM_PASSWORD_LABEL')}</div>
<TogglablePassword
className={!isConfirmValid && password.length > 0 ? 'invalid' : ''}
isValid={isConfirmValid && password.length > 0}
value={confirmedPassword}
placeholder={translateRaw('GEN_Placeholder_1')}
placeholder={translateRaw('GEN_PLACEHOLDER_1')}
onChange={this.onConfirmChange}
/>
</label>
</div>
<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>
<p className="EnterPw-warning">{translate('x_PasswordDesc')}</p>
<p className="EnterPw-warning">{translate('X_PASSWORDDESC')}</p>
</form>
</Template>
);
@ -101,18 +102,20 @@ export default class EnterPassword extends Component<Props, State> {
}
private getFeedback() {
let feedback = '';
let feedback: string = '';
const validity = this.getPasswordValidity();
if (validity !== 'valid') {
const { password, passwordValidation } = this.state;
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) {
feedback = `This password is not strong enough. ${passwordValidation.feedback.warning}.`;
feedback = translateRaw('WEAK_PASSWORD') + ' ' + passwordValidation.feedback.warning;
} 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">
{/* Private Key */}
<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="input-group-header">{translate('GEN_Label_5')}</h1>
<h1 className="GenPaper-title">{translate('GEN_LABEL_5')}</h1>
<Input
value={stripHexPrefix(props.privateKey)}
aria-label={translateRaw('x_PrivKey')}
aria-label={translateRaw('X_PRIVKEY')}
aria-describedby="x_PrivKeyDesc"
type="text"
readOnly={true}
@ -30,29 +29,21 @@ const PaperWallet: React.SFC<Props> = props => (
</label>
{/* Download Paper Wallet */}
<h2 className="GenPaper-title">{translate('x_Print')}</h2>
<h2 className="GenPaper-title">{translate('X_PRINT')}</h2>
<div className="GenPaper-paper">
<PrintableWallet address={props.keystore.address} privateKey={props.privateKey} />
</div>
{/* Warning */}
<div className="GenPaper-warning">
<p>
<strong>Do not lose it!</strong> It cannot be recovered if you lose it.
</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>
<p>{translate('DL_WALLET_WARNING_1')}</p>
<p>{translate('DL_WALLET_WARNING_2')}</p>
<p>{translate('DL_WALLET_WARNING_3')}</p>
</div>
{/* Continue button */}
<button className="GenPaper-continue btn btn-default" onClick={props.continue}>
{translate('NAV_ViewWallet')}
{translate('NAV_VIEWWALLET')}
</button>
</div>
</Template>

View File

@ -51,19 +51,12 @@ export default class GenerateMnemonic extends React.Component<{}, State> {
content = (
<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">
{isConfirming
? `
Re-enter your phrase to confirm you copied it correctly. If you
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.
`}
? translate('MNEMONIC_DESCRIPTOION_1')
: translate('MNEMONIC_DESCRIPTOION_2')}
</p>
<div className="GenerateMnemonic-words">
@ -80,7 +73,7 @@ export default class GenerateMnemonic extends React.Component<{}, State> {
className="GenerateMnemonic-buttons-btn btn btn-default"
onClick={this.regenerateWordArray}
>
<i className="fa fa-refresh" /> Regenerate Phrase
<i className="fa fa-refresh" /> {translate('REGENERATE_MNEMONIC')}
</button>
)}
<button
@ -88,7 +81,7 @@ export default class GenerateMnemonic extends React.Component<{}, State> {
disabled={!canContinue}
onClick={this.goToNextStep}
>
Confirm Phrase
{translate('CONFIRM_MNEMONIC')}
</button>
</div>

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -15,7 +15,7 @@ export default class SignMessageButton extends React.Component<Props, {}> {
public render() {
return (
<button className="SignMessage-sign btn btn-primary btn-lg" onClick={this.handleSignMessage}>
{translate('NAV_SignMsg')}
{translate('NAV_SIGNMSG')}
</button>
);
}
@ -34,10 +34,10 @@ export default class SignMessageButton extends React.Component<Props, {}> {
onSignMessage(signedMessage);
showNotification(
'success',
`Successfully signed message with address ${signedMessage.address}.`
translate('SIGN_MSG_SUCCESS', { $address: signedMessage.address })
);
} 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 { connect } from 'react-redux';
import WalletDecrypt, { DISABLE_WALLETS } from 'components/WalletDecrypt';
import translate from 'translations';
import translate, { translateRaw } from 'translations';
import { showNotification, TShowNotification } from 'actions/notifications';
import { resetWallet, TResetWallet } from 'actions/wallet';
import { ISignedMessage } from 'libs/signing';
@ -29,8 +29,7 @@ const initialState: State = {
signedMessage: null
};
const messagePlaceholder =
'This is a sweet message that you are signing to prove that you own the address you say you own.';
const messagePlaceholder = translateRaw('SIGN_MSG_PLACEHOLDER');
export class SignMessage extends Component<Props, State> {
public state: State = initialState;
@ -52,12 +51,12 @@ export class SignMessage extends Component<Props, State> {
onClick={this.changeWallet}
>
<i className="fa fa-refresh" />
{translate('Change Wallet')}
{translate('CHANGE_WALLET')}
</button>
<div className="input-group-wrapper Deploy-field">
<label className="input-group">
<div className="input-group-header">{translate('MSG_message')}</div>
<div className="input-group-header">{translate('MSG_MESSAGE')}</div>
<TextArea
className={`SignMessage-inputBox ${message ? 'is-valid' : 'is-invalid'}`}
placeholder={messagePlaceholder}
@ -65,7 +64,7 @@ export class SignMessage extends Component<Props, State> {
onChange={this.handleMessageChange}
/>
</label>
<div className="SignMessage-help">{translate('MSG_info2')}</div>
<div className="SignMessage-help">{translate('MSG_INFO2')}</div>
</div>
<SignButton
@ -78,7 +77,7 @@ export class SignMessage extends Component<Props, State> {
{!!signedMessage && (
<div className="input-group-wrapper SignMessage-inputBox">
<label className="input-group">
<div className="input-group-header">{translate('MSG_signature')}</div>
<div className="input-group-header">{translate('MSG_SIGNATURE')}</div>
<TextArea
className="SignMessage-inputBox"
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="input-group-wrapper ">
<label className="input-group">
<div className="input-group-header">{translate('MSG_signature')}</div>
<div className="input-group-header">{translate('MSG_SIGNATURE')}</div>
<TextArea
className={`VerifyMessage-inputBox ${signature ? 'is-valid' : 'is-invalid'}`}
placeholder={signaturePlaceholder}
@ -55,13 +55,13 @@ export class VerifyMessage extends Component<Props, State> {
onClick={this.handleVerifySignedMessage}
disabled={false}
>
{translate('MSG_verify')}
{translate('MSG_VERIFY')}
</button>
{!!verifiedAddress &&
!!verifiedMessage && (
<div className="VerifyMessage-success alert alert-success">
<strong>{verifiedAddress}</strong> did sign the message{' '}
<strong>{verifiedAddress}</strong> {translate('SIGNED')}
<strong>{verifiedMessage}</strong>.
</div>
)}

View File

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

View File

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

View File

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

View File

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

View File

@ -31,7 +31,7 @@ class FieldsClass extends Component<Props> {
onClick={this.changeWallet}
>
<i className="fa fa-refresh" />
{translate('Change Wallet')}
{translate('CHANGE_WALLET')}
</button>
</div>
<div className="col-xs-12">
@ -46,7 +46,7 @@ class FieldsClass extends Component<Props> {
<div className="row form-group">
<div className="col-xs-12">
<label>{translate('SEND_amount')}</label>
<label>{translate('SEND_AMOUNT')}</label>
{currentBalance === null ? (
<div className="row text-center">
<Spinner />
@ -56,10 +56,7 @@ class FieldsClass extends Component<Props> {
withProps={({ currentValue, isValid }) => (
<React.Fragment>
{!isValid && (
<h5 style={{ color: 'red' }}>
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>
<h5 style={{ color: 'red' }}>{translate('INSUFFICIENT_FUNDS')}</h5>
)}
{isValid && (
<Input

View File

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

View File

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

View File

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