Commit 520b9a58 authored by maggie-5miles's avatar maggie-5miles Committed by Hayden Adams

i18n support

parent e761cd6f
{
"noWallet": "No Ethereum wallet found",
"wrongNetwork": "You are on the wrong network",
"switchNetwork": "Please switch to {{ correctNetwork }}",
"installWeb3MobileBrowser": "Please visit us from a web3-enabled mobile browser such as Trust Wallet or Coinbase Wallet.",
"installMetamask": "Please visit us after installing Metamask on Chrome or Brave.",
"disconnected": "Disconnected",
"swap": "Swap",
"send": "Send",
"pool": "Pool",
"betaWarning": "This project is in beta. Use at your own risk.",
"input": "Input",
"output": "Output",
"estimated": "estimated",
"balance": "Balance: {{ balanceInput }}",
"unlock": "Unlock",
"pending": "Pending",
"selectToken": "Select a token",
"searchOrPaste": "Search Token or Paste Address",
"noExchange": "No Exchange Found",
"exchangeRate": "Exchange Rate",
"enterValueCont": "Enter a {{ missingCurrencyValue }} value to continue.",
"selectTokenCont": "Select a token to continue.",
"noLiquidity": "No liquidity.",
"unlockTokenCont": "Please unlock token to continue.",
"transactionDetails": "Transaction Details",
"youAreSelling": "You are selling",
"orTransFail": "or the transaction will fail.",
"youWillReceive": "You will receive at least",
"youAreBuying": "You are buying",
"itWillCost": "It will cost at most",
"insufficientBalance": "Insufficient Balance",
"inputNotValid": "Not a valid input value",
"differentToken": "Must be different token.",
"noRecipient": "Enter a wallet address to send to.",
"invalidRecipient": "Please enter a valid wallet address recipient.",
"recipientAddress": "Recipient Address",
"youAreSending": "You are sending",
"willReceive": "will receive at least",
"to": "to",
"addLiquidity": "Add Liquidity",
"deposit": "Deposit",
"currentPoolSize": "Current Pool Size",
"yourPoolShare": "Your Pool Share",
"noZero": "Amount cannot be zero.",
"mustBeETH": "One of the input must be ETH.",
"enterCurrencyOrLabelCont": "Enter a {{ inputCurrency }} or {{ label }} value to continue.",
"youAreAdding": "You are adding between",
"and": "and",
"intoPool": "into the liquidity pool.",
"outPool": "into the liquidity pool.",
"youWillMint": "You will mint",
"liquidityTokens": "liquidity tokens.",
"totalSupplyIs": "Current total supply of liquidity tokens is",
"tokenWorth": "At current exchange rate, each pool token is worth",
"firstLiquidity": "You are the first person to add liquidity!",
"initialExchangeRate": "The initial exchange rate will be set based on your deposits. Please make sure that your ETH and {{ label }} deposits have the same fiat value.",
"removeLiquidity": "Remove Liquidity",
"poolTokens": "Pool Tokens",
"enterLabelCont": "Enter a {{ label }} value to continue.",
"youAreRemoving": "You are removing between",
"youWillRemove": "You will remove",
"createExchange": "Create Exchange",
"invalidTokenAddress": "Not a valid token address",
"exchangeExists": "{{ label }} Exchange already exists!",
"invalidSymbol": "Invalid symbol",
"invalidDecimals": "Invalid decimals",
"tokenAddress": "Token Address",
"label": "Label",
"decimals": "Decimals",
"enterTokenCont": "Enter a token address to continue"
}
{
"noWallet": "未发现以太钱包",
"wrongNetwork": "网络错误",
"switchNetwork": "请切换到 {{ correctNetwork }}",
"installWeb3MobileBrowser": "请从支持web3的移动端浏览器,如 Trust Wallet 或 Coinbase Wallet 访问。",
"installMetamask": "请从安装了 Metamask 插件的 Chrome 或 Brave 访问。",
"disconnected": "未连接",
"swap": "交换",
"send": "发送",
"pool": "资金池",
"betaWarning": "项目尚处于beta阶段。使用需自行承担风险。",
"input": "输入",
"output": "输出",
"estimated": "估计",
"balance": "余额: {{ balanceInput }}",
"unlock": "解锁",
"pending": "处理中",
"selectToken": "选择代币",
"searchOrPaste": "搜索代币或粘贴地址",
"noExchange": "未找到交易所",
"exchangeRate": "兑换率",
"enterValueCont": "输入{{ missingCurrencyValue }}值继续。",
"selectTokenCont": "选取代币继续。",
"noLiquidity": "没有流动金。",
"unlockTokenCont": "请解锁代币继续。",
"transactionDetails": "交易明细",
"youAreSelling": "你正在出售",
"orTransFail": "或交易失败。",
"youWillReceive": "你将收到至少",
"youAreBuying": "你正在购买",
"itWillCost": "它将花费至少",
"insufficientBalance": "余额不足",
"inputNotValid": "无效的输入值",
"differentToken": "必须是不同的代币。",
"noRecipient": "输入接收钱包地址。",
"invalidRecipient": "请输入有效的接收钱包地址。",
"recipientAddress": "接收地址",
"youAreSending": "你正在发送",
"willReceive": "将收到至少",
"to": "到",
"addLiquidity": "添加流动金",
"deposit": "存入",
"currentPoolSize": "当前资金池大小",
"yourPoolShare": "你的资金池份额",
"noZero": "金额不能为零。",
"mustBeETH": "输入中必须有一个是 ETH。",
"enterCurrencyOrLabelCont": "输入 {{ inputCurrency }} 或 {{ label }} 值继续。",
"youAreAdding": "你将添加",
"and": "和",
"intoPool": "入流动资金池。",
"outPool": "出流动资金池。",
"youWillMint": "你将铸造",
"liquidityTokens": "流动代币。",
"totalSupplyIs": "当前流动代币的总量是",
"tokenWorth": "当前兑换率下,每个资金池代币价值",
"firstLiquidity": "你是第一个添加流动金的人!",
"initialExchangeRate": "初始兑换率将由你的存入情况决定。请确保你存入的 ETH 和 {{ label }} 具有相同的法币价值。",
"removeLiquidity": "删除流动金",
"poolTokens": "资金池代币",
"enterLabelCont": "输入 {{ label }} 值继续。",
"youAreRemoving": "你正在移除",
"youWillRemove": "你将移除",
"createExchange": "创建交易所",
"invalidTokenAddress": "代币地址无效",
"exchangeExists": "{{ label }} 交易所已存在!",
"invalidSymbol": "代币符号无效",
"invalidDecimals": "小数位数无效",
"tokenAddress": "代币地址",
"label": "代币符号",
"decimals": "小数位数",
"enterTokenCont": "输入代币地址继续"
}
...@@ -20,6 +20,7 @@ class AddressInputPanel extends Component { ...@@ -20,6 +20,7 @@ class AddressInputPanel extends Component {
render() { render() {
const { const {
t,
title, title,
onChange, onChange,
value, value,
...@@ -34,7 +35,7 @@ class AddressInputPanel extends Component { ...@@ -34,7 +35,7 @@ class AddressInputPanel extends Component {
<div className="address-input-panel__input-container"> <div className="address-input-panel__input-container">
<div className="currency-input-panel__label-row"> <div className="currency-input-panel__label-row">
<div className="currency-input-panel__label-container"> <div className="currency-input-panel__label-container">
<span className="currency-input-panel__label">{title || 'Recipient Address'}</span> <span className="currency-input-panel__label">{title || t("recipientAddress")}</span>
</div> </div>
</div> </div>
<div className="currency-input-panel__input-row"> <div className="currency-input-panel__input-row">
......
...@@ -32,10 +32,29 @@ class ContextualInfo extends Component { ...@@ -32,10 +32,29 @@ class ContextualInfo extends Component {
} }
return ( return (
<div className="contextual-info__details"> <Modal key="modal" onClose={() => this.setState({ showDetailModal: false })}>
<CSSTransitionGroup
transitionName="summary-modal"
transitionAppear={true}
transitionLeave={true}
transitionAppearTimeout={200}
transitionLeaveTimeout={200}
transitionEnterTimeout={200}
>
<div className={c('contextual-info__summary-modal', modalClass)}>
<div
key="open-details"
className="contextual-info__open-details-container contextual-info__modal-button"
onClick={() => this.setState({showDetailModal: false})}
>
<span>{this.props.openModalText}</span>
<img src={DropupBlue} />
</div>
{this.props.renderTransactionDetails()} {this.props.renderTransactionDetails()}
</div> </div>
) </CSSTransitionGroup>
</Modal>
);
} }
render() { render() {
......
...@@ -4,6 +4,7 @@ import PropTypes from 'prop-types'; ...@@ -4,6 +4,7 @@ import PropTypes from 'prop-types';
import { CSSTransitionGroup } from "react-transition-group"; import { CSSTransitionGroup } from "react-transition-group";
import classnames from 'classnames'; import classnames from 'classnames';
import { withRouter } from 'react-router-dom'; import { withRouter } from 'react-router-dom';
import { withNamespaces } from 'react-i18next';
import Fuse from '../../helpers/fuse'; import Fuse from '../../helpers/fuse';
import Modal from '../Modal'; import Modal from '../Modal';
import TokenLogo from '../TokenLogo'; import TokenLogo from '../TokenLogo';
...@@ -105,6 +106,7 @@ class CurrencyInputPanel extends Component { ...@@ -105,6 +106,7 @@ class CurrencyInputPanel extends Component {
const tokens = this.createTokenList(); const tokens = this.createTokenList();
const { loadingExchange, searchQuery } = this.state; const { loadingExchange, searchQuery } = this.state;
const { const {
t,
selectedTokens, selectedTokens,
disableTokenSelect, disableTokenSelect,
web3, web3,
...@@ -160,7 +162,7 @@ class CurrencyInputPanel extends Component { ...@@ -160,7 +162,7 @@ class CurrencyInputPanel extends Component {
const { label } = selectors().getBalance(account, searchQuery); const { label } = selectors().getBalance(account, searchQuery);
return [ return [
<div key="token-modal-no-exchange" className="token-modal__token-row token-modal__token-row--no-exchange"> <div key="token-modal-no-exchange" className="token-modal__token-row token-modal__token-row--no-exchange">
<div>No Exchange Found</div> <div>{t("noExchange")}</div>
</div>, </div>,
<div <div
key="token-modal-create-exchange" key="token-modal-create-exchange"
...@@ -178,7 +180,7 @@ class CurrencyInputPanel extends Component { ...@@ -178,7 +180,7 @@ class CurrencyInputPanel extends Component {
if (!results.length) { if (!results.length) {
return ( return (
<div className="token-modal__token-row token-modal__token-row--no-exchange"> <div className="token-modal__token-row token-modal__token-row--no-exchange">
<div>No Exchange Found</div> <div>{t("noExchange")}</div>
</div> </div>
) )
} }
...@@ -222,7 +224,7 @@ class CurrencyInputPanel extends Component { ...@@ -222,7 +224,7 @@ class CurrencyInputPanel extends Component {
<div className="token-modal__search-container"> <div className="token-modal__search-container">
<input <input
type="text" type="text"
placeholder="Search Token or Paste Address" placeholder={this.props.t("searchOrPaste")}
className="token-modal__search-input" className="token-modal__search-input"
onChange={e => { onChange={e => {
this.setState({ searchQuery: e.target.value }); this.setState({ searchQuery: e.target.value });
...@@ -241,6 +243,7 @@ class CurrencyInputPanel extends Component { ...@@ -241,6 +243,7 @@ class CurrencyInputPanel extends Component {
renderUnlockButton() { renderUnlockButton() {
const { const {
t,
selectors, selectors,
selectedTokenAddress, selectedTokenAddress,
account, account,
...@@ -276,7 +279,7 @@ class CurrencyInputPanel extends Component { ...@@ -276,7 +279,7 @@ class CurrencyInputPanel extends Component {
className='currency-input-panel__sub-currency-select currency-input-panel__sub-currency-select--pending' className='currency-input-panel__sub-currency-select currency-input-panel__sub-currency-select--pending'
> >
<div className="loader" /> <div className="loader" />
Pending {t("pending")}
</button> </button>
); );
} }
...@@ -296,13 +299,14 @@ class CurrencyInputPanel extends Component { ...@@ -296,13 +299,14 @@ class CurrencyInputPanel extends Component {
}); });
}} }}
> >
Unlock {t("unlock")}
</button> </button>
); );
} }
renderInput() { renderInput() {
const { const {
t,
errorMessage, errorMessage,
value, value,
onValueChange, onValueChange,
...@@ -358,7 +362,7 @@ class CurrencyInputPanel extends Component { ...@@ -358,7 +362,7 @@ class CurrencyInputPanel extends Component {
) )
: null : null
} }
{ TOKEN_ADDRESS_TO_LABEL[selectedTokenAddress] || 'Select a token' } { TOKEN_ADDRESS_TO_LABEL[selectedTokenAddress] || t("selectToken") }
<span className="currency-input-panel__dropdown-icon" /> <span className="currency-input-panel__dropdown-icon" />
</button> </button>
</div> </div>
...@@ -416,5 +420,5 @@ export default withRouter( ...@@ -416,5 +420,5 @@ export default withRouter(
addPendingTx: opts => dispatch(addPendingTx(opts)), addPendingTx: opts => dispatch(addPendingTx(opts)),
addApprovalTx: opts => dispatch(addApprovalTx(opts)), addApprovalTx: opts => dispatch(addApprovalTx(opts)),
}), }),
)(CurrencyInputPanel) )(withNamespaces()(CurrencyInputPanel))
); );
...@@ -3,6 +3,7 @@ import PropTypes from 'prop-types'; ...@@ -3,6 +3,7 @@ import PropTypes from 'prop-types';
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import classnames from 'classnames'; import classnames from 'classnames';
import UAParser from 'ua-parser-js'; import UAParser from 'ua-parser-js';
import { withNamespaces } from 'react-i18next';
import Logo from '../Logo'; import Logo from '../Logo';
import CoinbaseWalletLogo from '../../assets/images/coinbase-wallet-logo.png'; import CoinbaseWalletLogo from '../../assets/images/coinbase-wallet-logo.png';
import TrustLogo from '../../assets/images/trust-wallet-logo.svg'; import TrustLogo from '../../assets/images/trust-wallet-logo.svg';
...@@ -77,6 +78,7 @@ function isMobile() { ...@@ -77,6 +78,7 @@ function isMobile() {
class BlockingWarning extends Component { class BlockingWarning extends Component {
render () { render () {
const { const {
t,
isConnected, isConnected,
initialized, initialized,
networkId, networkId,
...@@ -90,21 +92,21 @@ class BlockingWarning extends Component { ...@@ -90,21 +92,21 @@ class BlockingWarning extends Component {
if (wrongNetwork && initialized) { if (wrongNetwork && initialized) {
content = [ content = [
<div key="warning-title">You are on the wrong network</div>, <div key="warning-title">{t("wrongNetwork")}</div>,
<div key="warning-desc" className="header__dialog__description"> <div key="warning-desc" className="header__dialog__description">
{`Please switch to ${correctNetwork}`} {t("switchNetwork", {correctNetwork})}
</div>, </div>,
]; ];
} }
if (!isConnected && initialized) { if (!isConnected && initialized) {
content = [ content = [
<div key="warning-title">No Ethereum wallet found</div>, <div key="warning-title">{t("noWallet")}</div>,
<div key="warning-desc" className="header__dialog__description"> <div key="warning-desc" className="header__dialog__description">
{ {
isMobile() isMobile()
? 'Please visit us from a web3-enabled mobile browser such as Trust Wallet or Coinbase Wallet.' ? t("installWeb3MobileBrowser")
: 'Please visit us after installing Metamask on Chrome or Brave.' : t("installMetamask")
} }
</div>, </div>,
<div key="warning-logos" className="header__download"> <div key="warning-logos" className="header__download">
...@@ -171,4 +173,4 @@ export default connect( ...@@ -171,4 +173,4 @@ export default connect(
web3: state.web3connect.web3, web3: state.web3connect.web3,
networkId: state.web3connect.networkId, networkId: state.web3connect.networkId,
}), }),
)(Header); )(withNamespaces()(Header));
...@@ -2,6 +2,7 @@ import React, { Component } from 'react'; ...@@ -2,6 +2,7 @@ import React, { Component } from 'react';
import { withRouter } from 'react-router-dom'; import { withRouter } from 'react-router-dom';
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import { withNamespaces } from 'react-i18next';
import { dismissBetaMessage } from '../../ducks/app'; import { dismissBetaMessage } from '../../ducks/app';
import {Tab, Tabs} from "../Tab"; import {Tab, Tabs} from "../Tab";
...@@ -38,18 +39,18 @@ class NavigationTabs extends Component { ...@@ -38,18 +39,18 @@ class NavigationTabs extends Component {
} }
render() { render() {
const { showBetaMessage, className, dismissBetaMessage } = this.props; const { t, showBetaMessage, className, dismissBetaMessage } = this.props;
return ( return (
<div> <div>
<Tabs className={className}> <Tabs className={className}>
{ this.renderTab('Swap', '/swap', /swap/) } { this.renderTab(t("swap"), '/swap', /swap/) }
{ this.renderTab('Send', '/send', /send/) } { this.renderTab(t("send"), '/send', /send/) }
{ this.renderTab('Pool', '/add-liquidity', /add-liquidity|remove-liquidity|create-exchange/) } { this.renderTab(t("pool"), '/add-liquidity', /add-liquidity|remove-liquidity|create-exchange/) }
</Tabs> </Tabs>
{ {
showBetaMessage && ( showBetaMessage && (
<div className="beta-message" onClick={dismissBetaMessage}> <div className="beta-message" onClick={dismissBetaMessage}>
💀 This project is in beta. Use at your own risk. 💀 {t("betaWarning")}
</div> </div>
) )
} }
...@@ -66,5 +67,5 @@ export default withRouter( ...@@ -66,5 +67,5 @@ export default withRouter(
dispatch => ({ dispatch => ({
dismissBetaMessage: () => dispatch(dismissBetaMessage()), dismissBetaMessage: () => dispatch(dismissBetaMessage()),
}), }),
)(NavigationTabs) )(withNamespaces()(NavigationTabs))
); );
...@@ -5,6 +5,7 @@ import classnames from 'classnames'; ...@@ -5,6 +5,7 @@ import classnames from 'classnames';
import Web3 from 'web3'; import Web3 from 'web3';
import Jazzicon from 'jazzicon'; import Jazzicon from 'jazzicon';
import { CSSTransitionGroup } from "react-transition-group"; import { CSSTransitionGroup } from "react-transition-group";
import { withNamespaces } from 'react-i18next';
import './web3-status.scss'; import './web3-status.scss';
import Modal from '../Modal'; import Modal from '../Modal';
...@@ -35,7 +36,7 @@ class Web3Status extends Component { ...@@ -35,7 +36,7 @@ class Web3Status extends Component {
{transaction} {transaction}
</div> </div>
<div className="pending-modal__pending-indicator"> <div className="pending-modal__pending-indicator">
<div className="loader" /> Pending <div className="loader" /> {this.props.t("pending")}
</div> </div>
</div> </div>
); );
...@@ -69,7 +70,7 @@ class Web3Status extends Component { ...@@ -69,7 +70,7 @@ class Web3Status extends Component {
} }
render() { render() {
const { address, pending, confirmed } = this.props; const { t, address, pending, confirmed } = this.props;
const hasPendingTransactions = !!pending.length; const hasPendingTransactions = !!pending.length;
const hasConfirmedTransactions = !!confirmed.length; const hasConfirmedTransactions = !!confirmed.length;
...@@ -83,7 +84,7 @@ class Web3Status extends Component { ...@@ -83,7 +84,7 @@ class Web3Status extends Component {
onClick={this.handleClick} onClick={this.handleClick}
> >
<div className="web3-status__text"> <div className="web3-status__text">
{ hasPendingTransactions ? getPendingText(pending) : getText(address) } {hasPendingTransactions ? getPendingText(pending, t("pending")) : getText(address, t("disconnected")) }
</div> </div>
<div <div
className="web3-status__identicon" className="web3-status__identicon"
...@@ -108,18 +109,18 @@ class Web3Status extends Component { ...@@ -108,18 +109,18 @@ class Web3Status extends Component {
function getPendingText(pendingTransactions) { function getPendingText(pendingTransactions, pendingLabel) {
return ( return (
<div className="web3-status__pending-container"> <div className="web3-status__pending-container">
<div className="loader" /> <div className="loader" />
<span key="text">{pendingTransactions.length} Pending</span> <span key="text">{pendingTransactions.length} {pendingLabel}</span>
</div> </div>
); );
} }
function getText(text) { function getText(text, disconnectedText) {
if (!text || text.length < 42 || !Web3.utils.isHexStrict(text)) { if (!text || text.length < 42 || !Web3.utils.isHexStrict(text)) {
return 'Disconnected'; return disconnectedText;
} }
const address = Web3.utils.toChecksumAddress(text); const address = Web3.utils.toChecksumAddress(text);
...@@ -145,4 +146,4 @@ export default connect( ...@@ -145,4 +146,4 @@ export default connect(
confirmed: state.web3connect.transactions.confirmed, confirmed: state.web3connect.transactions.confirmed,
}; };
} }
)(Web3Status); )(withNamespaces()(Web3Status));
import i18n from "i18next";
import Backend from 'i18next-xhr-backend';
import LanguageDetector from 'i18next-browser-languagedetector';
import { reactI18nextModule } from "react-i18next";
const resources = {
loadPath: `./locales/{{lng}}.json`
}
i18n
// load translation using xhr -> see /public/locales
// learn more: https://github.com/i18next/i18next-xhr-backend
.use(Backend)
// detect user language
// learn more: https://github.com/i18next/i18next-browser-languageDetector
.use(LanguageDetector)
// pass the i18n instance to react-i18next.
.use(reactI18nextModule)
// init i18next
// for all options read: https://www.i18next.com/overview/configuration-options
.init({
backend: resources,
fallbackLng: "en",
keySeparator: false,
interpolation: {
escapeValue: false
}
});
export default i18n;
...@@ -2,6 +2,7 @@ import React from 'react'; ...@@ -2,6 +2,7 @@ import React from 'react';
import ReactDOM from 'react-dom'; import ReactDOM from 'react-dom';
import { Provider } from 'react-redux'; import { Provider } from 'react-redux';
import ReactGA from 'react-ga'; import ReactGA from 'react-ga';
import './i18n';
import App from './pages/App'; import App from './pages/App';
import store from './store'; import store from './store';
......
...@@ -2,6 +2,7 @@ import React, { Component } from 'react'; ...@@ -2,6 +2,7 @@ import React, { Component } from 'react';
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import classnames from "classnames"; import classnames from "classnames";
import { withNamespaces } from 'react-i18next';
import CurrencyInputPanel from '../../components/CurrencyInputPanel'; import CurrencyInputPanel from '../../components/CurrencyInputPanel';
import OversizedPanel from '../../components/OversizedPanel'; import OversizedPanel from '../../components/OversizedPanel';
import ContextualInfo from '../../components/ContextualInfo'; import ContextualInfo from '../../components/ContextualInfo';
...@@ -51,10 +52,11 @@ class AddLiquidity extends Component { ...@@ -51,10 +52,11 @@ class AddLiquidity extends Component {
}; };
shouldComponentUpdate(nextProps, nextState) { shouldComponentUpdate(nextProps, nextState) {
const { isConnected, account, exchangeAddresses, balances, web3 } = this.props; const { t, isConnected, account, exchangeAddresses, balances, web3 } = this.props;
const { inputValue, outputValue, inputCurrency, outputCurrency, lastEditedField } = this.state; const { inputValue, outputValue, inputCurrency, outputCurrency, lastEditedField } = this.state;
return isConnected !== nextProps.isConnected || return isConnected !== nextProps.isConnected ||
t != nextProps.t ||
account !== nextProps.account || account !== nextProps.account ||
exchangeAddresses !== nextProps.exchangeAddresses || exchangeAddresses !== nextProps.exchangeAddresses ||
web3 !== nextProps.web3 || web3 !== nextProps.web3 ||
...@@ -111,7 +113,7 @@ class AddLiquidity extends Component { ...@@ -111,7 +113,7 @@ class AddLiquidity extends Component {
}; };
getBalance(currency) { getBalance(currency) {
const { selectors, account } = this.props; const { t, selectors, account } = this.props;
if (!currency) { if (!currency) {
return ''; return '';
...@@ -122,7 +124,8 @@ class AddLiquidity extends Component { ...@@ -122,7 +124,8 @@ class AddLiquidity extends Component {
return ''; return '';
} }
return `Balance: ${value.dividedBy(10 ** decimals).toFixed(4)}`; const balanceInput = value.dividedBy(10 ** decimals).toFixed(4);
return t("balance", { balanceInput });
} }
isUnapproved() { isUnapproved() {
...@@ -271,7 +274,7 @@ class AddLiquidity extends Component { ...@@ -271,7 +274,7 @@ class AddLiquidity extends Component {
} }
validate() { validate() {
const { selectors, account } = this.props; const { t, selectors, account } = this.props;
const { const {
inputValue, outputValue, inputValue, outputValue,
inputCurrency, outputCurrency, inputCurrency, outputCurrency,
...@@ -291,11 +294,11 @@ class AddLiquidity extends Component { ...@@ -291,11 +294,11 @@ class AddLiquidity extends Component {
const { value: tokenValue, decimals } = selectors().getBalance(account, outputCurrency); const { value: tokenValue, decimals } = selectors().getBalance(account, outputCurrency);
if (ethValue.isLessThan(BN(inputValue * 10 ** 18))) { if (ethValue.isLessThan(BN(inputValue * 10 ** 18))) {
inputError = 'Insufficient Balance'; inputError = t("insufficientBalance");
} }
if (tokenValue.isLessThan(BN(outputValue * 10 ** decimals))) { if (tokenValue.isLessThan(BN(outputValue * 10 ** decimals))) {
outputError = 'Insufficient Balance'; outputError = t("insufficientBalance");
} }
return { return {
...@@ -306,18 +309,19 @@ class AddLiquidity extends Component { ...@@ -306,18 +309,19 @@ class AddLiquidity extends Component {
} }
renderInfo() { renderInfo() {
const t = this.props.t;
const blank = ( const blank = (
<div className="pool__summary-panel"> <div className="pool__summary-panel">
<div className="pool__exchange-rate-wrapper"> <div className="pool__exchange-rate-wrapper">
<span className="pool__exchange-rate">Exchange Rate</span> <span className="pool__exchange-rate">{t("exchangeRate")}</span>
<span> - </span> <span> - </span>
</div> </div>
<div className="pool__exchange-rate-wrapper"> <div className="pool__exchange-rate-wrapper">
<span className="swap__exchange-rate">Current Pool Size</span> <span className="swap__exchange-rate">{t("currentPoolSize")}</span>
<span> - </span> <span> - </span>
</div> </div>
<div className="pool__exchange-rate-wrapper"> <div className="pool__exchange-rate-wrapper">
<span className="swap__exchange-rate">Your Pool Share</span> <span className="swap__exchange-rate">{t("yourPoolShare")}</span>
<span> - </span> <span> - </span>
</div> </div>
</div> </div>
...@@ -353,16 +357,16 @@ class AddLiquidity extends Component { ...@@ -353,16 +357,16 @@ class AddLiquidity extends Component {
return ( return (
<div className="pool__summary-panel"> <div className="pool__summary-panel">
<div className="pool__exchange-rate-wrapper"> <div className="pool__exchange-rate-wrapper">
<span className="pool__exchange-rate">Exchange Rate</span> <span className="pool__exchange-rate">{t("exchangeRate")}</span>
<span>{`1 ETH = ${rateText} ${label}`}</span> <span>{`1 ETH = ${rateText} ${label}`}</span>
</div> </div>
<div className="pool__exchange-rate-wrapper"> <div className="pool__exchange-rate-wrapper">
<span className="swap__exchange-rate">Current Pool Size</span> <span className="swap__exchange-rate">{t("currentPoolSize")}</span>
<span>{` ${ethValue.dividedBy(10 ** 18).toFixed(2)} ${eth} + ${tokenValue.dividedBy(10 ** decimals).toFixed(2)} ${label}`}</span> <span>{` ${ethValue.dividedBy(10 ** 18).toFixed(2)} ${eth} + ${tokenValue.dividedBy(10 ** decimals).toFixed(2)} ${label}`}</span>
</div> </div>
<div className="pool__exchange-rate-wrapper"> <div className="pool__exchange-rate-wrapper">
<span className="swap__exchange-rate"> <span className="swap__exchange-rate">
Your Pool Share ({ownership.multipliedBy(100).toFixed(2)}%) {t("yourPoolShare")} ({ownership.multipliedBy(100).toFixed(2)}%)
</span> </span>
<span>{`${ownedEth.toFixed(2)} ETH + ${ownedToken.toFixed(2)} ${label}`}</span> <span>{`${ownedEth.toFixed(2)} ETH + ${ownedToken.toFixed(2)} ${label}`}</span>
</div> </div>
...@@ -377,16 +381,16 @@ class AddLiquidity extends Component { ...@@ -377,16 +381,16 @@ class AddLiquidity extends Component {
return ( return (
<div className="pool__summary-panel"> <div className="pool__summary-panel">
<div className="pool__exchange-rate-wrapper"> <div className="pool__exchange-rate-wrapper">
<span className="pool__exchange-rate">Exchange Rate</span> <span className="pool__exchange-rate">{t("exchangeRate")}</span>
<span>{`1 ETH = ${tokenValue.multipliedBy(10 ** (18 - decimals)).dividedBy(ethValue).toFixed(4)} ${label}`}</span> <span>{`1 ETH = ${tokenValue.multipliedBy(10 ** (18 - decimals)).dividedBy(ethValue).toFixed(4)} ${label}`}</span>
</div> </div>
<div className="pool__exchange-rate-wrapper"> <div className="pool__exchange-rate-wrapper">
<span className="swap__exchange-rate">Current Pool Size</span> <span className="swap__exchange-rate">{t("currentPoolSize")}</span>
<span>{` ${ethValue.dividedBy(10 ** 18).toFixed(2)} ${eth} + ${tokenValue.dividedBy(10 ** decimals).toFixed(2)} ${label}`}</span> <span>{` ${ethValue.dividedBy(10 ** 18).toFixed(2)} ${eth} + ${tokenValue.dividedBy(10 ** decimals).toFixed(2)} ${label}`}</span>
</div> </div>
<div className="pool__exchange-rate-wrapper"> <div className="pool__exchange-rate-wrapper">
<span className="swap__exchange-rate"> <span className="swap__exchange-rate">
Your Pool Share ({ownership.multipliedBy(100).toFixed(2)}%) {t("yourPoolShare")} ({ownership.multipliedBy(100).toFixed(2)}%)
</span> </span>
<span>{`${ownedEth.toFixed(2)} ETH + ${ownedToken.toFixed(2)} ${label}`}</span> <span>{`${ownedEth.toFixed(2)} ETH + ${ownedToken.toFixed(2)} ${label}`}</span>
</div> </div>
...@@ -395,7 +399,7 @@ class AddLiquidity extends Component { ...@@ -395,7 +399,7 @@ class AddLiquidity extends Component {
} }
renderSummary(inputError, outputError) { renderSummary(inputError, outputError) {
const { selectors, exchangeAddresses: { fromToken } } = this.props; const { t, selectors, exchangeAddresses: { fromToken } } = this.props;
const { const {
inputValue, inputValue,
outputValue, outputValue,
...@@ -412,22 +416,23 @@ class AddLiquidity extends Component { ...@@ -412,22 +416,23 @@ class AddLiquidity extends Component {
contextualInfo = inputError || outputError; contextualInfo = inputError || outputError;
isError = true; isError = true;
} else if (!inputCurrency || !outputCurrency) { } else if (!inputCurrency || !outputCurrency) {
contextualInfo = 'Select a token to continue.'; contextualInfo = t("selectTokenCont");
} else if (inputCurrency === outputCurrency) { } else if (inputCurrency === outputCurrency) {
contextualInfo = 'Must be different token.'; contextualInfo = t("differentToken");
} else if (![inputCurrency, outputCurrency].includes('ETH')) { } else if (![inputCurrency, outputCurrency].includes('ETH')) {
contextualInfo = 'One of the input must be ETH.'; contextualInfo = t("mustBeETH");
} else if (inputIsZero || outputIsZero) { } else if (inputIsZero || outputIsZero) {
contextualInfo = 'Amount cannot be zero.'; contextualInfo = t("noZero");
} else if (this.isUnapproved()) { } else if (this.isUnapproved()) {
contextualInfo = 'Please unlock token to continue.'; contextualInfo = t("unlockTokenCont");
} else if (!inputValue || !outputValue) { } else if (!inputValue || !outputValue) {
contextualInfo = `Enter a ${inputCurrency} or ${label} value to continue.`; contextualInfo = t("enterCurrencyOrLabelCont", {inputCurrency, label});
} }
return ( return (
<ContextualInfo <ContextualInfo
key="context-info" key="context-info"
openModalText={t("transactionDetails")}
contextualInfo={contextualInfo} contextualInfo={contextualInfo}
isError={isError} isError={isError}
renderTransactionDetails={this.renderTransactionDetails} renderTransactionDetails={this.renderTransactionDetails}
...@@ -436,7 +441,7 @@ class AddLiquidity extends Component { ...@@ -436,7 +441,7 @@ class AddLiquidity extends Component {
} }
renderTransactionDetails = () => { renderTransactionDetails = () => {
const { selectors, exchangeAddresses: { fromToken }, account } = this.props; const { t, selectors, exchangeAddresses: { fromToken }, account } = this.props;
const { const {
inputValue, inputValue,
outputValue, outputValue,
...@@ -474,16 +479,17 @@ class AddLiquidity extends Component { ...@@ -474,16 +479,17 @@ class AddLiquidity extends Component {
return ( return (
<div> <div>
<div className="pool__summary-item">You are adding between {b(`${+BN(inputValue).toFixed(7)} ETH`)} and {b(`${+minOutput.toFixed(7)} - ${+maxOutput.toFixed(7)} ${label}`)} into the liquidity pool.</div> <div className="pool__summary-modal__item">{t("youAreAdding")} {b(`${+BN(inputValue).toFixed(7)} ETH`)} {t("and")} {b(`${+minOutput.toFixed(7)} - ${+maxOutput.toFixed(7)} ${label}`)} {t("intoPool")}</div>
<div className="pool__summary-item">You will mint {b(+liquidityMinted.toFixed(7))} liquidity tokens.</div> <div className="pool__summary-modal__item">{t("youWillMint")} {b(+liquidityMinted.toFixed(7))} {t("liquidityTokens")}</div>
<div className="pool__summary-item">Current total supply of liquidity tokens is {b(+adjTotalSupply.toFixed(7))}</div> <div className="pool__summary-modal__item">{t("totalSupplyIs")} {b(+adjTotalSupply.toFixed(7))}</div>
<div className="pool__summary-item">At current exchange rate, each pool token is worth {b(+ethReserve.dividedBy(totalSupply).toFixed(7))} ETH and {b(+tokenReserve.dividedBy(totalSupply).toFixed(7))} {label}</div> <div className="pool__summary-modal__item">{t("tokenWorth")} {b(+ethReserve.dividedBy(totalSupply).toFixed(7))} ETH {t("and")} {b(+tokenReserve.dividedBy(totalSupply).toFixed(7))} {label}</div>
</div> </div>
); );
} }
render() { render() {
const { const {
t,
isConnected, isConnected,
exchangeAddresses: { fromToken }, exchangeAddresses: { fromToken },
selectors, selectors,
...@@ -516,18 +522,18 @@ class AddLiquidity extends Component { ...@@ -516,18 +522,18 @@ class AddLiquidity extends Component {
? ( ? (
<div className="pool__new-exchange-warning"> <div className="pool__new-exchange-warning">
<div className="pool__new-exchange-warning-text"> <div className="pool__new-exchange-warning-text">
🚰 You are the first person to add liquidity! 🚰 {t("firstLiquidity")}
</div> </div>
<div className="pool__new-exchange-warning-text"> <div className="pool__new-exchange-warning-text">
{`The initial exchange rate will be set based on your deposits. Please make sure that your ETH and ${label} deposits have the same fiat value.`} { t("initialExchangeRate", { label }) }
</div> </div>
</div> </div>
) )
: null : null
} }
<ModeSelector title="Add Liquidity" /> <ModeSelector title={t("addLiquidity")}/>
<CurrencyInputPanel <CurrencyInputPanel
title="Deposit" title={t("deposit")}
extraText={this.getBalance(inputCurrency)} extraText={this.getBalance(inputCurrency)}
onValueChange={this.onInputChange} onValueChange={this.onInputChange}
selectedTokenAddress="ETH" selectedTokenAddress="ETH"
...@@ -541,8 +547,8 @@ class AddLiquidity extends Component { ...@@ -541,8 +547,8 @@ class AddLiquidity extends Component {
</div> </div>
</OversizedPanel> </OversizedPanel>
<CurrencyInputPanel <CurrencyInputPanel
title="Deposit" title={t("deposit")}
description={this.isNewExchange() ? '(estimated)' : ''} description={this.isNewExchange() ? `(${t("estimated")})` : ''}
extraText={this.getBalance(outputCurrency)} extraText={this.getBalance(outputCurrency)}
selectedTokenAddress={outputCurrency} selectedTokenAddress={outputCurrency}
onCurrencySelected={currency => { onCurrencySelected={currency => {
...@@ -568,7 +574,7 @@ class AddLiquidity extends Component { ...@@ -568,7 +574,7 @@ class AddLiquidity extends Component {
disabled={!isValid} disabled={!isValid}
onClick={this.onAddLiquidity} onClick={this.onAddLiquidity}
> >
Add Liquidity {t("addLiquidity")}
</button> </button>
</div> </div>
</div> </div>
...@@ -588,7 +594,7 @@ export default connect( ...@@ -588,7 +594,7 @@ export default connect(
selectors: () => dispatch(selectors()), selectors: () => dispatch(selectors()),
addPendingTx: id => dispatch(addPendingTx(id)), addPendingTx: id => dispatch(addPendingTx(id)),
}) })
)(AddLiquidity); )(withNamespaces()(AddLiquidity));
function b(text) { function b(text) {
return <span className="swap__highlight-text">{text}</span> return <span className="swap__highlight-text">{text}</span>
......
...@@ -2,6 +2,7 @@ import React, { Component } from 'react'; ...@@ -2,6 +2,7 @@ import React, { Component } from 'react';
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import { withRouter } from 'react-router-dom'; import { withRouter } from 'react-router-dom';
import { withNamespaces } from 'react-i18next';
import {selectors, addPendingTx} from "../../ducks/web3connect"; import {selectors, addPendingTx} from "../../ducks/web3connect";
import classnames from "classnames"; import classnames from "classnames";
import NavigationTabs from "../../components/NavigationTabs"; import NavigationTabs from "../../components/NavigationTabs";
...@@ -39,6 +40,7 @@ class CreateExchange extends Component { ...@@ -39,6 +40,7 @@ class CreateExchange extends Component {
validate() { validate() {
const { tokenAddress } = this.state; const { tokenAddress } = this.state;
const { const {
t,
web3, web3,
account, account,
selectors, selectors,
...@@ -59,7 +61,7 @@ class CreateExchange extends Component { ...@@ -59,7 +61,7 @@ class CreateExchange extends Component {
if (web3 && web3.utils && !web3.utils.isAddress(tokenAddress)) { if (web3 && web3.utils && !web3.utils.isAddress(tokenAddress)) {
return { return {
isValid: false, isValid: false,
errorMessage: 'Not a valid token address', errorMessage: t("invalidTokenAddress"),
}; };
} }
...@@ -74,15 +76,15 @@ class CreateExchange extends Component { ...@@ -74,15 +76,15 @@ class CreateExchange extends Component {
} }
}); });
} else { } else {
errorMessage = `${label} Exchange already exists!`; errorMessage = t("exchangeExists", { label });
} }
if (!label) { if (!label) {
errorMessage = 'Invalid symbol'; errorMessage = t("invalidSymbol");
} }
if (!decimals) { if (!decimals) {
errorMessage = 'Invalid decimals'; errorMessage = t("invalidDecimals");
} }
return { return {
...@@ -141,7 +143,7 @@ class CreateExchange extends Component { ...@@ -141,7 +143,7 @@ class CreateExchange extends Component {
if (!tokenAddress) { if (!tokenAddress) {
return ( return (
<div className="create-exchange__summary-panel"> <div className="create-exchange__summary-panel">
<div className="create-exchange__summary-text">Enter a token address to continue</div> <div className="create-exchange__summary-text">{this.props.t("enterTokenCont")}</div>
</div> </div>
) )
} }
...@@ -159,7 +161,7 @@ class CreateExchange extends Component { ...@@ -159,7 +161,7 @@ class CreateExchange extends Component {
render() { render() {
const { tokenAddress } = this.state; const { tokenAddress } = this.state;
const { isConnected, account, selectors, web3 } = this.props; const { t, isConnected, account, selectors, web3 } = this.props;
const { isValid, errorMessage } = this.validate(); const { isValid, errorMessage } = this.validate();
let label, decimals; let label, decimals;
...@@ -181,9 +183,9 @@ class CreateExchange extends Component { ...@@ -181,9 +183,9 @@ class CreateExchange extends Component {
'header--inactive': !isConnected, 'header--inactive': !isConnected,
})} })}
/> />
<ModeSelector title="Create Exchange" /> <ModeSelector title={t("createExchange")} />
<AddressInputPanel <AddressInputPanel
title="Token Address" title={t("tokenAddress")}
value={tokenAddress} value={tokenAddress}
onChange={this.onChange} onChange={this.onChange}
errorMessage={errorMessage} errorMessage={errorMessage}
...@@ -191,11 +193,11 @@ class CreateExchange extends Component { ...@@ -191,11 +193,11 @@ class CreateExchange extends Component {
<OversizedPanel hideBottom> <OversizedPanel hideBottom>
<div className="pool__summary-panel"> <div className="pool__summary-panel">
<div className="pool__exchange-rate-wrapper"> <div className="pool__exchange-rate-wrapper">
<span className="pool__exchange-rate">Label</span> <span className="pool__exchange-rate">{t("label")}</span>
<span>{label || ' - '}</span> <span>{label || ' - '}</span>
</div> </div>
<div className="pool__exchange-rate-wrapper"> <div className="pool__exchange-rate-wrapper">
<span className="swap__exchange-rate">Decimals</span> <span className="swap__exchange-rate">{t("decimals")}</span>
<span>{decimals || ' - '}</span> <span>{decimals || ' - '}</span>
</div> </div>
</div> </div>
...@@ -209,7 +211,7 @@ class CreateExchange extends Component { ...@@ -209,7 +211,7 @@ class CreateExchange extends Component {
disabled={!isValid} disabled={!isValid}
onClick={this.onCreateExchange} onClick={this.onCreateExchange}
> >
Create Exchange {t("createExchange")}
</button> </button>
</div> </div>
</div> </div>
...@@ -232,5 +234,5 @@ export default withRouter( ...@@ -232,5 +234,5 @@ export default withRouter(
addExchange: opts => dispatch(addExchange(opts)), addExchange: opts => dispatch(addExchange(opts)),
addPendingTx: id => dispatch(addPendingTx(id)), addPendingTx: id => dispatch(addPendingTx(id)),
}) })
)(CreateExchange) )(withNamespaces()(CreateExchange))
); );
import React, { Component } from 'react'; import React, { Component } from 'react';
import { withRouter } from 'react-router-dom'; import { withRouter } from 'react-router-dom';
import { withNamespaces } from 'react-i18next';
import OversizedPanel from "../../components/OversizedPanel"; import OversizedPanel from "../../components/OversizedPanel";
import Dropdown from "../../assets/images/dropdown-blue.svg"; import Dropdown from "../../assets/images/dropdown-blue.svg";
import Modal from "../../components/Modal"; import Modal from "../../components/Modal";
...@@ -55,19 +56,19 @@ class ModeSelector extends Component { ...@@ -55,19 +56,19 @@ class ModeSelector extends Component {
className="pool-modal__item" className="pool-modal__item"
onClick={() => this.changeView(ADD)} onClick={() => this.changeView(ADD)}
> >
{ADD} {this.props.t("addLiquidity")}
</div> </div>
<div <div
className="pool-modal__item" className="pool-modal__item"
onClick={() => this.changeView(REMOVE)} onClick={() => this.changeView(REMOVE)}
> >
{REMOVE} {this.props.t("removeLiquidity")}
</div> </div>
<div <div
className="pool-modal__item" className="pool-modal__item"
onClick={() => this.changeView(CREATE)} onClick={() => this.changeView(CREATE)}
> >
{CREATE} {this.props.t("createExchange")}
</div> </div>
</div> </div>
</CSSTransitionGroup> </CSSTransitionGroup>
...@@ -93,4 +94,4 @@ class ModeSelector extends Component { ...@@ -93,4 +94,4 @@ class ModeSelector extends Component {
} }
} }
export default withRouter(ModeSelector); export default withRouter(withNamespaces()(ModeSelector));
...@@ -3,6 +3,7 @@ import PropTypes from 'prop-types'; ...@@ -3,6 +3,7 @@ import PropTypes from 'prop-types';
import classnames from "classnames"; import classnames from "classnames";
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import { BigNumber as BN } from 'bignumber.js'; import { BigNumber as BN } from 'bignumber.js';
import { withNamespaces } from 'react-i18next';
import NavigationTabs from "../../components/NavigationTabs"; import NavigationTabs from "../../components/NavigationTabs";
import ModeSelector from "./ModeSelector"; import ModeSelector from "./ModeSelector";
import CurrencyInputPanel from "../../components/CurrencyInputPanel"; import CurrencyInputPanel from "../../components/CurrencyInputPanel";
...@@ -40,7 +41,7 @@ class RemoveLiquidity extends Component { ...@@ -40,7 +41,7 @@ class RemoveLiquidity extends Component {
validate() { validate() {
const { tokenAddress, value } = this.state; const { tokenAddress, value } = this.state;
const { account, selectors, exchangeAddresses: { fromToken }, web3 } = this.props; const { t, account, selectors, exchangeAddresses: { fromToken }, web3 } = this.props;
const exchangeAddress = fromToken[tokenAddress]; const exchangeAddress = fromToken[tokenAddress];
if (!web3 || !exchangeAddress || !account || !value) { if (!web3 || !exchangeAddress || !account || !value) {
...@@ -54,7 +55,7 @@ class RemoveLiquidity extends Component { ...@@ -54,7 +55,7 @@ class RemoveLiquidity extends Component {
const { value: liquidityBalance, decimals: liquidityDecimals } = getBalance(account, exchangeAddress); const { value: liquidityBalance, decimals: liquidityDecimals } = getBalance(account, exchangeAddress);
if (liquidityBalance.isLessThan(BN(value).multipliedBy(10 ** liquidityDecimals))) { if (liquidityBalance.isLessThan(BN(value).multipliedBy(10 ** liquidityDecimals))) {
return { isValid: false, errorMessage: 'Insufficient balance' }; return { isValid: false, errorMessage: t("insufficientBalance") };
} }
return { return {
...@@ -159,7 +160,7 @@ class RemoveLiquidity extends Component { ...@@ -159,7 +160,7 @@ class RemoveLiquidity extends Component {
}; };
renderSummary(errorMessage) { renderSummary(errorMessage) {
const { selectors, exchangeAddresses: { fromToken } } = this.props; const { t, selectors, exchangeAddresses: { fromToken } } = this.props;
const { const {
value: input, value: input,
tokenAddress, tokenAddress,
...@@ -172,17 +173,18 @@ class RemoveLiquidity extends Component { ...@@ -172,17 +173,18 @@ class RemoveLiquidity extends Component {
contextualInfo = errorMessage; contextualInfo = errorMessage;
isError = true; isError = true;
} else if (!tokenAddress) { } else if (!tokenAddress) {
contextualInfo = 'Select a token to continue.'; contextualInfo = t("selectTokenCont");
} else if (inputIsZero) { } else if (inputIsZero) {
contextualInfo = 'Amount cannot be zero.'; contextualInfo = t("noZero");
} else if (!input) { } else if (!input) {
const { label } = selectors().getTokenBalance(tokenAddress, fromToken[tokenAddress]); const { label } = selectors().getTokenBalance(tokenAddress, fromToken[tokenAddress]);
contextualInfo = `Enter a ${label} value to continue.`; contextualInfo = t("enterLabelCont", { label });
} }
return ( return (
<ContextualInfo <ContextualInfo
key="context-info" key="context-info"
openModalText={t("transactionDetails")}
contextualInfo={contextualInfo} contextualInfo={contextualInfo}
isError={isError} isError={isError}
renderTransactionDetails={this.renderTransactionDetails} renderTransactionDetails={this.renderTransactionDetails}
...@@ -193,6 +195,7 @@ class RemoveLiquidity extends Component { ...@@ -193,6 +195,7 @@ class RemoveLiquidity extends Component {
renderTransactionDetails = () => { renderTransactionDetails = () => {
const { tokenAddress, value: input, totalSupply } = this.state; const { tokenAddress, value: input, totalSupply } = this.state;
const { const {
t,
exchangeAddresses: { fromToken }, exchangeAddresses: { fromToken },
web3, web3,
selectors, selectors,
...@@ -228,16 +231,24 @@ class RemoveLiquidity extends Component { ...@@ -228,16 +231,24 @@ class RemoveLiquidity extends Component {
return ( return (
<div> <div>
<<<<<<< HEAD
<div className="pool__summary-item">You are removing between {b(`${+BN(ethWithdrawn).toFixed(7)} ETH`)} and {b(`${+minTokenWithdrawn} - ${+maxTokenWithdrawn} ${label}`)} into the liquidity pool.</div> <div className="pool__summary-item">You are removing between {b(`${+BN(ethWithdrawn).toFixed(7)} ETH`)} and {b(`${+minTokenWithdrawn} - ${+maxTokenWithdrawn} ${label}`)} into the liquidity pool.</div>
<div className="pool__summary-item">You will remove {b(+input)} liquidity tokens.</div> <div className="pool__summary-item">You will remove {b(+input)} liquidity tokens.</div>
<div className="pool__summary-item">Current total supply of liquidity tokens is {b(+adjTotalSupply.toFixed(7))}</div> <div className="pool__summary-item">Current total supply of liquidity tokens is {b(+adjTotalSupply.toFixed(7))}</div>
<div className="pool__summary-item">At current exchange rate, each pool token is worth {b(+ethReserve.dividedBy(totalSupply).toFixed(7))} ETH and {b(+tokenReserve.dividedBy(totalSupply).toFixed(7))} {label}</div> <div className="pool__summary-item">At current exchange rate, each pool token is worth {b(+ethReserve.dividedBy(totalSupply).toFixed(7))} ETH and {b(+tokenReserve.dividedBy(totalSupply).toFixed(7))} {label}</div>
=======
<div className="pool__summary-modal__item">{t("youAreRemoving")} {b(`${+BN(ethWithdrawn).toFixed(7)} ETH`)} {t("and")} {b(`${+minTokenWithdrawn} - ${+maxTokenWithdrawn} ${label}`)} {t("outPool")}</div>
<div className="pool__summary-modal__item">{t("youWillRemove")} {b(+input)} {t("liquidityTokens")}</div>
<div className="pool__summary-modal__item">{t("totalSupplyIs")} {b(+adjTotalSupply.toFixed(7))}</div>
<div className="pool__summary-modal__item">{t("tokenWorth")} {b(+ethReserve.dividedBy(totalSupply).toFixed(7))} ETH {t("and")} {b(+tokenReserve.dividedBy(totalSupply).toFixed(7))} {label}</div>
>>>>>>> 30eade0... i18n support
</div> </div>
); );
} }
renderOutput() { renderOutput() {
const { const {
t,
exchangeAddresses: { fromToken }, exchangeAddresses: { fromToken },
account, account,
web3, web3,
...@@ -250,8 +261,8 @@ class RemoveLiquidity extends Component { ...@@ -250,8 +261,8 @@ class RemoveLiquidity extends Component {
const blank = [ const blank = [
<CurrencyInputPanel <CurrencyInputPanel
key="remove-liquidity-input" key="remove-liquidity-input"
title="Output" title={t("output")}
description="(estimated)" description={`(${t("estimated")})`}
renderInput={() => ( renderInput={() => (
<div className="remove-liquidity__output"></div> <div className="remove-liquidity__output"></div>
)} )}
...@@ -261,15 +272,15 @@ class RemoveLiquidity extends Component { ...@@ -261,15 +272,15 @@ class RemoveLiquidity extends Component {
<OversizedPanel key="remove-liquidity-input-under" hideBottom> <OversizedPanel key="remove-liquidity-input-under" hideBottom>
<div className="pool__summary-panel"> <div className="pool__summary-panel">
<div className="pool__exchange-rate-wrapper"> <div className="pool__exchange-rate-wrapper">
<span className="pool__exchange-rate">Exchange Rate</span> <span className="pool__exchange-rate">{t("exchangeRate")}</span>
<span> - </span> <span> - </span>
</div> </div>
<div className="pool__exchange-rate-wrapper"> <div className="pool__exchange-rate-wrapper">
<span className="swap__exchange-rate">Current Pool Size</span> <span className="swap__exchange-rate">{t("currentPoolSize")}</span>
<span> - </span> <span> - </span>
</div> </div>
<div className="pool__exchange-rate-wrapper"> <div className="pool__exchange-rate-wrapper">
<span className="swap__exchange-rate">Your Pool Share</span> <span className="swap__exchange-rate">{t("yourPoolShare")}</span>
<span> - </span> <span> - </span>
</div> </div>
</div> </div>
...@@ -299,8 +310,8 @@ class RemoveLiquidity extends Component { ...@@ -299,8 +310,8 @@ class RemoveLiquidity extends Component {
return [ return [
<CurrencyInputPanel <CurrencyInputPanel
title="Output" title={t("output")}
description="(estimated)" description={`(${t("estimated")})`}
key="remove-liquidity-input" key="remove-liquidity-input"
renderInput={() => input renderInput={() => input
? ( ? (
...@@ -322,18 +333,18 @@ class RemoveLiquidity extends Component { ...@@ -322,18 +333,18 @@ class RemoveLiquidity extends Component {
<OversizedPanel key="remove-liquidity-input-under" hideBottom> <OversizedPanel key="remove-liquidity-input-under" hideBottom>
<div className="pool__summary-panel"> <div className="pool__summary-panel">
<div className="pool__exchange-rate-wrapper"> <div className="pool__exchange-rate-wrapper">
<span className="pool__exchange-rate">Exchange Rate</span> <span className="pool__exchange-rate">{t("exchangeRate")}</span>
<span> <span>
{`1 ETH = ${exchangeRate.toFixed(4)} ${label}`} {`1 ETH = ${exchangeRate.toFixed(4)} ${label}`}
</span> </span>
</div> </div>
<div className="pool__exchange-rate-wrapper"> <div className="pool__exchange-rate-wrapper">
<span className="swap__exchange-rate">Current Pool Size</span> <span className="swap__exchange-rate">{t("currentPoolSize")}</span>
<span>{`${ethReserve.dividedBy(10 ** 18).toFixed(2)} ETH + ${tokenReserve.dividedBy(10 ** tokenDecimals).toFixed(2)} ${label}`}</span> <span>{`${ethReserve.dividedBy(10 ** 18).toFixed(2)} ETH + ${tokenReserve.dividedBy(10 ** tokenDecimals).toFixed(2)} ${label}`}</span>
</div> </div>
<div className="pool__exchange-rate-wrapper"> <div className="pool__exchange-rate-wrapper">
<span className="swap__exchange-rate"> <span className="swap__exchange-rate">
Your Pool Share ({ownership.multipliedBy(100).toFixed(2)}%) {t("yourPoolShare")} ({ownership.multipliedBy(100).toFixed(2)}%)
</span> </span>
<span>{`${ownedEth.toFixed(2)} ETH + ${ownedToken.toFixed(2)} ${label}`}</span> <span>{`${ownedEth.toFixed(2)} ETH + ${ownedToken.toFixed(2)} ${label}`}</span>
</div> </div>
...@@ -343,7 +354,7 @@ class RemoveLiquidity extends Component { ...@@ -343,7 +354,7 @@ class RemoveLiquidity extends Component {
} }
render() { render() {
const { isConnected } = this.props; const { t, isConnected } = this.props;
const { tokenAddress, value } = this.state; const { tokenAddress, value } = this.state;
const { isValid, errorMessage } = this.validate(); const { isValid, errorMessage } = this.validate();
...@@ -359,9 +370,9 @@ class RemoveLiquidity extends Component { ...@@ -359,9 +370,9 @@ class RemoveLiquidity extends Component {
'header--inactive': !isConnected, 'header--inactive': !isConnected,
})} })}
/> />
<ModeSelector title="Remove Liquidity" /> <ModeSelector title={t("removeLiquidity")} />
<CurrencyInputPanel <CurrencyInputPanel
title="Pool Tokens" title={t("poolTokens")}
extraText={this.getBalance(tokenAddress)} extraText={this.getBalance(tokenAddress)}
onValueChange={this.onInputChange} onValueChange={this.onInputChange}
value={value} value={value}
...@@ -386,7 +397,7 @@ class RemoveLiquidity extends Component { ...@@ -386,7 +397,7 @@ class RemoveLiquidity extends Component {
disabled={!isValid} disabled={!isValid}
onClick={this.onRemoveLiquidity} onClick={this.onRemoveLiquidity}
> >
Remove Liquidity {t("removeLiquidity")}
</button> </button>
</div> </div>
</div> </div>
...@@ -406,7 +417,7 @@ export default connect( ...@@ -406,7 +417,7 @@ export default connect(
selectors: () => dispatch(selectors()), selectors: () => dispatch(selectors()),
addPendingTx: id => dispatch(addPendingTx(id)), addPendingTx: id => dispatch(addPendingTx(id)),
}) })
)(RemoveLiquidity); )(withNamespaces()(RemoveLiquidity));
function b(text) { function b(text) {
return <span className="swap__highlight-text">{text}</span> return <span className="swap__highlight-text">{text}</span>
......
...@@ -3,6 +3,7 @@ import { connect } from 'react-redux'; ...@@ -3,6 +3,7 @@ import { connect } from 'react-redux';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import classnames from 'classnames'; import classnames from 'classnames';
import {BigNumber as BN} from "bignumber.js"; import {BigNumber as BN} from "bignumber.js";
import { withNamespaces } from 'react-i18next';
import { selectors, addPendingTx } from '../../ducks/web3connect'; import { selectors, addPendingTx } from '../../ducks/web3connect';
import Header from '../../components/Header'; import Header from '../../components/Header';
import NavigationTabs from '../../components/NavigationTabs'; import NavigationTabs from '../../components/NavigationTabs';
...@@ -87,11 +88,11 @@ class Send extends Component { ...@@ -87,11 +88,11 @@ class Send extends Component {
const { value: inputBalance, decimals: inputDecimals } = selectors().getBalance(account, inputCurrency); const { value: inputBalance, decimals: inputDecimals } = selectors().getBalance(account, inputCurrency);
if (inputBalance.isLessThan(BN(inputValue * 10 ** inputDecimals))) { if (inputBalance.isLessThan(BN(inputValue * 10 ** inputDecimals))) {
inputError = 'Insufficient Balance'; inputError = this.props.t("insufficientBalance");
} }
if (inputValue === 'N/A') { if (inputValue === 'N/A') {
inputError = 'Not a valid input value'; inputError = this.props.t("inputNotValid");
} }
return { return {
...@@ -535,7 +536,7 @@ class Send extends Component { ...@@ -535,7 +536,7 @@ class Send extends Component {
outputCurrency, outputCurrency,
recipient, recipient,
} = this.state; } = this.state;
const { web3 } = this.props; const { t, web3 } = this.props;
const { selectors, account } = this.props; const { selectors, account } = this.props;
const { label: inputLabel } = selectors().getBalance(account, inputCurrency); const { label: inputLabel } = selectors().getBalance(account, inputCurrency);
...@@ -551,24 +552,25 @@ class Send extends Component { ...@@ -551,24 +552,25 @@ class Send extends Component {
contextualInfo = inputError || outputError; contextualInfo = inputError || outputError;
isError = true; isError = true;
} else if (!inputCurrency || !outputCurrency) { } else if (!inputCurrency || !outputCurrency) {
contextualInfo = 'Select a token to continue.'; contextualInfo = t("selectTokenCont");
} else if (inputCurrency === outputCurrency) { } else if (inputCurrency === outputCurrency) {
contextualInfo = 'Must be different token.'; contextualInfo = t("differentToken");
} else if (!inputValue || !outputValue) { } else if (!inputValue || !outputValue) {
const missingCurrencyValue = !inputValue ? inputLabel : outputLabel; const missingCurrencyValue = !inputValue ? inputLabel : outputLabel;
contextualInfo = `Enter a ${missingCurrencyValue} value to continue.`; contextualInfo = t("enterValueCont", {missingCurrencyValue});
} else if (inputIsZero || outputIsZero) { } else if (inputIsZero || outputIsZero) {
contextualInfo = 'No liquidity.'; contextualInfo = t("noLiquidity");
} else if (this.isUnapproved()) { } else if (this.isUnapproved()) {
contextualInfo = 'Please unlock token to continue.'; contextualInfo = t("unlockTokenCont");
} else if (!recipient) { } else if (!recipient) {
contextualInfo = 'Enter a wallet address to send to.'; contextualInfo = t("noRecipient");
} else if (!validRecipientAddress) { } else if (!validRecipientAddress) {
contextualInfo = 'Please enter a valid wallet address recipient.'; contextualInfo = t("invalidRecipient");
} }
return ( return (
<ContextualInfo <ContextualInfo
openModalText={t("transactionDetails")}
contextualInfo={contextualInfo} contextualInfo={contextualInfo}
isError={isError} isError={isError}
renderTransactionDetails={this.renderTransactionDetails} renderTransactionDetails={this.renderTransactionDetails}
...@@ -586,7 +588,7 @@ class Send extends Component { ...@@ -586,7 +588,7 @@ class Send extends Component {
inputAmountB, inputAmountB,
lastEditedField, lastEditedField,
} = this.state; } = this.state;
const { selectors, account } = this.props; const { t, selectors, account } = this.props;
ReactGA.event({ ReactGA.event({
category: 'TransactionDetail', category: 'TransactionDetail',
...@@ -641,10 +643,10 @@ class Send extends Component { ...@@ -641,10 +643,10 @@ class Send extends Component {
return ( return (
<div> <div>
<div> <div>
You are selling {b(`${+inputValue} ${inputLabel}`)}. {t("youAreSending")} {b(`${+inputValue} ${inputLabel}`)}.
</div> </div>
<div className="send__last-summary-text"> <div className="send__last-summary-text">
{recipientText} will receive at least {b(`${+minOutput} ${outputLabel}`)} or the transaction will fail. {recipientText} {t("willReceive")} {b(`${+minOutput} ${outputLabel}`)} {t("orTransFail")}
</div> </div>
</div> </div>
); );
...@@ -652,12 +654,12 @@ class Send extends Component { ...@@ -652,12 +654,12 @@ class Send extends Component {
return ( return (
<div> <div>
<div> <div>
You are sending {b(`${+outputValue} ${outputLabel}`)} to {recipientText}. {t("youAreSending")} {b(`${+outputValue} ${outputLabel}`)} {t("to")} {recipientText}.
{/*You are selling between {b(`${+inputValue} ${inputLabel}`)} to {b(`${+maxInput} ${inputLabel}`)}.*/} {/*You are selling between {b(`${+inputValue} ${inputLabel}`)} to {b(`${+maxInput} ${inputLabel}`)}.*/}
</div> </div>
<div className="send__last-summary-text"> <div className="send__last-summary-text">
{/*{b(`${recipient.slice(0, 6)}...${recipient.slice(-4)}`)} will receive {b(`${+outputValue} ${outputLabel}`)}.*/} {/*{b(`${recipient.slice(0, 6)}...${recipient.slice(-4)}`)} will receive {b(`${+outputValue} ${outputLabel}`)}.*/}
It will cost at most {b(`${+maxInput} ${inputLabel}`)} or the transaction will fail. {t("itWillCost")} {b(`${+maxInput} ${inputLabel}`)} {t("orTransFail")}
</div> </div>
</div> </div>
); );
...@@ -665,7 +667,7 @@ class Send extends Component { ...@@ -665,7 +667,7 @@ class Send extends Component {
} }
renderExchangeRate() { renderExchangeRate() {
const { account, selectors } = this.props; const { t, account, selectors } = this.props;
const { exchangeRate, inputCurrency, outputCurrency } = this.state; const { exchangeRate, inputCurrency, outputCurrency } = this.state;
const { label: inputLabel } = selectors().getBalance(account, inputCurrency); const { label: inputLabel } = selectors().getBalance(account, inputCurrency);
const { label: outputLabel } = selectors().getBalance(account, outputCurrency); const { label: outputLabel } = selectors().getBalance(account, outputCurrency);
...@@ -674,7 +676,7 @@ class Send extends Component { ...@@ -674,7 +676,7 @@ class Send extends Component {
return ( return (
<OversizedPanel hideBottom> <OversizedPanel hideBottom>
<div className="swap__exchange-rate-wrapper"> <div className="swap__exchange-rate-wrapper">
<span className="swap__exchange-rate">Exchange Rate</span> <span className="swap__exchange-rate">{t("exchangeRate")}</span>
<span> - </span> <span> - </span>
</div> </div>
</OversizedPanel> </OversizedPanel>
...@@ -684,7 +686,7 @@ class Send extends Component { ...@@ -684,7 +686,7 @@ class Send extends Component {
return ( return (
<OversizedPanel hideBottom> <OversizedPanel hideBottom>
<div className="swap__exchange-rate-wrapper"> <div className="swap__exchange-rate-wrapper">
<span className="swap__exchange-rate">Exchange Rate</span> <span className="swap__exchange-rate">{t("exchangeRate")}</span>
<span> <span>
{`1 ${inputLabel} = ${exchangeRate.toFixed(7)} ${outputLabel}`} {`1 ${inputLabel} = ${exchangeRate.toFixed(7)} ${outputLabel}`}
</span> </span>
...@@ -697,12 +699,12 @@ class Send extends Component { ...@@ -697,12 +699,12 @@ class Send extends Component {
if (!currency || decimals === 0) { if (!currency || decimals === 0) {
return ''; return '';
} }
const balanceInput = balance.dividedBy(BN(10 ** decimals)).toFixed(4)
return `Balance: ${balance.dividedBy(BN(10 ** decimals)).toFixed(4)}` return this.props.t("balance", { balanceInput })
} }
render() { render() {
const { selectors, account } = this.props; const { t, selectors, account } = this.props;
const { const {
lastEditedField, lastEditedField,
inputCurrency, inputCurrency,
...@@ -711,7 +713,7 @@ class Send extends Component { ...@@ -711,7 +713,7 @@ class Send extends Component {
outputValue, outputValue,
recipient, recipient,
} = this.state; } = this.state;
const estimatedText = '(estimated)'; const estimatedText = `(${t("estimated")})`;
const { value: inputBalance, decimals: inputDecimals } = selectors().getBalance(account, inputCurrency); const { value: inputBalance, decimals: inputDecimals } = selectors().getBalance(account, inputCurrency);
const { value: outputBalance, decimals: outputDecimals } = selectors().getBalance(account, outputCurrency); const { value: outputBalance, decimals: outputDecimals } = selectors().getBalance(account, outputCurrency);
...@@ -733,7 +735,7 @@ class Send extends Component { ...@@ -733,7 +735,7 @@ class Send extends Component {
})} })}
/> />
<CurrencyInputPanel <CurrencyInputPanel
title="Input" title={t("input")}
description={lastEditedField === OUTPUT ? estimatedText : ''} description={lastEditedField === OUTPUT ? estimatedText : ''}
extraText={this.renderBalance(inputCurrency, inputBalance, inputDecimals)} extraText={this.renderBalance(inputCurrency, inputBalance, inputDecimals)}
onCurrencySelected={inputCurrency => this.setState({ inputCurrency }, this.recalcForm)} onCurrencySelected={inputCurrency => this.setState({ inputCurrency }, this.recalcForm)}
...@@ -749,7 +751,7 @@ class Send extends Component { ...@@ -749,7 +751,7 @@ class Send extends Component {
</div> </div>
</OversizedPanel> </OversizedPanel>
<CurrencyInputPanel <CurrencyInputPanel
title="Output" title={t("output")}
description={lastEditedField === INPUT ? estimatedText : ''} description={lastEditedField === INPUT ? estimatedText : ''}
extraText={this.renderBalance(outputCurrency, outputBalance, outputDecimals)} extraText={this.renderBalance(outputCurrency, outputBalance, outputDecimals)}
onCurrencySelected={outputCurrency => this.setState({ outputCurrency }, this.recalcForm)} onCurrencySelected={outputCurrency => this.setState({ outputCurrency }, this.recalcForm)}
...@@ -766,6 +768,7 @@ class Send extends Component { ...@@ -766,6 +768,7 @@ class Send extends Component {
</div> </div>
</OversizedPanel> </OversizedPanel>
<AddressInputPanel <AddressInputPanel
t={this.props.t}
value={recipient} value={recipient}
onChange={address => this.setState({recipient: address})} onChange={address => this.setState({recipient: address})}
/> />
...@@ -779,7 +782,7 @@ class Send extends Component { ...@@ -779,7 +782,7 @@ class Send extends Component {
disabled={!isValid} disabled={!isValid}
onClick={this.onSend} onClick={this.onSend}
> >
Send {t("send")}
</button> </button>
</div> </div>
</div> </div>
...@@ -800,7 +803,7 @@ export default connect( ...@@ -800,7 +803,7 @@ export default connect(
selectors: () => dispatch(selectors()), selectors: () => dispatch(selectors()),
addPendingTx: id => dispatch(addPendingTx(id)), addPendingTx: id => dispatch(addPendingTx(id)),
}), }),
)(Send); )(withNamespaces()(Send));
const b = text => <span className="swap__highlight-text">{text}</span>; const b = text => <span className="swap__highlight-text">{text}</span>;
......
...@@ -5,6 +5,7 @@ import classnames from 'classnames'; ...@@ -5,6 +5,7 @@ import classnames from 'classnames';
import {BigNumber as BN} from "bignumber.js"; import {BigNumber as BN} from "bignumber.js";
import MediaQuery from 'react-responsive'; import MediaQuery from 'react-responsive';
import ReactGA from 'react-ga'; import ReactGA from 'react-ga';
import { withNamespaces } from 'react-i18next';
import { selectors, addPendingTx } from '../../ducks/web3connect'; import { selectors, addPendingTx } from '../../ducks/web3connect';
import Header from '../../components/Header'; import Header from '../../components/Header';
import NavigationTabs from '../../components/NavigationTabs'; import NavigationTabs from '../../components/NavigationTabs';
...@@ -84,11 +85,11 @@ class Swap extends Component { ...@@ -84,11 +85,11 @@ class Swap extends Component {
const { value: inputBalance, decimals: inputDecimals } = selectors().getBalance(account, inputCurrency); const { value: inputBalance, decimals: inputDecimals } = selectors().getBalance(account, inputCurrency);
if (inputBalance.isLessThan(BN(inputValue * 10 ** inputDecimals))) { if (inputBalance.isLessThan(BN(inputValue * 10 ** inputDecimals))) {
inputError = 'Insufficient Balance'; inputError = this.props.t("insufficientBalance");
} }
if (inputValue === 'N/A') { if (inputValue === 'N/A') {
inputError = 'Not a valid input value'; inputError = this.props.t("inputNotValid");
} }
return { return {
...@@ -525,6 +526,7 @@ class Swap extends Component { ...@@ -525,6 +526,7 @@ class Swap extends Component {
outputValue, outputValue,
outputCurrency, outputCurrency,
} = this.state; } = this.state;
const t = this.props.t;
const inputIsZero = BN(inputValue).isZero(); const inputIsZero = BN(inputValue).isZero();
const outputIsZero = BN(outputValue).isZero(); const outputIsZero = BN(outputValue).isZero();
...@@ -532,11 +534,11 @@ class Swap extends Component { ...@@ -532,11 +534,11 @@ class Swap extends Component {
let isError = false; let isError = false;
if (!inputCurrency || !outputCurrency) { if (!inputCurrency || !outputCurrency) {
contextualInfo = 'Select a token to continue.'; contextualInfo = t("selectTokenCont");
} }
if (!inputValue || !outputValue) { if (!inputValue || !outputValue) {
contextualInfo = 'Enter a value to continue.'; contextualInfo = t("enterValueCont");
} }
if (inputError || outputError) { if (inputError || outputError) {
...@@ -545,15 +547,16 @@ class Swap extends Component { ...@@ -545,15 +547,16 @@ class Swap extends Component {
} }
if (inputIsZero || outputIsZero) { if (inputIsZero || outputIsZero) {
contextualInfo = 'No liquidity.'; contextualInfo = t("noLiquidity");
} }
if (this.isUnapproved()) { if (this.isUnapproved()) {
contextualInfo = 'Please unlock token to continue.'; contextualInfo = t("unlockTokenCont");
} }
return ( return (
<ContextualInfo <ContextualInfo
openModalText={t("transactionDetails")}
contextualInfo={contextualInfo} contextualInfo={contextualInfo}
isError={isError} isError={isError}
renderTransactionDetails={this.renderTransactionDetails} renderTransactionDetails={this.renderTransactionDetails}
...@@ -569,7 +572,7 @@ class Swap extends Component { ...@@ -569,7 +572,7 @@ class Swap extends Component {
outputCurrency, outputCurrency,
lastEditedField, lastEditedField,
} = this.state; } = this.state;
const { selectors, account } = this.props; const { t, selectors, account } = this.props;
ReactGA.event({ ReactGA.event({
category: 'TransactionDetail', category: 'TransactionDetail',
...@@ -623,10 +626,10 @@ class Swap extends Component { ...@@ -623,10 +626,10 @@ class Swap extends Component {
return ( return (
<div> <div>
<div> <div>
You are selling {b(`${+inputValue} ${inputLabel}`)}. {t("youAreSelling")} {b(`${+inputValue} ${inputLabel}`)} {t("orTransFail")}
</div> </div>
<div className="send__last-summary-text"> <div className="send__last-summary-text">
You will receive at least {b(`${+minOutput} ${outputLabel}`)} or the transaction will fail. {t("youWillReceive")} {b(`${+minOutput} ${outputLabel}`)} {t("orTransFail")}
</div> </div>
</div> </div>
); );
...@@ -634,10 +637,10 @@ class Swap extends Component { ...@@ -634,10 +637,10 @@ class Swap extends Component {
return ( return (
<div> <div>
<div> <div>
You are buying {b(`${+outputValue} ${outputLabel}`)}. {t("youAreBuying")} {b(`${+outputValue} ${outputLabel}`)}.
</div> </div>
<div className="send__last-summary-text"> <div className="send__last-summary-text">
It will cost at most {b(`${+maxInput} ${inputLabel}`)} or the transaction will fail. {t("itWillCost")} {b(`${+maxInput} ${inputLabel}`)} {t("orTransFail")}
</div> </div>
</div> </div>
); );
...@@ -645,7 +648,7 @@ class Swap extends Component { ...@@ -645,7 +648,7 @@ class Swap extends Component {
} }
renderExchangeRate() { renderExchangeRate() {
const { account, selectors } = this.props; const { t, account, selectors } = this.props;
const { exchangeRate, inputCurrency, outputCurrency } = this.state; const { exchangeRate, inputCurrency, outputCurrency } = this.state;
const { label: inputLabel } = selectors().getBalance(account, inputCurrency); const { label: inputLabel } = selectors().getBalance(account, inputCurrency);
const { label: outputLabel } = selectors().getBalance(account, outputCurrency); const { label: outputLabel } = selectors().getBalance(account, outputCurrency);
...@@ -654,7 +657,7 @@ class Swap extends Component { ...@@ -654,7 +657,7 @@ class Swap extends Component {
return ( return (
<OversizedPanel hideBottom> <OversizedPanel hideBottom>
<div className="swap__exchange-rate-wrapper"> <div className="swap__exchange-rate-wrapper">
<span className="swap__exchange-rate">Exchange Rate</span> <span className="swap__exchange-rate">{t("exchangeRate")}</span>
<span> - </span> <span> - </span>
</div> </div>
</OversizedPanel> </OversizedPanel>
...@@ -664,7 +667,7 @@ class Swap extends Component { ...@@ -664,7 +667,7 @@ class Swap extends Component {
return ( return (
<OversizedPanel hideBottom> <OversizedPanel hideBottom>
<div className="swap__exchange-rate-wrapper"> <div className="swap__exchange-rate-wrapper">
<span className="swap__exchange-rate">Exchange Rate</span> <span className="swap__exchange-rate">{t("exchangeRate")}</span>
<span> <span>
{`1 ${inputLabel} = ${exchangeRate.toFixed(7)} ${outputLabel}`} {`1 ${inputLabel} = ${exchangeRate.toFixed(7)} ${outputLabel}`}
</span> </span>
...@@ -678,11 +681,12 @@ class Swap extends Component { ...@@ -678,11 +681,12 @@ class Swap extends Component {
return ''; return '';
} }
return `Balance: ${balance.dividedBy(BN(10 ** decimals)).toFixed(4)}` const balanceInput = balance.dividedBy(BN(10 ** decimals)).toFixed(4)
return this.props.t("balance", { balanceInput })
} }
render() { render() {
const { selectors, account } = this.props; const { t, selectors, account } = this.props;
const { const {
lastEditedField, lastEditedField,
inputCurrency, inputCurrency,
...@@ -690,7 +694,7 @@ class Swap extends Component { ...@@ -690,7 +694,7 @@ class Swap extends Component {
inputValue, inputValue,
outputValue, outputValue,
} = this.state; } = this.state;
const estimatedText = '(estimated)'; const estimatedText = `(${t("estimated")})`;
const { value: inputBalance, decimals: inputDecimals } = selectors().getBalance(account, inputCurrency); const { value: inputBalance, decimals: inputDecimals } = selectors().getBalance(account, inputCurrency);
const { value: outputBalance, decimals: outputDecimals } = selectors().getBalance(account, outputCurrency); const { value: outputBalance, decimals: outputDecimals } = selectors().getBalance(account, outputCurrency);
...@@ -715,7 +719,7 @@ class Swap extends Component { ...@@ -715,7 +719,7 @@ class Swap extends Component {
})} })}
/> />
<CurrencyInputPanel <CurrencyInputPanel
title="Input" title={t("input")}
description={lastEditedField === OUTPUT ? estimatedText : ''} description={lastEditedField === OUTPUT ? estimatedText : ''}
extraText={this.renderBalance(inputCurrency, inputBalance, inputDecimals)} extraText={this.renderBalance(inputCurrency, inputBalance, inputDecimals)}
onCurrencySelected={inputCurrency => this.setState({ inputCurrency }, this.recalcForm)} onCurrencySelected={inputCurrency => this.setState({ inputCurrency }, this.recalcForm)}
...@@ -731,7 +735,7 @@ class Swap extends Component { ...@@ -731,7 +735,7 @@ class Swap extends Component {
</div> </div>
</OversizedPanel> </OversizedPanel>
<CurrencyInputPanel <CurrencyInputPanel
title="Output" title={t("output")}
description={lastEditedField === INPUT ? estimatedText : ''} description={lastEditedField === INPUT ? estimatedText : ''}
extraText={this.renderBalance(outputCurrency, outputBalance, outputDecimals)} extraText={this.renderBalance(outputCurrency, outputBalance, outputDecimals)}
onCurrencySelected={outputCurrency => this.setState({ outputCurrency }, this.recalcForm)} onCurrencySelected={outputCurrency => this.setState({ outputCurrency }, this.recalcForm)}
...@@ -752,7 +756,7 @@ class Swap extends Component { ...@@ -752,7 +756,7 @@ class Swap extends Component {
disabled={!isValid} disabled={!isValid}
onClick={this.onSwap} onClick={this.onSwap}
> >
Swap {t("swap")}
</button> </button>
</div> </div>
</div> </div>
...@@ -773,7 +777,7 @@ export default connect( ...@@ -773,7 +777,7 @@ export default connect(
selectors: () => dispatch(selectors()), selectors: () => dispatch(selectors()),
addPendingTx: id => dispatch(addPendingTx(id)), addPendingTx: id => dispatch(addPendingTx(id)),
}), }),
)(Swap); )(withNamespaces()(Swap));
const b = text => <span className="swap__highlight-text">{text}</span>; const b = text => <span className="swap__highlight-text">{text}</span>;
......
...@@ -751,6 +751,13 @@ ...@@ -751,6 +751,13 @@
dependencies: dependencies:
regenerator-runtime "^0.12.0" regenerator-runtime "^0.12.0"
"@babel/runtime@^7.1.2":
version "7.2.0"
resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.2.0.tgz#b03e42eeddf5898e00646e4c840fa07ba8dcad7f"
integrity sha512-oouEibCbHMVdZSDlJBO6bZmID/zA/G/Qx3H1d3rSNPTD+L8UNKvCat7aKWSJ74zYbm5zWGh0GQN0hKj8zYFTCg==
dependencies:
regenerator-runtime "^0.12.0"
"@babel/template@7.0.0-beta.44": "@babel/template@7.0.0-beta.44":
version "7.0.0-beta.44" version "7.0.0-beta.44"
resolved "http://registry.npmjs.org/@babel/template/-/template-7.0.0-beta.44.tgz#f8832f4fdcee5d59bf515e595fc5106c529b394f" resolved "http://registry.npmjs.org/@babel/template/-/template-7.0.0-beta.44.tgz#f8832f4fdcee5d59bf515e595fc5106c529b394f"
...@@ -2994,6 +3001,14 @@ create-hmac@^1.1.0, create-hmac@^1.1.2, create-hmac@^1.1.4: ...@@ -2994,6 +3001,14 @@ create-hmac@^1.1.0, create-hmac@^1.1.2, create-hmac@^1.1.4:
safe-buffer "^5.0.1" safe-buffer "^5.0.1"
sha.js "^2.4.8" sha.js "^2.4.8"
create-react-context@0.2.3:
version "0.2.3"
resolved "https://registry.yarnpkg.com/create-react-context/-/create-react-context-0.2.3.tgz#9ec140a6914a22ef04b8b09b7771de89567cb6f3"
integrity sha512-CQBmD0+QGgTaxDL3OX1IDXYqjkp2It4RIbcb99jS6AEg27Ga+a9G3JtK6SIu0HBwPLZlmwt9F7UwWA4Bn92Rag==
dependencies:
fbjs "^0.8.0"
gud "^1.0.0"
cross-spawn@6.0.5, cross-spawn@^6.0.0, cross-spawn@^6.0.5: cross-spawn@6.0.5, cross-spawn@^6.0.0, cross-spawn@^6.0.5:
version "6.0.5" version "6.0.5"
resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-6.0.5.tgz#4a5ec7c64dfae22c3a14124dbacdee846d80cbc4" resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-6.0.5.tgz#4a5ec7c64dfae22c3a14124dbacdee846d80cbc4"
...@@ -4835,6 +4850,19 @@ fb-watchman@^2.0.0: ...@@ -4835,6 +4850,19 @@ fb-watchman@^2.0.0:
dependencies: dependencies:
bser "^2.0.0" bser "^2.0.0"
fbjs@^0.8.0:
version "0.8.17"
resolved "https://registry.yarnpkg.com/fbjs/-/fbjs-0.8.17.tgz#c4d598ead6949112653d6588b01a5cdcd9f90fdd"
integrity sha1-xNWY6taUkRJlPWWIsBpc3Nn5D90=
dependencies:
core-js "^1.0.0"
isomorphic-fetch "^2.1.1"
loose-envify "^1.0.0"
object-assign "^4.1.0"
promise "^7.1.1"
setimmediate "^1.0.5"
ua-parser-js "^0.7.18"
fbjs@^0.8.16: fbjs@^0.8.16:
version "0.8.16" version "0.8.16"
resolved "https://registry.yarnpkg.com/fbjs/-/fbjs-0.8.16.tgz#5e67432f550dc41b572bf55847b8aca64e5337db" resolved "https://registry.yarnpkg.com/fbjs/-/fbjs-0.8.16.tgz#5e67432f550dc41b572bf55847b8aca64e5337db"
...@@ -5522,6 +5550,11 @@ growly@^1.3.0: ...@@ -5522,6 +5550,11 @@ growly@^1.3.0:
resolved "https://registry.yarnpkg.com/growly/-/growly-1.3.0.tgz#f10748cbe76af964b7c96c93c6bcc28af120c081" resolved "https://registry.yarnpkg.com/growly/-/growly-1.3.0.tgz#f10748cbe76af964b7c96c93c6bcc28af120c081"
integrity sha1-8QdIy+dq+WS3yWyTxrzCivEgwIE= integrity sha1-8QdIy+dq+WS3yWyTxrzCivEgwIE=
gud@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/gud/-/gud-1.0.0.tgz#a489581b17e6a70beca9abe3ae57de7a499852c0"
integrity sha512-zGEOVKFM5sVPPrYs7J5/hYEw2Pof8KCyOwyhG8sAF26mCAeUFAcYPu1mwB7hhpIP29zOIBaDqwuHdLp0jvZXjw==
gzip-size@5.0.0: gzip-size@5.0.0:
version "5.0.0" version "5.0.0"
resolved "https://registry.yarnpkg.com/gzip-size/-/gzip-size-5.0.0.tgz#a55ecd99222f4c48fd8c01c625ce3b349d0a0e80" resolved "https://registry.yarnpkg.com/gzip-size/-/gzip-size-5.0.0.tgz#a55ecd99222f4c48fd8c01c625ce3b349d0a0e80"
...@@ -5767,6 +5800,13 @@ hoek@4.x.x: ...@@ -5767,6 +5800,13 @@ hoek@4.x.x:
resolved "https://registry.yarnpkg.com/hoek/-/hoek-4.2.0.tgz#72d9d0754f7fe25ca2d01ad8f8f9a9449a89526d" resolved "https://registry.yarnpkg.com/hoek/-/hoek-4.2.0.tgz#72d9d0754f7fe25ca2d01ad8f8f9a9449a89526d"
integrity sha512-v0XCLxICi9nPfYrS9RL8HbYnXi9obYAeLbSP00BmnZwCK9+Ih9WOjoZ8YoHCoav2csqn4FOz4Orldsy2dmDwmQ== integrity sha512-v0XCLxICi9nPfYrS9RL8HbYnXi9obYAeLbSP00BmnZwCK9+Ih9WOjoZ8YoHCoav2csqn4FOz4Orldsy2dmDwmQ==
hoist-non-react-statics@3.0.1:
version "3.0.1"
resolved "https://registry.yarnpkg.com/hoist-non-react-statics/-/hoist-non-react-statics-3.0.1.tgz#fba3e7df0210eb9447757ca1a7cb607162f0a364"
integrity sha512-1kXwPsOi0OGQIZNVMPvgWJ9tSnGMiMfJdihqEzrPEXlHOBh9AAHXX/QYmAJTXztnz/K+PQ8ryCb4eGaN6HlGbQ==
dependencies:
react-is "^16.3.2"
hoist-non-react-statics@^2.5.0: hoist-non-react-statics@^2.5.0:
version "2.5.5" version "2.5.5"
resolved "https://registry.yarnpkg.com/hoist-non-react-statics/-/hoist-non-react-statics-2.5.5.tgz#c5903cf409c0dfd908f388e619d86b9c1174cb47" resolved "https://registry.yarnpkg.com/hoist-non-react-statics/-/hoist-non-react-statics-2.5.5.tgz#c5903cf409c0dfd908f388e619d86b9c1174cb47"
...@@ -5853,6 +5893,13 @@ html-minifier@^3.2.3: ...@@ -5853,6 +5893,13 @@ html-minifier@^3.2.3:
relateurl "0.2.x" relateurl "0.2.x"
uglify-js "3.3.x" uglify-js "3.3.x"
html-parse-stringify2@2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/html-parse-stringify2/-/html-parse-stringify2-2.0.1.tgz#dc5670b7292ca158b7bc916c9a6735ac8872834a"
integrity sha1-3FZwtyksoVi3vJFsmmc1rIhyg0o=
dependencies:
void-elements "^2.0.1"
html-webpack-plugin@4.0.0-alpha.2: html-webpack-plugin@4.0.0-alpha.2:
version "4.0.0-alpha.2" version "4.0.0-alpha.2"
resolved "https://registry.yarnpkg.com/html-webpack-plugin/-/html-webpack-plugin-4.0.0-alpha.2.tgz#7745967e389a57a098e26963f328ebe4c19b598d" resolved "https://registry.yarnpkg.com/html-webpack-plugin/-/html-webpack-plugin-4.0.0-alpha.2.tgz#7745967e389a57a098e26963f328ebe4c19b598d"
...@@ -5966,6 +6013,21 @@ hyphenate-style-name@^1.0.0: ...@@ -5966,6 +6013,21 @@ hyphenate-style-name@^1.0.0:
resolved "https://registry.yarnpkg.com/hyphenate-style-name/-/hyphenate-style-name-1.0.2.tgz#31160a36930adaf1fc04c6074f7eb41465d4ec4b" resolved "https://registry.yarnpkg.com/hyphenate-style-name/-/hyphenate-style-name-1.0.2.tgz#31160a36930adaf1fc04c6074f7eb41465d4ec4b"
integrity sha1-MRYKNpMK2vH8BMYHT360FGXU7Es= integrity sha1-MRYKNpMK2vH8BMYHT360FGXU7Es=
i18next-browser-languagedetector@^2.2.4:
version "2.2.4"
resolved "https://registry.yarnpkg.com/i18next-browser-languagedetector/-/i18next-browser-languagedetector-2.2.4.tgz#b02412d7ab15d7d74e1b1317d67d8a244b219ee3"
integrity sha512-wPbtH18FdOuB245I8Bhma5/XSDdN/HpYlX+wga1eMy+slhaFQSnrWX6fp+aYSL2eEuj0RlfHeEVz6Fo/lxAj6A==
i18next-xhr-backend@^1.5.1:
version "1.5.1"
resolved "https://registry.yarnpkg.com/i18next-xhr-backend/-/i18next-xhr-backend-1.5.1.tgz#50282610780c6a696d880dfa7f4ac1d01e8c3ad5"
integrity sha512-9OLdC/9YxDvTFcgsH5t2BHCODHEotHCa6h7Ly0EUlUC7Y2GS09UeoHOGj3gWKQ3HCqXz8NlH4gOrK3NNc9vPuw==
i18next@^13.0.1:
version "13.0.1"
resolved "https://registry.yarnpkg.com/i18next/-/i18next-13.0.1.tgz#aac758333e01a712710a81447bf033e6a0dbb71c"
integrity sha512-V9hnqoP7N7aHncb1FYvHcAgKiDTmVpNuIr70QGFTyyNUVlQwz2O393fM0x7JIm0/ZYsoKjZdwtlGKYO4aYJ79Q==
iconv-lite@0.4, iconv-lite@0.4.24, iconv-lite@^0.4.24, iconv-lite@^0.4.4: iconv-lite@0.4, iconv-lite@0.4.24, iconv-lite@^0.4.24, iconv-lite@^0.4.4:
version "0.4.24" version "0.4.24"
resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b" resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b"
...@@ -10374,6 +10436,16 @@ react-helmet@^5.2.0: ...@@ -10374,6 +10436,16 @@ react-helmet@^5.2.0:
prop-types "^15.5.4" prop-types "^15.5.4"
react-side-effect "^1.1.0" react-side-effect "^1.1.0"
react-i18next@^8.4.0:
version "8.4.0"
resolved "https://registry.yarnpkg.com/react-i18next/-/react-i18next-8.4.0.tgz#e9f0c5b9938b155eaa6051360614719c08cae72f"
integrity sha512-zIO/bc1L0UUGdaws2y40cTiSQHuQud5e9SSodYM6MTzhJTI3iayxCCdgvotblOLM4taOD77Ct2/fUbheQIhyeg==
dependencies:
"@babel/runtime" "^7.1.2"
create-react-context "0.2.3"
hoist-non-react-statics "3.0.1"
html-parse-stringify2 "2.0.1"
react-input-autosize@^2.1.2: react-input-autosize@^2.1.2:
version "2.2.1" version "2.2.1"
resolved "https://registry.yarnpkg.com/react-input-autosize/-/react-input-autosize-2.2.1.tgz#ec428fa15b1592994fb5f9aa15bb1eb6baf420f8" resolved "https://registry.yarnpkg.com/react-input-autosize/-/react-input-autosize-2.2.1.tgz#ec428fa15b1592994fb5f9aa15bb1eb6baf420f8"
...@@ -10381,6 +10453,11 @@ react-input-autosize@^2.1.2: ...@@ -10381,6 +10453,11 @@ react-input-autosize@^2.1.2:
dependencies: dependencies:
prop-types "^15.5.8" prop-types "^15.5.8"
react-is@^16.3.2:
version "16.7.0"
resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.7.0.tgz#c1bd21c64f1f1364c6f70695ec02d69392f41bfa"
integrity sha512-Z0VRQdF4NPDoI0tsXVMLkJLiwEBa+RP66g0xDHxgxysxSoCUccSten4RTF/UFvZF1dZvZ9Zu1sx+MDXwcOR34g==
react-motion@^0.5.0: react-motion@^0.5.0:
version "0.5.2" version "0.5.2"
resolved "https://registry.yarnpkg.com/react-motion/-/react-motion-0.5.2.tgz#0dd3a69e411316567927917c6626551ba0607316" resolved "https://registry.yarnpkg.com/react-motion/-/react-motion-0.5.2.tgz#0dd3a69e411316567927917c6626551ba0607316"
...@@ -12964,6 +13041,11 @@ vm-browserify@0.0.4: ...@@ -12964,6 +13041,11 @@ vm-browserify@0.0.4:
dependencies: dependencies:
indexof "0.0.1" indexof "0.0.1"
void-elements@^2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/void-elements/-/void-elements-2.0.1.tgz#c066afb582bb1cb4128d60ea92392e94d5e9dbec"
integrity sha1-wGavtYK7HLQSjWDqkjkulNXp2+w=
w3c-hr-time@^1.0.1: w3c-hr-time@^1.0.1:
version "1.0.1" version "1.0.1"
resolved "https://registry.yarnpkg.com/w3c-hr-time/-/w3c-hr-time-1.0.1.tgz#82ac2bff63d950ea9e3189a58a65625fedf19045" resolved "https://registry.yarnpkg.com/w3c-hr-time/-/w3c-hr-time-1.0.1.tgz#82ac2bff63d950ea9e3189a58a65625fedf19045"
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment