From e504bc6215967bfa0408d1eac862beed3f4f3a46 Mon Sep 17 00:00:00 2001 From: Dan Finlay Date: Mon, 19 Mar 2018 11:28:02 -0700 Subject: [PATCH 01/12] Add connecting indication templates --- app/_locales/en/messages.json | 15 +++++++++++++++ ui/app/app.js | 33 +++++++++++++++++++++++++++------ 2 files changed, 42 insertions(+), 6 deletions(-) diff --git a/app/_locales/en/messages.json b/app/_locales/en/messages.json index 35a360c84..8267658b1 100644 --- a/app/_locales/en/messages.json +++ b/app/_locales/en/messages.json @@ -604,6 +604,21 @@ "ropsten": { "message": "Ropsten Test Network" }, + "connectingToMainnet": { + "message": "Connecting to Main Ethereum Network" + }, + "connectingToRopsten": { + "message": "Connecting to Ropsten Test Network" + }, + "connectingToKovan": { + "message": "Connecting to Kovan Test Network" + }, + "connectingToRinkeby": { + "message": "Connecting to Rinkeby Test Network" + }, + "connectingToUnknown": { + "message": "Connecting to Unknown Network" + }, "sampleAccountName": { "message": "E.g. My new account", "description": "Help user understand concept of adding a human-readable name to their account" diff --git a/ui/app/app.js b/ui/app/app.js index 954299a6a..6d9296131 100644 --- a/ui/app/app.js +++ b/ui/app/app.js @@ -132,7 +132,7 @@ App.prototype.render = function () { } = props const isLoadingNetwork = network === 'loading' && props.currentView.name !== 'config' const loadMessage = loadingMessage || isLoadingNetwork ? - `Connecting to ${this.getNetworkName()}` : null + this.getConnectingLabel() : null log.debug('Main ui render function') return ( @@ -550,6 +550,27 @@ App.prototype.toggleMetamaskActive = function () { } } +App.prototype.getConnectingLabel = function () { + const { provider } = this.props + const providerName = provider.type + + let name + + if (providerName === 'mainnet') { + name = t('connectingToMainnet') + } else if (providerName === 'ropsten') { + name = t('connectingToRopsten') + } else if (providerName === 'kovan') { + name = t('connectingToRopsten') + } else if (providerName === 'rinkeby') { + name = t('connectingToRinkeby') + } else { + name = t('connectingToUnknown') + } + + return name +} + App.prototype.getNetworkName = function () { const { provider } = this.props const providerName = provider.type @@ -557,15 +578,15 @@ App.prototype.getNetworkName = function () { let name if (providerName === 'mainnet') { - name = 'Main Ethereum Network' + name = t('mainnet') } else if (providerName === 'ropsten') { - name = 'Ropsten Test Network' + name = t('ropsten') } else if (providerName === 'kovan') { - name = 'Kovan Test Network' + name = t('kovan') } else if (providerName === 'rinkeby') { - name = 'Rinkeby Test Network' + name = t('rinkeby') } else { - name = 'Unknown Private Network' + name = t('unknownNetwork') } return name From 17371bb7ecaf5fba3773cd2a0e8f8784d2c4bd49 Mon Sep 17 00:00:00 2001 From: Dan Finlay Date: Mon, 19 Mar 2018 11:30:45 -0700 Subject: [PATCH 02/12] Add login templates --- ui/app/unlock.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ui/app/unlock.js b/ui/app/unlock.js index ac97d04d0..322808619 100644 --- a/ui/app/unlock.js +++ b/ui/app/unlock.js @@ -67,7 +67,7 @@ UnlockScreen.prototype.render = function () { style: { margin: 10, }, - }, 'Log In'), + }, t('login')), h('p.pointer', { onClick: () => { @@ -81,7 +81,7 @@ UnlockScreen.prototype.render = function () { color: 'rgb(247, 134, 28)', textDecoration: 'underline', }, - }, 'Restore from seed phrase'), + }, t('restoreFromSeed')), h('p.pointer', { onClick: () => { @@ -94,7 +94,7 @@ UnlockScreen.prototype.render = function () { textDecoration: 'underline', marginTop: '32px', }, - }, 'Use classic interface'), + }, t('classicInterface')), ]) ) } From 2e7d4db2dec000d31ad967400d25b46aabf70e29 Mon Sep 17 00:00:00 2001 From: Dan Finlay Date: Mon, 19 Mar 2018 11:43:22 -0700 Subject: [PATCH 03/12] Add recover and backup tempaltes --- app/_locales/en/messages.json | 18 ++++++++++ .../keychains/hd/recover-seed/confirmation.js | 7 ++-- ui/app/keychains/hd/restore-vault.js | 35 +++++++++++-------- 3 files changed, 42 insertions(+), 18 deletions(-) diff --git a/app/_locales/en/messages.json b/app/_locales/en/messages.json index 8267658b1..cbc6b3a3c 100644 --- a/app/_locales/en/messages.json +++ b/app/_locales/en/messages.json @@ -83,6 +83,9 @@ "buyCoinbaseExplainer": { "message": "Coinbase is the world’s most popular way to buy and sell bitcoin, ethereum, and litecoin." }, + "ok": { + message: "Ok" + }, "cancel": { "message": "Cancel" }, @@ -244,6 +247,12 @@ "enterPasswordConfirm": { "message": "Enter your password to confirm" }, + "passwordNotLongEnough": { + "message": "Password not long enough" + }, + "passwordsDontMatch": { + "message": "Passwords Don't Match" + }, "etherscanView": { "message": "View account on Etherscan" }, @@ -583,12 +592,18 @@ "restoreFromSeed": { "message": "Restore from seed phrase" }, + "restoreVault": { + "message": "Restore Vault" + }, "required": { "message": "Required" }, "retryWithMoreGas": { "message": "Retry with a higher gas price here" }, + "walletSeed": { + "message": "Wallet Seed" + }, "revealSeedWords": { "message": "Reveal Seed Words" }, @@ -639,6 +654,9 @@ "secretPhrase": { "message": "Enter your secret twelve word phrase here to restore your vault." }, + "newPassword8Chars": { + "message": "New Password (min 8 chars)" + }, "seedPhraseReq": { "message": "seed phrases are 12 words long" }, diff --git a/ui/app/keychains/hd/recover-seed/confirmation.js b/ui/app/keychains/hd/recover-seed/confirmation.js index 4335186a5..bc5339549 100644 --- a/ui/app/keychains/hd/recover-seed/confirmation.js +++ b/ui/app/keychains/hd/recover-seed/confirmation.js @@ -4,6 +4,7 @@ const Component = require('react').Component const connect = require('react-redux').connect const h = require('react-hyperscript') const actions = require('../../../actions') +const t = require('../../../../i18n') module.exports = connect(mapStateToProps)(RevealSeedConfirmation) @@ -49,13 +50,13 @@ RevealSeedConfirmation.prototype.render = function () { }, }, [ - h('h4', 'Do not recover your seed words in a public place! These words can be used to steal all your accounts.'), + h('h4', t('revealSeedWordsWarning')), // confirmation h('input.large-input.letter-spacey', { type: 'password', id: 'password-box', - placeholder: 'Enter your password to confirm', + placeholder: t('enterPasswordConfirm'), onKeyPress: this.checkConfirmation.bind(this), style: { width: 260, @@ -91,7 +92,7 @@ RevealSeedConfirmation.prototype.render = function () { ), props.inProgress && ( - h('span.in-progress-notification', 'Generating Seed...') + h('span.in-progress-notification', t('generatingSeed')) ), ]), ]) diff --git a/ui/app/keychains/hd/restore-vault.js b/ui/app/keychains/hd/restore-vault.js index cb4088f61..5e4e004cf 100644 --- a/ui/app/keychains/hd/restore-vault.js +++ b/ui/app/keychains/hd/restore-vault.js @@ -2,6 +2,7 @@ const inherits = require('util').inherits const PersistentForm = require('../../../lib/persistent-form') const connect = require('react-redux').connect const h = require('react-hyperscript') +const t = require('../../../i18n') const actions = require('../../actions') module.exports = connect(mapStateToProps)(RestoreVaultScreen) @@ -36,23 +37,23 @@ RestoreVaultScreen.prototype.render = function () { padding: 6, }, }, [ - 'Restore Vault', + t('restoreVault'), ]), // wallet seed entry - h('h3', 'Wallet Seed'), + h('h3', t('walletSeed')), h('textarea.twelve-word-phrase.letter-spacey', { dataset: { persistentFormId: 'wallet-seed', }, - placeholder: 'Enter your secret twelve word phrase here to restore your vault.', + placeholder: t('secretPhrase'), }), // password h('input.large-input.letter-spacey', { type: 'password', id: 'password-box', - placeholder: 'New Password (min 8 chars)', + placeholder: t('newPassword8Chars'), dataset: { persistentFormId: 'password', }, @@ -66,7 +67,7 @@ RestoreVaultScreen.prototype.render = function () { h('input.large-input.letter-spacey', { type: 'password', id: 'password-box-confirm', - placeholder: 'Confirm Password', + placeholder: t('confirmPassword'), onKeyPress: this.createOnEnter.bind(this), dataset: { persistentFormId: 'password-confirmation', @@ -93,16 +94,20 @@ RestoreVaultScreen.prototype.render = function () { // cancel h('button.primary', { onClick: this.showInitializeMenu.bind(this), - }, 'CANCEL'), + style: { + textTransform: 'uppercase', + }, + }, t('cancel')), // submit h('button.primary', { onClick: this.createNewVaultAndRestore.bind(this), - }, 'OK'), - + style: { + textTransform: 'uppercase', + }, + }, t('ok')), ]), ]) - ) } @@ -131,13 +136,13 @@ RestoreVaultScreen.prototype.createNewVaultAndRestore = function () { var passwordConfirmBox = document.getElementById('password-box-confirm') var passwordConfirm = passwordConfirmBox.value if (password.length < 8) { - this.warning = 'Password not long enough' + this.warning = t('passwordNotLongEnough') this.props.dispatch(actions.displayWarning(this.warning)) return } if (password !== passwordConfirm) { - this.warning = 'Passwords don\'t match' + this.warning = t('passwordsDontMatch') this.props.dispatch(actions.displayWarning(this.warning)) return } @@ -147,18 +152,18 @@ RestoreVaultScreen.prototype.createNewVaultAndRestore = function () { // true if the string has more than a space between words. if (seed.split(' ').length > 1) { - this.warning = 'there can only be a space between words' + this.warning = t('spaceBetween') this.props.dispatch(actions.displayWarning(this.warning)) return } // true if seed contains a character that is not between a-z or a space if (!seed.match(/^[a-z ]+$/)) { - this.warning = 'seed words only have lowercase characters' - this.props.dispatch(actions.displayWarning(this.warning)) + this.warning = t('loweCaseWords') + this.props.dispatch(actions.displayWarning(this.warning)) return } if (seed.split(' ').length !== 12) { - this.warning = 'seed phrases are 12 words long' + this.warning = t('seedPhraseReq') this.props.dispatch(actions.displayWarning(this.warning)) return } From 293ca6c9a630b939c97e4939e0416a57d8bad79c Mon Sep 17 00:00:00 2001 From: Dan Finlay Date: Mon, 19 Mar 2018 12:02:34 -0700 Subject: [PATCH 04/12] Add template for settings and info --- app/_locales/en/messages.json | 9 +++++++ ui/app/settings.js | 48 ++++++++++++++++++----------------- 2 files changed, 34 insertions(+), 23 deletions(-) diff --git a/app/_locales/en/messages.json b/app/_locales/en/messages.json index cbc6b3a3c..e2ce68b3b 100644 --- a/app/_locales/en/messages.json +++ b/app/_locales/en/messages.json @@ -619,6 +619,9 @@ "ropsten": { "message": "Ropsten Test Network" }, + "currentRpc": { + "message": "Current RPC" + }, "connectingToMainnet": { "message": "Connecting to Main Ethereum Network" }, @@ -687,6 +690,9 @@ "settings": { "message": "Settings" }, + "info": { + "message": "Info" + }, "shapeshiftBuy": { "message": "Buy with Shapeshift" }, @@ -723,6 +729,9 @@ "stateLogsDescription": { "message": "State logs contain your public account addresses and sent transactions." }, + "stateLogError": { + "message": "Error in retrieving state logs." + }, "submit": { "message": "Submit" }, diff --git a/ui/app/settings.js b/ui/app/settings.js index 466f739d5..60d68bfed 100644 --- a/ui/app/settings.js +++ b/ui/app/settings.js @@ -10,6 +10,7 @@ const TabBar = require('./components/tab-bar') const SimpleDropdown = require('./components/dropdowns/simple-dropdown') const ToggleButton = require('react-toggle-button') const { OLD_UI_NETWORK_TYPE } = require('../../app/scripts/config').enums +const t = require('../i18n') const getInfuraCurrencyOptions = () => { const sortedCurrencies = infuraCurrencies.objects.sort((a, b) => { @@ -44,8 +45,8 @@ class Settings extends Component { return h('div.settings__tabs', [ h(TabBar, { tabs: [ - { content: 'Settings', key: 'settings' }, - { content: 'Info', key: 'info' }, + { content: t('settings'), key: 'settings' }, + { content: t('info'), key: 'info' }, ], defaultTab: activeTab, tabSelected: key => this.setState({ activeTab: key }), @@ -84,7 +85,7 @@ class Settings extends Component { h('div.settings__content-item', [ h('div.settings__content-item-col', [ h(SimpleDropdown, { - placeholder: 'Select Currency', + placeholder: t('selectCurrency'), options: getInfuraCurrencyOptions(), selectedOption: currentCurrency, onSelect: newCurrency => setCurrentCurrency(newCurrency), @@ -101,31 +102,31 @@ class Settings extends Component { switch (provider.type) { case 'mainnet': - title = 'Current Network' - value = 'Main Ethereum Network' + title = t('currentNetwork') + value = t('mainnet') color = '#038789' break case 'ropsten': - title = 'Current Network' - value = 'Ropsten Test Network' + title = t('currentNetwork') + value = t('ropsten') color = '#e91550' break case 'kovan': - title = 'Current Network' - value = 'Kovan Test Network' + title = t('currentNetwork') + value = t('kovan') color = '#690496' break case 'rinkeby': - title = 'Current Network' - value = 'Rinkeby Test Network' + title = t('currentNetwork') + value = t('rinkeby') color = '#ebb33f' break default: - title = 'Current RPC' + title = t('currentRpc') value = provider.rpcTarget } @@ -146,12 +147,12 @@ class Settings extends Component { return ( h('div.settings__content-row', [ h('div.settings__content-item', [ - h('span', 'New RPC URL'), + h('span', t('newRPC')), ]), h('div.settings__content-item', [ h('div.settings__content-item-col', [ h('input.settings__input', { - placeholder: 'New RPC URL', + placeholder: t('newRPC'), onChange: event => this.setState({ newRpc: event.target.value }), onKeyPress: event => { if (event.key === 'Enter') { @@ -164,7 +165,7 @@ class Settings extends Component { event.preventDefault() this.validateRpc(this.state.newRpc) }, - }, 'Save'), + }, t('save')), ]), ]), ]) @@ -180,9 +181,9 @@ class Settings extends Component { const appendedRpc = `http://${newRpc}` if (validUrl.isWebUri(appendedRpc)) { - displayWarning('URIs require the appropriate HTTP/HTTPS prefix.') + displayWarning(t('uriErrorMsg')) } else { - displayWarning('Invalid RPC URI') + displayWarning(t('invalidRPC')) } } } @@ -194,7 +195,7 @@ class Settings extends Component { h('div', 'State Logs'), h( 'div.settings__content-description', - 'State logs contain your public account addresses and sent transactions.' + t('stateLogsDescription') ), ]), h('div.settings__content-item', [ @@ -203,13 +204,13 @@ class Settings extends Component { onClick (event) { window.logStateString((err, result) => { if (err) { - this.state.dispatch(actions.displayWarning('Error in retrieving state logs.')) + this.state.dispatch(actions.displayWarning(t('stateLogError'))) } else { exportAsFile('MetaMask State Logs.json', result) } }) }, - }, 'Download State Logs'), + }, t('downloadStateLogs')), ]), ]), ]) @@ -229,7 +230,7 @@ class Settings extends Component { event.preventDefault() revealSeedConfirmation() }, - }, 'Reveal Seed Words'), + }, t('revealSeedWords')), ]), ]), ]) @@ -249,7 +250,7 @@ class Settings extends Component { event.preventDefault() setFeatureFlagToBeta() }, - }, 'Use old UI'), + }, t('useOldUI')), ]), ]), ]) @@ -268,7 +269,7 @@ class Settings extends Component { event.preventDefault() showResetAccountConfirmationModal() }, - }, 'Reset Account'), + }, t('resetAccount')), ]), ]), ]) @@ -445,3 +446,4 @@ const mapDispatchToProps = dispatch => { } module.exports = connect(mapStateToProps, mapDispatchToProps)(Settings) + From f5b0d56b9d0b0ae0d4076ff296fdea87316fd32c Mon Sep 17 00:00:00 2001 From: Dan Finlay Date: Mon, 19 Mar 2018 12:37:10 -0700 Subject: [PATCH 05/12] Add send screen template --- app/_locales/en/messages.json | 14 +++++++++++++- ui/app/send-v2.js | 30 +++++++++++++++--------------- 2 files changed, 28 insertions(+), 16 deletions(-) diff --git a/app/_locales/en/messages.json b/app/_locales/en/messages.json index e2ce68b3b..875662cc5 100644 --- a/app/_locales/en/messages.json +++ b/app/_locales/en/messages.json @@ -84,7 +84,7 @@ "message": "Coinbase is the world’s most popular way to buy and sell bitcoin, ethereum, and litecoin." }, "ok": { - message: "Ok" + "message": "Ok" }, "cancel": { "message": "Cancel" @@ -282,6 +282,9 @@ "from": { "message": "From" }, + "to": { + "message": "To: " + }, "fromToSame": { "message": "From and To address cannot be the same" }, @@ -412,6 +415,9 @@ "knowledgeDataBase": { "message": "Visit our Knowledge Base" }, + "max": { + "message": "Max" + }, "lessThanMax": { "message": "must be less than or equal to $1.", "description": "helper for inputting hex as decimal input" @@ -684,9 +690,15 @@ "sendTokens": { "message": "Send Tokens" }, + "onlySendToEtherAddress": { + "message": "Only send to an Ethereum address." + }, "sendTokensAnywhere": { "message": "Send Tokens to anyone with an Ethereum account" }, + "required": { + "Required" + }, "settings": { "message": "Settings" }, diff --git a/ui/app/send-v2.js b/ui/app/send-v2.js index fc1df1f51..dbfa6025d 100644 --- a/ui/app/send-v2.js +++ b/ui/app/send-v2.js @@ -1,6 +1,7 @@ const { inherits } = require('util') const PersistentForm = require('../lib/persistent-form') const h = require('react-hyperscript') +const t = require('../i18n') const ethAbi = require('ethereumjs-abi') const ethUtil = require('ethereumjs-util') @@ -180,13 +181,12 @@ SendTransactionScreen.prototype.componentDidUpdate = function (prevProps) { SendTransactionScreen.prototype.renderHeader = function () { const { selectedToken, clearSend, goHome } = this.props - const tokenText = selectedToken ? 'tokens' : 'ETH' return h('div.page-container__header', [ - h('div.page-container__title', selectedToken ? 'Send Tokens' : 'Send ETH'), + h('div.page-container__title', selectedToken ? t('sendTokens') : t('sendETH')), - h('div.page-container__subtitle', `Only send ${tokenText} to an Ethereum address.`), + h('div.page-container__subtitle', t('onlySendToEtherAddress')), h('div.page-container__header-close', { onClick: () => { @@ -257,11 +257,11 @@ SendTransactionScreen.prototype.handleToChange = function (to) { let toError = null if (!to) { - toError = 'Required' + toError = t('required') } else if (!isValidAddress(to)) { - toError = 'Recipient address is invalid' + toError = t('invalidAddressRecipient') } else if (to === from) { - toError = 'From and To address cannot be the same' + toError = t('fromToSame') } updateSendTo(to) @@ -277,9 +277,9 @@ SendTransactionScreen.prototype.renderToRow = function () { h('div.send-v2__form-label', [ - 'To:', + t('to'), - this.renderErrorMessage('to'), + this.renderErrorMessage(t('to')), ]), @@ -377,11 +377,11 @@ SendTransactionScreen.prototype.validateAmount = function (value) { ) if (conversionRate && !sufficientBalance) { - amountError = 'Insufficient funds.' + amountError = t('insufficientFunds') } else if (verifyTokenBalance && !sufficientTokens) { - amountError = 'Insufficient tokens.' + amountError = t('insufficientTokens') } else if (amountLessThanZero) { - amountError = 'Can not send negative amounts of ETH.' + amountError = t('negativeETH') } updateSendErrors({ amount: amountError }) @@ -411,7 +411,7 @@ SendTransactionScreen.prototype.renderAmountRow = function () { setMaxModeTo(true) this.setAmountToMax() }, - }, [ !maxModeOn ? 'Max' : '' ]), + }, [ !maxModeOn ? t('max') : '' ]), ]), h('div.send-v2__form-field', [ @@ -439,7 +439,7 @@ SendTransactionScreen.prototype.renderGasRow = function () { return h('div.send-v2__form-row', [ - h('div.send-v2__form-label', 'Gas fee:'), + h('div.send-v2__form-label', h('gasFee')), h('div.send-v2__form-field', [ @@ -507,11 +507,11 @@ SendTransactionScreen.prototype.renderFooter = function () { clearSend() goHome() }, - }, 'Cancel'), + }, t('cancel')), h('button.btn-clear.page-container__footer-button', { disabled: !noErrors || !gasTotal || missingTokenBalance, onClick: event => this.onSubmit(event), - }, 'Next'), + }, t('next')), ]) } From de98cb403974df4ed8cea5ea82f81065ce9e6c0e Mon Sep 17 00:00:00 2001 From: Thomas Date: Tue, 20 Mar 2018 02:33:46 -0700 Subject: [PATCH 06/12] Remove duplicate keys --- app/_locales/en/messages.json | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/app/_locales/en/messages.json b/app/_locales/en/messages.json index 875662cc5..95f46106a 100644 --- a/app/_locales/en/messages.json +++ b/app/_locales/en/messages.json @@ -282,9 +282,6 @@ "from": { "message": "From" }, - "to": { - "message": "To: " - }, "fromToSame": { "message": "From and To address cannot be the same" }, @@ -696,9 +693,6 @@ "sendTokensAnywhere": { "message": "Send Tokens to anyone with an Ethereum account" }, - "required": { - "Required" - }, "settings": { "message": "Settings" }, @@ -763,7 +757,7 @@ "message": "Test Faucet" }, "to": { - "message": "To" + "message": "To: " }, "toETHviaShapeShift": { "message": "$1 to ETH via ShapeShift", From 85a612b34de27c3f4dcaa070e39cf88d21541652 Mon Sep 17 00:00:00 2001 From: Thomas Date: Tue, 20 Mar 2018 02:34:12 -0700 Subject: [PATCH 07/12] I18n add-token.js --- ui/app/add-token.js | 43 ++++++++++++++++++++++--------------------- 1 file changed, 22 insertions(+), 21 deletions(-) diff --git a/ui/app/add-token.js b/ui/app/add-token.js index b8878b772..b3a5bdc20 100644 --- a/ui/app/add-token.js +++ b/ui/app/add-token.js @@ -26,6 +26,7 @@ const fuse = new Fuse(contractList, { const actions = require('./actions') const ethUtil = require('ethereumjs-util') const { tokenInfoGetter } = require('./token-util') +const t = require('../i18n') const emptyAddr = '0x0000000000000000000000000000000000000000' @@ -139,28 +140,28 @@ AddTokenScreen.prototype.validate = function () { if (customAddress) { const validAddress = ethUtil.isValidAddress(customAddress) if (!validAddress) { - errors.customAddress = 'Address is invalid. ' + errors.customAddress = t('invalidAddress') } const validDecimals = customDecimals !== null && customDecimals >= 0 && customDecimals < 36 if (!validDecimals) { - errors.customDecimals = 'Decimals must be at least 0, and not over 36.' + errors.customDecimals = t('decimalsMustZerotoTen') } const symbolLen = customSymbol.trim().length const validSymbol = symbolLen > 0 && symbolLen < 10 if (!validSymbol) { - errors.customSymbol = 'Symbol must be between 0 and 10 characters.' + errors.customSymbol = t('symbolBetweenZeroTen') } const ownAddress = identitiesList.includes(standardAddress) if (ownAddress) { - errors.customAddress = 'Personal address detected. Input the token contract address.' + errors.customAddress = t('personalAddressDetected') } const tokenAlreadyAdded = this.checkExistingAddresses(customAddress) if (tokenAlreadyAdded) { - errors.customAddress = 'Token has already been added.' + errors.customAddress = t('tokenAlreadyAdded') } } else if ( Object.entries(selectedTokens) @@ -168,7 +169,7 @@ AddTokenScreen.prototype.validate = function () { isEmpty && !isSelected ), true) ) { - errors.tokenSelector = 'Must select at least 1 token.' + errors.tokenSelector = t('mustSelectOne') } return { @@ -198,7 +199,7 @@ AddTokenScreen.prototype.renderCustomForm = function () { 'add-token__add-custom-field--error': errors.customAddress, }), }, [ - h('div.add-token__add-custom-label', 'Token Address'), + h('div.add-token__add-custom-label', t('tokenAddress')), h('input.add-token__add-custom-input', { type: 'text', onChange: this.tokenAddressDidChange, @@ -211,7 +212,7 @@ AddTokenScreen.prototype.renderCustomForm = function () { 'add-token__add-custom-field--error': errors.customSymbol, }), }, [ - h('div.add-token__add-custom-label', 'Token Symbol'), + h('div.add-token__add-custom-label', t('tokenSymbol')), h('input.add-token__add-custom-input', { type: 'text', onChange: this.tokenSymbolDidChange, @@ -225,7 +226,7 @@ AddTokenScreen.prototype.renderCustomForm = function () { 'add-token__add-custom-field--error': errors.customDecimals, }), }, [ - h('div.add-token__add-custom-label', 'Decimals of Precision'), + h('div.add-token__add-custom-label', t('decimal')), h('input.add-token__add-custom-input', { type: 'number', onChange: this.tokenDecimalsDidChange, @@ -299,11 +300,11 @@ AddTokenScreen.prototype.renderConfirmation = function () { h('div.add-token', [ h('div.add-token__wrapper', [ h('div.add-token__title-container.add-token__confirmation-title', [ - h('div.add-token__title', 'Add Token'), - h('div.add-token__description', 'Would you like to add these tokens?'), + h('div.add-token__title', t('addToken')), + h('div.add-token__description', t('likeToAddTokens')), ]), h('div.add-token__content-container.add-token__confirmation-content', [ - h('div.add-token__description.add-token__confirmation-description', 'Your balances'), + h('div.add-token__description.add-token__confirmation-description', t('balances')), h('div.add-token__confirmation-token-list', Object.entries(tokens) .map(([ address, token ]) => ( @@ -322,10 +323,10 @@ AddTokenScreen.prototype.renderConfirmation = function () { h('div.add-token__buttons', [ h('button.btn-cancel.add-token__button', { onClick: () => this.setState({ isShowingConfirmation: false }), - }, 'Back'), + }, t('back')), h('button.btn-clear.add-token__button', { onClick: () => addTokens(tokens).then(goHome), - }, 'Add Tokens'), + }, t('addTokens')), ]), ]) ) @@ -341,15 +342,15 @@ AddTokenScreen.prototype.render = function () { h('div.add-token', [ h('div.add-token__wrapper', [ h('div.add-token__title-container', [ - h('div.add-token__title', 'Add Token'), - h('div.add-token__description', 'Keep track of the tokens you’ve bought with your MetaMask account. If you bought tokens using a different account, those tokens will not appear here.'), - h('div.add-token__description', 'Search for tokens or select from our list of popular tokens.'), + h('div.add-token__title', t('addToken')), + h('div.add-token__description', t('tokenWarning1')), + h('div.add-token__description', t('tokenSelection')), ]), h('div.add-token__content-container', [ h('div.add-token__input-container', [ h('input.add-token__input', { type: 'text', - placeholder: 'Search', + placeholder: t('search'), onChange: e => this.setState({ searchQuery: e.target.value }), }), h('div.add-token__search-input-error-message', errors.tokenSelector), @@ -363,7 +364,7 @@ AddTokenScreen.prototype.render = function () { h('div.add-token__add-custom', { onClick: () => this.setState({ isCollapsed: !isCollapsed }), }, [ - 'Add custom token', + t('addCustomToken'), h(`i.fa.fa-angle-${isCollapsed ? 'down' : 'up'}`), ]), this.renderCustomForm(), @@ -372,10 +373,10 @@ AddTokenScreen.prototype.render = function () { h('div.add-token__buttons', [ h('button.btn-cancel.add-token__button', { onClick: goHome, - }, 'Cancel'), + }, t('cancel')), h('button.btn-clear.add-token__button', { onClick: this.onNext, - }, 'Next'), + }, t('next')), ]), ]) ) From cffaf44714830904526c05bd4acf7a88c6e3cabe Mon Sep 17 00:00:00 2001 From: Thomas Date: Tue, 20 Mar 2018 09:49:12 -0700 Subject: [PATCH 08/12] i18n Import flow --- ui/app/accounts/import/index.js | 6 +++--- ui/app/accounts/import/json.js | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/ui/app/accounts/import/index.js b/ui/app/accounts/import/index.js index c1b190e3d..fc9031a65 100644 --- a/ui/app/accounts/import/index.js +++ b/ui/app/accounts/import/index.js @@ -37,7 +37,7 @@ AccountImportSubview.prototype.render = function () { h('div.new-account-import-form', [ h('.new-account-import-disclaimer', [ - h('span', 'Imported accounts will not be associated with your originally created MetaMask account seedphrase. Learn more about imported accounts '), + h('span', t('importAccountMsg')), h('span', { style: { cursor: 'pointer', @@ -48,12 +48,12 @@ AccountImportSubview.prototype.render = function () { url: 'https://metamask.helpscoutdocs.com/article/17-what-are-loose-accounts', }) }, - }, 'here'), + }, t('here')), ]), h('div.new-account-import-form__select-section', [ - h('div.new-account-import-form__select-label', 'Select Type'), + h('div.new-account-import-form__select-label', t('selectType')), h(Select, { className: 'new-account-import-form__select', diff --git a/ui/app/accounts/import/json.js b/ui/app/accounts/import/json.js index 1b5e485d7..fa25168f1 100644 --- a/ui/app/accounts/import/json.js +++ b/ui/app/accounts/import/json.js @@ -84,7 +84,7 @@ class JsonImportSubview extends Component { const state = this.state if (!state) { - const message = 'You must select a valid file to import.' + const message = t('validFileImport') return this.props.displayWarning(message) } @@ -102,7 +102,7 @@ class JsonImportSubview extends Component { const message = t('needImportPassword') return this.props.displayWarning(message) } - + this.props.importNewJsonAccount([ fileContents, password ]) } } From 7a8e0802455b8819dac12d73a4a8e245d6907dc0 Mon Sep 17 00:00:00 2001 From: Thomas Date: Tue, 20 Mar 2018 10:29:22 -0700 Subject: [PATCH 09/12] Started on Tx list i18n --- app/_locales/en/messages.json | 6 ++++++ ui/app/components/tx-list.js | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/app/_locales/en/messages.json b/app/_locales/en/messages.json index 95f46106a..357d51363 100644 --- a/app/_locales/en/messages.json +++ b/app/_locales/en/messages.json @@ -98,6 +98,9 @@ "confirm": { "message": "Confirm" }, + "confirmed": { + "message": "Confirmed" + }, "confirmContract": { "message": "Confirm Contract" }, @@ -812,6 +815,9 @@ "uiWelcomeMessage": { "message": "You are now using the new Metamask UI. Take a look around, try out new features like sending tokens, and let us know if you have any issues." }, + "unapproved": { + "message": "Unapproved" + }, "unavailable": { "message": "Unavailable" }, diff --git a/ui/app/components/tx-list.js b/ui/app/components/tx-list.js index 34dc837ae..b6538347c 100644 --- a/ui/app/components/tx-list.js +++ b/ui/app/components/tx-list.js @@ -40,7 +40,7 @@ TxList.prototype.render = function () { return h('div.flex-column', [ h('div.flex-row.tx-list-header-wrapper', [ h('div.flex-row.tx-list-header', [ - h('div', 'transactions'), + h('div', t('transactions')), ]), ]), h('div.flex-column.tx-list-container', {}, [ From 4fc68ca20833e5f6c70b8a532d79ac60e65f4704 Mon Sep 17 00:00:00 2001 From: Thomas Date: Tue, 20 Mar 2018 10:56:35 -0700 Subject: [PATCH 10/12] Add i18n in settings/info --- app/_locales/en/messages.json | 3 +++ ui/app/settings.js | 28 ++++++++++++++-------------- 2 files changed, 17 insertions(+), 14 deletions(-) diff --git a/app/_locales/en/messages.json b/app/_locales/en/messages.json index 357d51363..ecce27de2 100644 --- a/app/_locales/en/messages.json +++ b/app/_locales/en/messages.json @@ -425,6 +425,9 @@ "likeToAddTokens": { "message": "Would you like to add these tokens?" }, + "links": { + "message": "Links" + }, "limit": { "message": "Limit" }, diff --git a/ui/app/settings.js b/ui/app/settings.js index 60d68bfed..105cbb40b 100644 --- a/ui/app/settings.js +++ b/ui/app/settings.js @@ -59,7 +59,7 @@ class Settings extends Component { return h('div.settings__content-row', [ h('div.settings__content-item', [ - h('span', 'Use Blockies Identicon'), + h('span', t('blockiesIdenticon')), ]), h('div.settings__content-item', [ h('div.settings__content-item-col', [ @@ -79,7 +79,7 @@ class Settings extends Component { return h('div.settings__content-row', [ h('div.settings__content-item', [ - h('span', 'Current Conversion'), + h('span', t('currentConversion')), h('span.settings__content-description', `Updated ${Date(conversionDate)}`), ]), h('div.settings__content-item', [ @@ -192,7 +192,7 @@ class Settings extends Component { return ( h('div.settings__content-row', [ h('div.settings__content-item', [ - h('div', 'State Logs'), + h('div', t('stateLogs')), h( 'div.settings__content-description', t('stateLogsDescription') @@ -222,7 +222,7 @@ class Settings extends Component { return ( h('div.settings__content-row', [ - h('div.settings__content-item', 'Reveal Seed Words'), + h('div.settings__content-item', t('revealSeedWords')), h('div.settings__content-item', [ h('div.settings__content-item-col', [ h('button.settings__clear-button.settings__clear-button--red', { @@ -242,7 +242,7 @@ class Settings extends Component { return ( h('div.settings__content-row', [ - h('div.settings__content-item', 'Use old UI'), + h('div.settings__content-item', t('useOldUI')), h('div.settings__content-item', [ h('div.settings__content-item-col', [ h('button.settings__clear-button.settings__clear-button--orange', { @@ -261,7 +261,7 @@ class Settings extends Component { const { showResetAccountConfirmationModal } = this.props return h('div.settings__content-row', [ - h('div.settings__content-item', 'Reset Account'), + h('div.settings__content-item', t('resetAccount')), h('div.settings__content-item', [ h('div.settings__content-item-col', [ h('button.settings__clear-button.settings__clear-button--orange', { @@ -304,13 +304,13 @@ class Settings extends Component { renderInfoLinks () { return ( h('div.settings__content-item.settings__content-item--without-height', [ - h('div.settings__info-link-header', 'Links'), + h('div.settings__info-link-header', t('links')), h('div.settings__info-link-item', [ h('a', { href: 'https://metamask.io/privacy.html', target: '_blank', }, [ - h('span.settings__info-link', 'Privacy Policy'), + h('span.settings__info-link', t('privacyMsg')), ]), ]), h('div.settings__info-link-item', [ @@ -318,7 +318,7 @@ class Settings extends Component { href: 'https://metamask.io/terms.html', target: '_blank', }, [ - h('span.settings__info-link', 'Terms of Use'), + h('span.settings__info-link', t('terms')), ]), ]), h('div.settings__info-link-item', [ @@ -326,7 +326,7 @@ class Settings extends Component { href: 'https://metamask.io/attributions.html', target: '_blank', }, [ - h('span.settings__info-link', 'Attributions'), + h('span.settings__info-link', t('attributions')), ]), ]), h('hr.settings__info-separator'), @@ -335,7 +335,7 @@ class Settings extends Component { href: 'https://support.metamask.io', target: '_blank', }, [ - h('span.settings__info-link', 'Visit our Support Center'), + h('span.settings__info-link', t('supportCenter')), ]), ]), h('div.settings__info-link-item', [ @@ -343,7 +343,7 @@ class Settings extends Component { href: 'https://metamask.io/', target: '_blank', }, [ - h('span.settings__info-link', 'Visit our web site'), + h('span.settings__info-link', t('visitWebSite')), ]), ]), h('div.settings__info-link-item', [ @@ -351,7 +351,7 @@ class Settings extends Component { target: '_blank', href: 'mailto:help@metamask.io?subject=Feedback', }, [ - h('span.settings__info-link', 'Email us!'), + h('span.settings__info-link', t('emailUs')), ]), ]), ]) @@ -373,7 +373,7 @@ class Settings extends Component { h('div.settings__info-item', [ h( 'div.settings__info-about', - 'MetaMask is designed and built in California.' + t('builtInCalifornia') ), ]), ]), From 2c42cfdf1e8c8aff517cae9f6011dd39e503cef3 Mon Sep 17 00:00:00 2001 From: Thomas Date: Tue, 20 Mar 2018 11:04:15 -0700 Subject: [PATCH 11/12] Update onlySendToEtherAddress message --- app/_locales/en/messages.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/_locales/en/messages.json b/app/_locales/en/messages.json index ecce27de2..7353d8976 100644 --- a/app/_locales/en/messages.json +++ b/app/_locales/en/messages.json @@ -694,7 +694,7 @@ "message": "Send Tokens" }, "onlySendToEtherAddress": { - "message": "Only send to an Ethereum address." + "message": "Only send ETH to an Ethereum address." }, "sendTokensAnywhere": { "message": "Send Tokens to anyone with an Ethereum account" From dd19a934475cfa8cc31495b351b69a7d8d1f8d5e Mon Sep 17 00:00:00 2001 From: Thomas Date: Tue, 20 Mar 2018 12:06:59 -0700 Subject: [PATCH 12/12] Add i18n to tx status --- app/_locales/en/messages.json | 14 +++++++++++++- ui/app/components/tx-list-item.js | 27 ++++++++++++++++++++++++++- 2 files changed, 39 insertions(+), 2 deletions(-) diff --git a/app/_locales/en/messages.json b/app/_locales/en/messages.json index 7353d8976..c64b7248b 100644 --- a/app/_locales/en/messages.json +++ b/app/_locales/en/messages.json @@ -37,6 +37,9 @@ "message": "MetaMask", "description": "The name of the application" }, + "approved": { + "message": "Approved" + }, "attemptingConnect": { "message": "Attempting to connect to blockchain." }, @@ -232,6 +235,9 @@ "downloadStatelogs": { "message": "Download State Logs" }, + "dropped": { + "message": "Dropped" + }, "edit": { "message": "Edit" }, @@ -703,7 +709,7 @@ "message": "Settings" }, "info": { - "message": "Info" + "message": "Info" }, "shapeshiftBuy": { "message": "Buy with Shapeshift" @@ -717,6 +723,9 @@ "sign": { "message": "Sign" }, + "signed": { + "message": "Signed" + }, "signMessage": { "message": "Sign Message" }, @@ -747,6 +756,9 @@ "submit": { "message": "Submit" }, + "submitted": { + "message": "Submitted" + }, "supportCenter": { "message": "Visit our Support Center" }, diff --git a/ui/app/components/tx-list-item.js b/ui/app/components/tx-list-item.js index 5ff1820a6..d104eda88 100644 --- a/ui/app/components/tx-list-item.js +++ b/ui/app/components/tx-list-item.js @@ -265,7 +265,7 @@ TxListItem.prototype.render = function () { 'tx-list-status--dropped': transactionStatus === 'dropped', }), }, - transactionStatus, + this.txStatusIndicator(), ), ]), ]), @@ -300,3 +300,28 @@ TxListItem.prototype.render = function () { ]), // holding on icon from design ]) } + +TxListItem.prototype.txStatusIndicator = function () { + const { transactionStatus } = this.props + + let name + + if (transactionStatus === 'unapproved') { + name = t('unapproved') + } else if (transactionStatus === 'rejected') { + name = t('rejected') + } else if (transactionStatus === 'approved') { + name = t('approved') + } else if (transactionStatus === 'signed') { + name = t('signed') + } else if (transactionStatus === 'submitted') { + name = t('submitted') + } else if (transactionStatus === 'confirmed') { + name = t('confirmed') + } else if (transactionStatus === 'failed') { + name = t('failed') + } else if (transactionStatus === 'dropped') { + name = t('dropped') + } + return name +}