feat(web3): use i18next (#5256)

This commit is contained in:
Bartłomiej Głownia 2023-11-18 01:44:30 +01:00 committed by GitHub
parent b6052bc3e5
commit c3ef639daf
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 413 additions and 186 deletions

View File

@ -10,8 +10,9 @@ import en_fills from './locales/en/fills.json';
import en_funding_payments from './locales/en/funding-payments.json'; import en_funding_payments from './locales/en/funding-payments.json';
import en_governance from './locales/en/governance.json'; import en_governance from './locales/en/governance.json';
import en_trading from './locales/en/trading.json'; import en_trading from './locales/en/trading.json';
import en_markets from './locales/en/markets.json'; import en_markets from './locales/en/markets.json';
import en_web3 from './locales/en/web3.json';
export const locales = { export const locales = {
en: { en: {
accounts: en_accounts, accounts: en_accounts,
@ -26,5 +27,6 @@ export const locales = {
governance: en_governance, governance: en_governance,
trading: en_trading, trading: en_trading,
markets: en_markets, markets: en_markets,
web3: en_web3,
}, },
}; };

View File

@ -0,0 +1,110 @@
{
"{{title}} complete": "{{title}} complete",
"{{title}} failed": "{{title}} failed",
"{{title}} pending": "{{title}} pending",
"Action required": "Action required",
"Approved": "Approved",
"Await Ethereum transaction": "Await Ethereum transaction",
"Awaiting confirmation": "Awaiting confirmation",
"Awaiting confirmations {{confirmations}}/{[requiredConfirmations}}": "Awaiting confirmations {{confirmations}}/{[requiredConfirmations}}",
"Awaiting Ethereum transaction {{confirmations}}/{{requiredConfirmations}} confirmations...": "Awaiting Ethereum transaction {{confirmations}}/{{requiredConfirmations}} confirmations...",
"Batch market instruction": "Batch market instruction",
"Cancel all orders": "Cancel all orders",
"Cancel all orders for <strong>{{marketName}}</strong>": "Cancel all orders for <strong>{{marketName}}</strong>",
"Cancel all stop orders": "Cancel all stop orders",
"Cancel all stop orders for <strong>{{marketName}}</strong>": "Cancel all stop orders for <strong>{{marketName}}</strong>",
"Cancel order": "Cancel order",
"Cancel order - {{status}}": "Cancel order - {{status}}",
"Cancel stop order": "Cancel stop order",
"Cannot be completed until {{time}}": "Cannot be completed until {{time}}",
"Change network": "Change network",
"Close": "Close",
"Close position for <strong>{{marketName}}</strong>": "Close position for <strong>{{marketName}}</strong>",
"Coinbase": "Coinbase",
"Complete withdrawal": "Complete withdrawal",
"Confirm transaction": "Confirm transaction",
"Confirm transaction in wallet": "Confirm transaction in wallet",
"Confirmed": "Confirmed",
"Confirmed in wallet": "Confirmed in wallet",
"Connect to your Ethereum wallet": "Connect to your Ethereum wallet",
"Connect wallet": "Connect wallet",
"Connect wallet to withdraw": "Connect wallet to withdraw",
"Copy": "Copy",
"Delayed": "Delayed",
"Deposit": "Deposit",
"Edit order": "Edit order",
"Edit order - {{status}}": "Edit order - {{status}}",
"Error": "Error",
"Error occurred": "Error occurred",
"Error: {{errorMessage}}": "Error: {{errorMessage}}",
"Ethereum transaction complete": "Ethereum transaction complete",
"Filled": "Filled",
"Funds unlocked": "Funds unlocked",
"Go to your Ethereum wallet and connect to the network {{networkName}}": "Go to your Ethereum wallet and connect to the network {{networkName}}",
"If the network is reset or has an outage, records of your withdrawal may be lost. It is recommended that you save these details in a safe place so you can still complete your withdrawal.": "If the network is reset or has an outage, records of your withdrawal may be lost. It is recommended that you save these details in a safe place so you can still complete your withdrawal.",
"Invalid asset source: {{source}}": "Invalid asset source: {{source}}",
"Loading": "Loading",
"MetaMask": "MetaMask",
"MetaMask, Brave or other injected web wallet": "MetaMask, Brave or other injected web wallet",
"No data": "No data",
"Order cancelled'": "Order cancelled'",
"Order expired'": "Order expired'",
"Order filled": "Order filled",
"Order parked": "Order parked",
"Order partially filled": "Order partially filled",
"Order rejected": "Order rejected",
"Order stopped": "Order stopped",
"Order submitted": "Order submitted",
"Pending approval": "Pending approval",
"Please go to your Vega wallet application and approve or reject the transaction.": "Please go to your Vega wallet application and approve or reject the transaction.",
"Please go to your wallet application and approve or reject the transaction.": "Please go to your wallet application and approve or reject the transaction.",
"Please wait for your transaction to be confirmed": "Please wait for your transaction to be confirmed",
"Please wait for your transaction to be confirmed.": "Please wait for your transaction to be confirmed.",
"Processing": "Processing",
"Processing deposit": "Processing deposit",
"Return": "Return",
"Save withdrawal details": "Save withdrawal details",
"save your withdrawal details": "save your withdrawal details",
"Something went wrong": "Something went wrong",
"Submission failed": "Submission failed",
"Submit order": "Submit order",
"Submit order - {{status}}": "Submit order - {{status}}",
"Submit stop order": "Submit stop order",
"The amount you're withdrawing has triggered a time delay": "The amount you're withdrawing has triggered a time delay",
"The connection to your Vega Wallet has been lost.": "The connection to your Vega Wallet has been lost.",
"The withdrawal has been approved.": "The withdrawal has been approved.",
"To {{address}}": "To {{address}}",
"To complete this withdrawal, connect the Ethereum wallet {{receiverAddress}}": "To complete this withdrawal, connect the Ethereum wallet {{receiverAddress}}",
"Transaction confirmed": "Transaction confirmed",
"Transfer": "Transfer",
"Transfer complete": "Transfer complete",
"Unknown": "Unknown",
"Vega confirmation": "Vega confirmation",
"Vega is confirming your transaction...": "Vega is confirming your transaction...",
"Verifying withdrawal approval": "Verifying withdrawal approval",
"Verifying...": "Verifying...",
"View in block explorer": "View in block explorer",
"View on Etherscan": "View on Etherscan",
"View transaction on Etherscan": "View transaction on Etherscan",
"Waiting for deposit confirmation.": "Waiting for deposit confirmation.",
"Wallet disconnected": "Wallet disconnected",
"WalletConnect": "WalletConnect",
"WalletConnect Legacy": "WalletConnect Legacy",
"WalletConnect v1": "WalletConnect v1",
"WalletConnect v2": "WalletConnect v2",
"Withdraw": "Withdraw",
"Withdraw {{amount}} {{symbol}}": "Withdraw {{amount}} {{symbol}}",
"Withdraw dependencies not met.": "Withdraw dependencies not met.",
"Withdraw failure": "Withdraw failure",
"Your {{timeInForce}} order was not filled and it has been stopped": "Your {{timeInForce}} order was not filled and it has been stopped",
"Your Ethereum wallet is connected to the wrong network.": "Your Ethereum wallet is connected to the wrong network.",
"Your funds have been unlocked for withdrawal.": "Your funds have been unlocked for withdrawal.",
"Your order has been rejected": "Your order has been rejected",
"Your order has been rejected because: {{rejectionReason}}": "Your order has been rejected because: {{rejectionReason}}",
"Your order has been stopped": "Your order has been stopped",
"Your order has been stopped because: {{rejectionReason}}": "Your order has been stopped because: {{rejectionReason}}",
"Your order was rejected.": "Your order was rejected.",
"Your transaction has been completed.": "Your transaction has been completed.",
"Your transaction has been confirmed": "Your transaction has been confirmed",
"Your transaction has been confirmed.": "Your transaction has been confirmed."
}

View File

@ -1,11 +1,12 @@
import { t } from '@vegaprotocol/i18n';
import { Link } from '@vegaprotocol/ui-toolkit'; import { Link } from '@vegaprotocol/ui-toolkit';
import { EtherscanLink, useEnvironment } from '@vegaprotocol/environment'; import { EtherscanLink, useEnvironment } from '@vegaprotocol/environment';
import { EthTxStatus } from '../use-ethereum-transaction'; import { EthTxStatus } from '../use-ethereum-transaction';
import { useT } from '../use-t';
const ACTIVE_CLASSES = 'text-black dark:text-white'; const ACTIVE_CLASSES = 'text-black dark:text-white';
export const ConfirmRow = ({ status }: { status: EthTxStatus }) => { export const ConfirmRow = ({ status }: { status: EthTxStatus }) => {
const t = useT();
if (status === EthTxStatus.Requested) { if (status === EthTxStatus.Requested) {
return ( return (
<p className="text-black dark:text-white"> <p className="text-black dark:text-white">
@ -32,6 +33,7 @@ export const TxRow = ({
requiredConfirmations, requiredConfirmations,
highlightComplete = true, highlightComplete = true,
}: TxRowProps) => { }: TxRowProps) => {
const t = useT();
const { ETHERSCAN_URL } = useEnvironment(); const { ETHERSCAN_URL } = useEnvironment();
if (status === EthTxStatus.Pending) { if (status === EthTxStatus.Pending) {
@ -39,7 +41,8 @@ export const TxRow = ({
<p className={`flex justify-between ${ACTIVE_CLASSES}`}> <p className={`flex justify-between ${ACTIVE_CLASSES}`}>
<span> <span>
{t( {t(
`Awaiting Ethereum transaction ${confirmations}/${requiredConfirmations} confirmations...` `Awaiting Ethereum transaction {{confirmations}}/{{requiredConfirmations}} confirmations...`,
{ confirmations, requiredConfirmations }
)} )}
</span> </span>
<Link <Link
@ -82,6 +85,7 @@ interface ConfirmationEventRowProps {
} }
export const ConfirmationEventRow = ({ status }: ConfirmationEventRowProps) => { export const ConfirmationEventRow = ({ status }: ConfirmationEventRowProps) => {
const t = useT();
if (status !== EthTxStatus.Complete && status !== EthTxStatus.Confirmed) { if (status !== EthTxStatus.Complete && status !== EthTxStatus.Confirmed) {
return <p>{t('Vega confirmation')}</p>; return <p>{t('Vega confirmation')}</p>;
} }

View File

@ -1,9 +1,9 @@
import { t } from '@vegaprotocol/i18n';
import { Button, Dialog, Icon, Intent, Loader } from '@vegaprotocol/ui-toolkit'; import { Button, Dialog, Icon, Intent, Loader } from '@vegaprotocol/ui-toolkit';
import { isEthereumError } from '../ethereum-error'; import { isEthereumError } from '../ethereum-error';
import type { EthTxState, TxError } from '../use-ethereum-transaction'; import type { EthTxState, TxError } from '../use-ethereum-transaction';
import { EthTxStatus } from '../use-ethereum-transaction'; import { EthTxStatus } from '../use-ethereum-transaction';
import { ConfirmRow, TxRow, ConfirmationEventRow } from './dialog-rows'; import { ConfirmRow, TxRow, ConfirmationEventRow } from './dialog-rows';
import { useT } from '../use-t';
export interface EthereumTransactionDialogProps { export interface EthereumTransactionDialogProps {
title: string; title: string;
@ -20,13 +20,14 @@ export const EthereumTransactionDialog = ({
onChange, onChange,
requiredConfirmations = 1, requiredConfirmations = 1,
}: EthereumTransactionDialogProps) => { }: EthereumTransactionDialogProps) => {
const t = useT();
const { status, error, confirmations, txHash } = transaction; const { status, error, confirmations, txHash } = transaction;
return ( return (
<Dialog <Dialog
open={transaction.dialogOpen} open={transaction.dialogOpen}
onChange={onChange} onChange={onChange}
size="small" size="small"
{...getWrapperProps(title, status)} {...getWrapperProps(title, status, t)}
> >
<TransactionContent <TransactionContent
status={status} status={status}
@ -44,11 +45,13 @@ export const getTransactionContent = ({
transaction, transaction,
requiredConfirmations, requiredConfirmations,
reset, reset,
t,
}: { }: {
title: string; title: string;
transaction: EthTxState; transaction: EthTxState;
requiredConfirmations?: number; requiredConfirmations?: number;
reset: () => void; reset: () => void;
t: ReturnType<typeof useT>;
}) => { }) => {
const { status, error, confirmations, txHash } = transaction; const { status, error, confirmations, txHash } = transaction;
const content = ({ returnLabel }: { returnLabel?: string }) => ( const content = ({ returnLabel }: { returnLabel?: string }) => (
@ -75,7 +78,7 @@ export const getTransactionContent = ({
</> </>
); );
return { return {
...getWrapperProps(title, status), ...getWrapperProps(title, status, t),
status, status,
Content: content, Content: content,
}; };
@ -94,6 +97,7 @@ export const TransactionContent = ({
confirmations: number; confirmations: number;
requiredConfirmations?: number; requiredConfirmations?: number;
}) => { }) => {
const t = useT();
if (status === EthTxStatus.Error) { if (status === EthTxStatus.Error) {
let errorMessage = ''; let errorMessage = '';
@ -105,7 +109,10 @@ export const TransactionContent = ({
return ( return (
<p className="break-all"> <p className="break-all">
{t('Error')}: {errorMessage} {t('Error: {{errorMessage}}', {
nsSeparator: '*',
replace: { errorMessage },
})}
</p> </p>
); );
} }
@ -128,7 +135,8 @@ export const TransactionContent = ({
type WrapperProps = { title: string; icon?: JSX.Element; intent?: Intent }; type WrapperProps = { title: string; icon?: JSX.Element; intent?: Intent };
export const getWrapperProps = ( export const getWrapperProps = (
title: string, title: string,
status: EthTxStatus status: EthTxStatus,
t: ReturnType<typeof useT>
): WrapperProps => { ): WrapperProps => {
const propsMap = { const propsMap = {
[EthTxStatus.Default]: { [EthTxStatus.Default]: {
@ -137,17 +145,17 @@ export const getWrapperProps = (
intent: undefined, intent: undefined,
}, },
[EthTxStatus.Error]: { [EthTxStatus.Error]: {
title: t(`${title} failed`), title: t(`{{title}} failed`, { title }),
icon: <Icon name="warning-sign" />, icon: <Icon name="warning-sign" />,
intent: Intent.Danger, intent: Intent.Danger,
}, },
[EthTxStatus.Requested]: { [EthTxStatus.Requested]: {
title: t('Confirm transaction'), title: t('Confirm transaction', { title }),
icon: <Icon name="hand-up" />, icon: <Icon name="hand-up" />,
intent: Intent.Warning, intent: Intent.Warning,
}, },
[EthTxStatus.Pending]: { [EthTxStatus.Pending]: {
title: t(`${title} pending`), title: t(`{{title}} pending`, { title }),
icon: ( icon: (
<span className="mt-1"> <span className="mt-1">
<Loader size="small" /> <Loader size="small" />
@ -156,12 +164,12 @@ export const getWrapperProps = (
intent: Intent.None, intent: Intent.None,
}, },
[EthTxStatus.Complete]: { [EthTxStatus.Complete]: {
title: t(`${title} pending`), title: t(`{{title}} pending`, { title }),
icon: <Loader size="small" />, icon: <Loader size="small" />,
intent: Intent.None, intent: Intent.None,
}, },
[EthTxStatus.Confirmed]: { [EthTxStatus.Confirmed]: {
title: t(`${title} complete`), title: t(`{{title}} complete`, { title }),
icon: <Icon name="tick" />, icon: <Icon name="tick" />,
intent: Intent.Success, intent: Intent.Success,
}, },

View File

@ -3,7 +3,6 @@ import { useEffect } from 'react';
import { useAssetsDataProvider } from '@vegaprotocol/assets'; import { useAssetsDataProvider } from '@vegaprotocol/assets';
import { EtherscanLink } from '@vegaprotocol/environment'; import { EtherscanLink } from '@vegaprotocol/environment';
import { formatNumber, toBigNum } from '@vegaprotocol/utils'; import { formatNumber, toBigNum } from '@vegaprotocol/utils';
import { t } from '@vegaprotocol/i18n';
import type { Toast, ToastContent } from '@vegaprotocol/ui-toolkit'; import type { Toast, ToastContent } from '@vegaprotocol/ui-toolkit';
import { ToastHeading } from '@vegaprotocol/ui-toolkit'; import { ToastHeading } from '@vegaprotocol/ui-toolkit';
import { Panel } from '@vegaprotocol/ui-toolkit'; import { Panel } from '@vegaprotocol/ui-toolkit';
@ -17,6 +16,7 @@ import { EthTxStatus } from './use-ethereum-transaction';
import { isEthereumError } from './ethereum-error'; import { isEthereumError } from './ethereum-error';
import { TransactionContent } from './ethereum-transaction-dialog'; import { TransactionContent } from './ethereum-transaction-dialog';
import { useEthTransactionStore } from './use-ethereum-transaction-store'; import { useEthTransactionStore } from './use-ethereum-transaction-store';
import { useT } from './use-t';
const intentMap: { [s in EthTxStatus]: Intent } = { const intentMap: { [s in EthTxStatus]: Intent } = {
Default: Intent.Primary, Default: Intent.Primary,
@ -34,6 +34,7 @@ const isDepositTransaction = (tx: EthStoredTxState) =>
tx.methodName === 'deposit_asset'; tx.methodName === 'deposit_asset';
const EthTransactionDetails = ({ tx }: { tx: EthStoredTxState }) => { const EthTransactionDetails = ({ tx }: { tx: EthStoredTxState }) => {
const t = useT();
const { data: assets } = useAssetsDataProvider(); const { data: assets } = useAssetsDataProvider();
if (!assets) return null; if (!assets) return null;
@ -64,8 +65,10 @@ const EthTransactionDetails = ({ tx }: { tx: EthStoredTxState }) => {
{tx.status === EthTxStatus.Pending && ( {tx.status === EthTxStatus.Pending && (
<> <>
<p className="mt-[2px]"> <p className="mt-[2px]">
{t('Awaiting confirmations')}{' '} {t(
{`(${tx.confirmations}/${tx.requiredConfirmations})`} 'Awaiting confirmations {{confirmations}}/{[requiredConfirmations}}',
tx
)}
</p> </p>
<ProgressBar <ProgressBar
value={(tx.confirmations / tx.requiredConfirmations) * 100} value={(tx.confirmations / tx.requiredConfirmations) * 100}
@ -84,6 +87,7 @@ type EthTxToastContentProps = {
}; };
const EthTxRequestedToastContent = ({ tx }: EthTxToastContentProps) => { const EthTxRequestedToastContent = ({ tx }: EthTxToastContentProps) => {
const t = useT();
return ( return (
<> <>
<ToastHeading>{t('Action required')}</ToastHeading> <ToastHeading>{t('Action required')}</ToastHeading>
@ -98,6 +102,7 @@ const EthTxRequestedToastContent = ({ tx }: EthTxToastContentProps) => {
}; };
const EthTxPendingToastContent = ({ tx }: EthTxToastContentProps) => { const EthTxPendingToastContent = ({ tx }: EthTxToastContentProps) => {
const t = useT();
return ( return (
<> <>
<ToastHeading>{t('Awaiting confirmation')}</ToastHeading> <ToastHeading>{t('Awaiting confirmation')}</ToastHeading>
@ -111,6 +116,7 @@ const EthTxPendingToastContent = ({ tx }: EthTxToastContentProps) => {
}; };
const EthTxErrorToastContent = ({ tx }: EthTxToastContentProps) => { const EthTxErrorToastContent = ({ tx }: EthTxToastContentProps) => {
const t = useT();
let errorMessage = ''; let errorMessage = '';
if (isEthereumError(tx.error)) { if (isEthereumError(tx.error)) {
@ -128,6 +134,7 @@ const EthTxErrorToastContent = ({ tx }: EthTxToastContentProps) => {
}; };
const EthTxConfirmedToastContent = ({ tx }: EthTxToastContentProps) => { const EthTxConfirmedToastContent = ({ tx }: EthTxToastContentProps) => {
const t = useT();
return ( return (
<> <>
<ToastHeading>{t('Transaction confirmed')}</ToastHeading> <ToastHeading>{t('Transaction confirmed')}</ToastHeading>
@ -141,11 +148,12 @@ const EthTxConfirmedToastContent = ({ tx }: EthTxToastContentProps) => {
}; };
const EthTxCompletedToastContent = ({ tx }: EthTxToastContentProps) => { const EthTxCompletedToastContent = ({ tx }: EthTxToastContentProps) => {
const t = useT();
const isDeposit = isDepositTransaction(tx); const isDeposit = isDepositTransaction(tx);
return ( return (
<> <>
<ToastHeading> <ToastHeading>
{t('Processing')} {isDeposit && t('deposit')} {isDeposit ? t('Processing deposit') : t('Processing')}
</ToastHeading> </ToastHeading>
<p> <p>
{t('Your transaction has been completed.')}{' '} {t('Your transaction has been completed.')}{' '}

View File

@ -8,6 +8,7 @@ import {
EthereumTransactionDialog, EthereumTransactionDialog,
getTransactionContent, getTransactionContent,
} from './ethereum-transaction-dialog'; } from './ethereum-transaction-dialog';
import { useT } from './use-t';
export enum EthTxStatus { export enum EthTxStatus {
Default = 'Default', Default = 'Default',
@ -51,6 +52,7 @@ export const useEthereumTransaction = <
requiredConfirmations = 1, requiredConfirmations = 1,
requiresConfirmation = false requiresConfirmation = false
) => { ) => {
const t = useT();
const [transaction, _setTransaction] = useState<EthTxState>(initialState); const [transaction, _setTransaction] = useState<EthTxState>(initialState);
const setTransaction = useCallback((update: Partial<EthTxState>) => { const setTransaction = useCallback((update: Partial<EthTxState>) => {
@ -173,8 +175,9 @@ export const useEthereumTransaction = <
transaction, transaction,
requiredConfirmations, requiredConfirmations,
reset, reset,
t,
}), }),
[methodName, requiredConfirmations, reset, transaction] [methodName, requiredConfirmations, reset, transaction, t]
); );
return { perform, transaction, reset, setConfirmed, Dialog, TxContent }; return { perform, transaction, reset, setConfirmed, Dialog, TxContent };

View File

@ -1,5 +1,4 @@
import { formatNumber, toBigNum } from '@vegaprotocol/utils'; import { formatNumber, toBigNum } from '@vegaprotocol/utils';
import { t } from '@vegaprotocol/i18n';
import type { Toast } from '@vegaprotocol/ui-toolkit'; import type { Toast } from '@vegaprotocol/ui-toolkit';
import { ToastHeading } from '@vegaprotocol/ui-toolkit'; import { ToastHeading } from '@vegaprotocol/ui-toolkit';
import { Panel } from '@vegaprotocol/ui-toolkit'; import { Panel } from '@vegaprotocol/ui-toolkit';
@ -15,6 +14,7 @@ import {
} from './use-ethereum-withdraw-approvals-store'; } from './use-ethereum-withdraw-approvals-store';
import { ApprovalStatus } from './use-ethereum-withdraw-approvals-store'; import { ApprovalStatus } from './use-ethereum-withdraw-approvals-store';
import { VerificationStatus } from './withdrawal-approval-status'; import { VerificationStatus } from './withdrawal-approval-status';
import { useT } from './use-t';
const intentMap: { [s in ApprovalStatus]: Intent } = { const intentMap: { [s in ApprovalStatus]: Intent } = {
Pending: Intent.Warning, Pending: Intent.Warning,
@ -29,6 +29,7 @@ const EthWithdrawalApprovalToastContent = ({
}: { }: {
tx: EthWithdrawalApprovalState; tx: EthWithdrawalApprovalState;
}) => { }) => {
const t = useT();
const isConnectionFailure = const isConnectionFailure =
tx.failureReason && tx.failureReason &&
[ [
@ -54,14 +55,17 @@ const EthWithdrawalApprovalToastContent = ({
title = t('Approved'); title = t('Approved');
} }
const num = formatNumber( const amount = formatNumber(
toBigNum(tx.withdrawal.amount, tx.withdrawal.asset.decimals), toBigNum(tx.withdrawal.amount, tx.withdrawal.asset.decimals),
tx.withdrawal.asset.decimals tx.withdrawal.asset.decimals
); );
const details = isConnectionFailure ? null : ( const details = isConnectionFailure ? null : (
<Panel> <Panel>
<strong> <strong>
{t('Withdraw')} {num} {tx.withdrawal.asset.symbol} {t('Withdraw {{amount}} {{symbol}}', {
amount,
symbol: tx.withdrawal.asset.symbol,
})}
</strong> </strong>
</Panel> </Panel>
); );

View File

@ -4,7 +4,6 @@ import { useEffect, useRef } from 'react';
import { addDecimal } from '@vegaprotocol/utils'; import { addDecimal } from '@vegaprotocol/utils';
import { useGetWithdrawThreshold } from './use-get-withdraw-threshold'; import { useGetWithdrawThreshold } from './use-get-withdraw-threshold';
import { useGetWithdrawDelay } from './use-get-withdraw-delay'; import { useGetWithdrawDelay } from './use-get-withdraw-delay';
import { t } from '@vegaprotocol/i18n';
import { localLoggerFactory } from '@vegaprotocol/logger'; import { localLoggerFactory } from '@vegaprotocol/logger';
import { CollateralBridge } from '@vegaprotocol/smart-contracts'; import { CollateralBridge } from '@vegaprotocol/smart-contracts';
@ -21,8 +20,10 @@ import {
useEthWithdrawApprovalsStore, useEthWithdrawApprovalsStore,
WithdrawalFailure, WithdrawalFailure,
} from './use-ethereum-withdraw-approvals-store'; } from './use-ethereum-withdraw-approvals-store';
import { useT } from './use-t';
export const useEthWithdrawApprovalsManager = () => { export const useEthWithdrawApprovalsManager = () => {
const t = useT();
const getThreshold = useGetWithdrawThreshold(); const getThreshold = useGetWithdrawThreshold();
const getDelay = useGetWithdrawDelay(); const getDelay = useGetWithdrawDelay();
const { query } = useApolloClient(); const { query } = useApolloClient();
@ -49,9 +50,12 @@ export const useEthWithdrawApprovalsManager = () => {
if (withdrawal.asset.source.__typename !== 'ERC20') { if (withdrawal.asset.source.__typename !== 'ERC20') {
update(transaction.id, { update(transaction.id, {
status: ApprovalStatus.Error, status: ApprovalStatus.Error,
message: t( message: t(`Invalid asset source: {{source}}`, {
`Invalid asset source: ${withdrawal.asset.source.__typename}` nsSeparator: '*',
), replace: {
source: withdrawal.asset.source.__typename,
},
}),
failureReason: WithdrawalFailure.InvalidAsset, failureReason: WithdrawalFailure.InvalidAsset,
}); });
return; return;
@ -162,5 +166,6 @@ export const useEthWithdrawApprovalsManager = () => {
transaction, transaction,
update, update,
chainId, chainId,
t,
]); ]);
}; };

View File

@ -0,0 +1,3 @@
import { useTranslation } from 'react-i18next';
export const ns = 'web3';
export const useT = () => useTranslation(ns).t;

View File

@ -418,32 +418,33 @@ describe('getVegaTransactionContentIntent', () => {
}); });
}); });
describe('getOrderToastTitle', () => { describe('getOrderToastTitle', () => {
const t = (v: string) => v;
it('should return the correct title', () => { it('should return the correct title', () => {
expect(getOrderToastTitle(Types.OrderStatus.STATUS_ACTIVE)).toBe( expect(getOrderToastTitle(Types.OrderStatus.STATUS_ACTIVE, t)).toBe(
'Order submitted' 'Order submitted'
); );
expect(getOrderToastTitle(Types.OrderStatus.STATUS_FILLED)).toBe( expect(getOrderToastTitle(Types.OrderStatus.STATUS_FILLED, t)).toBe(
'Order filled' 'Order filled'
); );
expect(getOrderToastTitle(Types.OrderStatus.STATUS_PARTIALLY_FILLED)).toBe( expect(
'Order partially filled' getOrderToastTitle(Types.OrderStatus.STATUS_PARTIALLY_FILLED, t)
); ).toBe('Order partially filled');
expect(getOrderToastTitle(Types.OrderStatus.STATUS_PARKED)).toBe( expect(getOrderToastTitle(Types.OrderStatus.STATUS_PARKED, t)).toBe(
'Order parked' 'Order parked'
); );
expect(getOrderToastTitle(Types.OrderStatus.STATUS_STOPPED)).toBe( expect(getOrderToastTitle(Types.OrderStatus.STATUS_STOPPED, t)).toBe(
'Order stopped' 'Order stopped'
); );
expect(getOrderToastTitle(Types.OrderStatus.STATUS_CANCELLED)).toBe( expect(getOrderToastTitle(Types.OrderStatus.STATUS_CANCELLED, t)).toBe(
'Order cancelled' 'Order cancelled'
); );
expect(getOrderToastTitle(Types.OrderStatus.STATUS_EXPIRED)).toBe( expect(getOrderToastTitle(Types.OrderStatus.STATUS_EXPIRED, t)).toBe(
'Order expired' 'Order expired'
); );
expect(getOrderToastTitle(Types.OrderStatus.STATUS_REJECTED)).toBe( expect(getOrderToastTitle(Types.OrderStatus.STATUS_REJECTED, t)).toBe(
'Order rejected' 'Order rejected'
); );
expect(getOrderToastTitle(undefined)).toBe(undefined); expect(getOrderToastTitle(undefined, t)).toBe(undefined);
}); });
}); });
@ -480,7 +481,8 @@ describe('getOrderToastIntent', () => {
describe('getRejectionReason', () => { describe('getRejectionReason', () => {
it('should return the correct rejection reason for insufficient asset balance', () => { it('should return the correct rejection reason for insufficient asset balance', () => {
expect( expect(
getRejectionReason({ getRejectionReason(
{
rejectionReason: rejectionReason:
Types.OrderRejectionReason.ORDER_ERROR_INSUFFICIENT_ASSET_BALANCE, Types.OrderRejectionReason.ORDER_ERROR_INSUFFICIENT_ASSET_BALANCE,
status: Types.OrderStatus.STATUS_REJECTED, status: Types.OrderStatus.STATUS_REJECTED,
@ -492,13 +494,16 @@ describe('getRejectionReason', () => {
side: Types.Side.SIDE_BUY, side: Types.Side.SIDE_BUY,
marketId: '', marketId: '',
remaining: '', remaining: '',
}) },
(v) => v
)
).toBe('Insufficient asset balance'); ).toBe('Insufficient asset balance');
}); });
it('should return the correct rejection reason when order is stopped', () => { it('should return the correct rejection reason when order is stopped', () => {
expect( expect(
getRejectionReason({ getRejectionReason(
{
rejectionReason: null, rejectionReason: null,
status: Types.OrderStatus.STATUS_STOPPED, status: Types.OrderStatus.STATUS_STOPPED,
id: '', id: '',
@ -509,9 +514,9 @@ describe('getRejectionReason', () => {
side: Types.Side.SIDE_BUY, side: Types.Side.SIDE_BUY,
marketId: '', marketId: '',
remaining: '', remaining: '',
}) },
).toBe( (v) => v
'Your Fill or Kill (FOK) order was not filled and it has been stopped' )
); ).toBe('Your {{timeInForce}} order was not filled and it has been stopped');
}); });
}); });

View File

@ -43,7 +43,6 @@ import {
formatTrigger, formatTrigger,
MAXGOINT64, MAXGOINT64,
} from '@vegaprotocol/utils'; } from '@vegaprotocol/utils';
import { t } from '@vegaprotocol/i18n';
import { useAssetsMapProvider } from '@vegaprotocol/assets'; import { useAssetsMapProvider } from '@vegaprotocol/assets';
import { useEthWithdrawApprovalsStore } from './use-ethereum-withdraw-approvals-store'; import { useEthWithdrawApprovalsStore } from './use-ethereum-withdraw-approvals-store';
import { DApp, EXPLORER_TX, useLinks } from '@vegaprotocol/environment'; import { DApp, EXPLORER_TX, useLinks } from '@vegaprotocol/environment';
@ -58,26 +57,31 @@ import { OrderStatusMapping } from '@vegaprotocol/types';
import { Size } from '@vegaprotocol/datagrid'; import { Size } from '@vegaprotocol/datagrid';
import { useWithdrawalApprovalDialog } from './withdrawal-approval-dialog'; import { useWithdrawalApprovalDialog } from './withdrawal-approval-dialog';
import * as Schema from '@vegaprotocol/types'; import * as Schema from '@vegaprotocol/types';
import { Trans } from 'react-i18next';
import { useT } from './use-t';
export const getRejectionReason = ( export const getRejectionReason = (
order: OrderTxUpdateFieldsFragment order: OrderTxUpdateFieldsFragment,
t: ReturnType<typeof useT>
): string | null => { ): string | null => {
switch (order.status) { switch (order.status) {
case Schema.OrderStatus.STATUS_STOPPED: case Schema.OrderStatus.STATUS_STOPPED:
return t( return t(
`Your ${ `Your {{timeInForce}} order was not filled and it has been stopped`,
Schema.OrderTimeInForceMapping[order.timeInForce] {
} order was not filled and it has been stopped` timeInForce: Schema.OrderTimeInForceMapping[order.timeInForce],
}
); );
default: default:
return order.rejectionReason return order.rejectionReason
? t(Schema.OrderRejectionReasonMapping[order.rejectionReason]) ? Schema.OrderRejectionReasonMapping[order.rejectionReason]
: ''; : '';
} }
}; };
export const getOrderToastTitle = ( export const getOrderToastTitle = (
status?: Schema.OrderStatus status: Schema.OrderStatus | undefined,
t: ReturnType<typeof useT>
): string | undefined => { ): string | undefined => {
if (!status) { if (!status) {
return; return;
@ -212,6 +216,7 @@ const SubmitOrderDetails = ({
data: OrderSubmission; data: OrderSubmission;
order?: OrderTxUpdateFieldsFragment; order?: OrderTxUpdateFieldsFragment;
}) => { }) => {
const t = useT();
const { data: markets } = useMarketsMapProvider(); const { data: markets } = useMarketsMapProvider();
const market = markets?.[order?.marketId || '']; const market = markets?.[order?.marketId || ''];
if (!market) return null; if (!market) return null;
@ -224,9 +229,9 @@ const SubmitOrderDetails = ({
<Panel> <Panel>
<h4> <h4>
{order {order
? t( ? t(`Submit order - {{status}}`, {
`Submit order - ${OrderStatusMapping[order.status].toLowerCase()}` status: OrderStatusMapping[order.status].toLowerCase(),
) })
: t('Submit order')} : t('Submit order')}
</h4> </h4>
<p>{market?.tradableInstrument.instrument.code}</p> <p>{market?.tradableInstrument.instrument.code}</p>
@ -294,6 +299,7 @@ const SubmitStopOrderSetup = ({
}; };
const SubmitStopOrderDetails = ({ data }: { data: StopOrdersSubmission }) => { const SubmitStopOrderDetails = ({ data }: { data: StopOrdersSubmission }) => {
const t = useT();
const { data: markets } = useMarketsMapProvider(); const { data: markets } = useMarketsMapProvider();
const marketId = const marketId =
data.fallsBelow?.orderSubmission.marketId || data.fallsBelow?.orderSubmission.marketId ||
@ -335,6 +341,7 @@ const EditOrderDetails = ({
data: OrderAmendment; data: OrderAmendment;
order?: OrderTxUpdateFieldsFragment; order?: OrderTxUpdateFieldsFragment;
}) => { }) => {
const t = useT();
const { data: orderById } = useOrderByIdQuery({ const { data: orderById } = useOrderByIdQuery({
variables: { orderId: data.orderId }, variables: { orderId: data.orderId },
fetchPolicy: 'no-cache', fetchPolicy: 'no-cache',
@ -376,7 +383,9 @@ const EditOrderDetails = ({
<Panel title={data.orderId}> <Panel title={data.orderId}>
<h4> <h4>
{order {order
? t(`Edit order - ${OrderStatusMapping[order.status].toLowerCase()}`) ? t(`Edit order - {{status}}`, {
status: OrderStatusMapping[order.status].toLowerCase(),
})
: t('Edit order')} : t('Edit order')}
</h4> </h4>
<p>{market?.tradableInstrument.instrument.code}</p> <p>{market?.tradableInstrument.instrument.code}</p>
@ -395,6 +404,7 @@ const CancelOrderDetails = ({
orderId: string; orderId: string;
order?: OrderTxUpdateFieldsFragment; order?: OrderTxUpdateFieldsFragment;
}) => { }) => {
const t = useT();
const { data: orderById } = useOrderByIdQuery({ const { data: orderById } = useOrderByIdQuery({
variables: { orderId }, variables: { orderId },
}); });
@ -421,9 +431,9 @@ const CancelOrderDetails = ({
<Panel title={orderId}> <Panel title={orderId}>
<h4> <h4>
{order {order
? t( ? t(`Cancel order - {{status}}`, {
`Cancel order - ${OrderStatusMapping[order.status].toLowerCase()}` status: OrderStatusMapping[order.status].toLowerCase(),
) })
: t('Cancel order')} : t('Cancel order')}
</h4> </h4>
<p>{market?.tradableInstrument.instrument.code}</p> <p>{market?.tradableInstrument.instrument.code}</p>
@ -435,6 +445,7 @@ const CancelOrderDetails = ({
}; };
const CancelStopOrderDetails = ({ stopOrderId }: { stopOrderId: string }) => { const CancelStopOrderDetails = ({ stopOrderId }: { stopOrderId: string }) => {
const t = useT();
const { data: orderById } = useStopOrderByIdQuery({ const { data: orderById } = useStopOrderByIdQuery({
variables: { stopOrderId }, variables: { stopOrderId },
}); });
@ -473,6 +484,7 @@ const CancelStopOrderDetails = ({ stopOrderId }: { stopOrderId: string }) => {
}; };
export const VegaTransactionDetails = ({ tx }: { tx: VegaStoredTxState }) => { export const VegaTransactionDetails = ({ tx }: { tx: VegaStoredTxState }) => {
const t = useT();
const { data: assets } = useAssetsMapProvider(); const { data: assets } = useAssetsMapProvider();
const { data: markets } = useMarketsMapProvider(); const { data: markets } = useMarketsMapProvider();
@ -480,14 +492,17 @@ export const VegaTransactionDetails = ({ tx }: { tx: VegaStoredTxState }) => {
const transactionDetails = tx.body; const transactionDetails = tx.body;
const asset = assets?.[transactionDetails.withdrawSubmission.asset]; const asset = assets?.[transactionDetails.withdrawSubmission.asset];
if (asset) { if (asset) {
const num = formatNumber( const amount = formatNumber(
toBigNum(transactionDetails.withdrawSubmission.amount, asset.decimals), toBigNum(transactionDetails.withdrawSubmission.amount, asset.decimals),
asset.decimals asset.decimals
); );
return ( return (
<Panel> <Panel>
<strong> <strong>
{t('Withdraw')} {num} {asset.symbol} {t('Withdraw {{amount}} {{symbol}}', {
amount,
symbol: asset.symbol,
})}
</strong> </strong>
</Panel> </Panel>
); );
@ -526,7 +541,10 @@ export const VegaTransactionDetails = ({ tx }: { tx: VegaStoredTxState }) => {
if (marketName) { if (marketName) {
return ( return (
<Panel> <Panel>
{t('Cancel all orders for')} <strong>{marketName}</strong> <Trans
defaults="Cancel all orders for <strong>{{marketName}}</strong>"
values={{ marketName }}
/>
</Panel> </Panel>
); );
} }
@ -556,7 +574,10 @@ export const VegaTransactionDetails = ({ tx }: { tx: VegaStoredTxState }) => {
if (marketName) { if (marketName) {
return ( return (
<Panel> <Panel>
{t('Cancel all stop orders for')} <strong>{marketName}</strong> <Trans
defaults="Cancel all stop orders for <strong>{{marketName}}</strong>"
values={{ marketName }}
/>
</Panel> </Panel>
); );
} }
@ -584,8 +605,12 @@ export const VegaTransactionDetails = ({ tx }: { tx: VegaStoredTxState }) => {
if (market) { if (market) {
return ( return (
<Panel> <Panel>
{t('Close position for')}{' '} <Trans
<strong>{market.tradableInstrument.instrument.code}</strong> defaults="Close position for <strong>{{instrumentCode}}</strong>"
values={{
instrumentCode: market.tradableInstrument.instrument.code,
}}
/>
{tx.order?.remaining && ( {tx.order?.remaining && (
<p> <p>
{t('Filled')}{' '} {t('Filled')}{' '}
@ -621,9 +646,7 @@ export const VegaTransactionDetails = ({ tx }: { tx: VegaStoredTxState }) => {
return ( return (
<Panel> <Panel>
<h4>{t('Transfer')}</h4> <h4>{t('Transfer')}</h4>
<p> <p>{t('To {{address}}', { address: truncateByChars(to) })}</p>
{t('To')} {truncateByChars(to)}
</p>
<p> <p>
{value} {transferAsset.symbol} {value} {transferAsset.symbol}
</p> </p>
@ -637,7 +660,9 @@ export const VegaTransactionDetails = ({ tx }: { tx: VegaStoredTxState }) => {
type VegaTxToastContentProps = { tx: VegaStoredTxState }; type VegaTxToastContentProps = { tx: VegaStoredTxState };
const VegaTxRequestedToastContent = ({ tx }: VegaTxToastContentProps) => ( const VegaTxRequestedToastContent = ({ tx }: VegaTxToastContentProps) => {
const t = useT();
return (
<> <>
<ToastHeading>{t('Action required')}</ToastHeading> <ToastHeading>{t('Action required')}</ToastHeading>
<p> <p>
@ -647,9 +672,13 @@ const VegaTxRequestedToastContent = ({ tx }: VegaTxToastContentProps) => (
</p> </p>
<VegaTransactionDetails tx={tx} /> <VegaTransactionDetails tx={tx} />
</> </>
); );
};
const VegaTxPendingToastContentProps = ({ tx }: VegaTxToastContentProps) => { const VegaTxPendingToastContentProps = (
{ tx }: VegaTxToastContentProps,
t: ReturnType<typeof useT>
) => {
const explorerLink = useLinks(DApp.Explorer); const explorerLink = useLinks(DApp.Explorer);
return ( return (
<> <>
@ -671,6 +700,7 @@ const VegaTxPendingToastContentProps = ({ tx }: VegaTxToastContentProps) => {
}; };
const VegaTxCompleteToastsContent = ({ tx }: VegaTxToastContentProps) => { const VegaTxCompleteToastsContent = ({ tx }: VegaTxToastContentProps) => {
const t = useT();
const { createEthWithdrawalApproval } = useEthWithdrawApprovalsStore( const { createEthWithdrawalApproval } = useEthWithdrawApprovalsStore(
(state) => ({ (state) => ({
createEthWithdrawalApproval: state.create, createEthWithdrawalApproval: state.create,
@ -696,24 +726,6 @@ const VegaTxCompleteToastsContent = ({ tx }: VegaTxToastContentProps) => {
</p> </p>
); );
const dialogTrigger = (
// It has to stay as <a> due to the word breaking issue
// eslint-disable-next-line jsx-a11y/anchor-is-valid
<a
href="#"
className="inline underline underline-offset-4 cursor-pointer text-inherit break-words"
data-testid="toast-withdrawal-details"
onClick={(e) => {
e.preventDefault();
if (tx.withdrawal?.id) {
useWithdrawalApprovalDialog.getState().open(tx.withdrawal?.id);
}
}}
>
{t('save your withdrawal details')}
</a>
);
return ( return (
<> <>
<ToastHeading>{t('Funds unlocked')}</ToastHeading> <ToastHeading>{t('Funds unlocked')}</ToastHeading>
@ -729,7 +741,28 @@ const VegaTxCompleteToastsContent = ({ tx }: VegaTxToastContentProps) => {
)} )}
{/* TODO: Delay message - This withdrawal is subject to a delay. Come back in 5 days to complete the withdrawal. */} {/* TODO: Delay message - This withdrawal is subject to a delay. Come back in 5 days to complete the withdrawal. */}
<p className="break-words"> <p className="break-words">
{t('You can')} {dialogTrigger} {t('for extra security.')} <Trans
defaults="You can <0>save your withdrawal details</0> for extra security."
components={[
// It has to stay as <a> due to the word breaking issue
// eslint-disable-next-line jsx-a11y/anchor-is-valid
<a
href="#"
className="inline underline underline-offset-4 cursor-pointer text-inherit break-words"
data-testid="toast-withdrawal-details"
onClick={(e) => {
e.preventDefault();
if (tx.withdrawal?.id) {
useWithdrawalApprovalDialog
.getState()
.open(tx.withdrawal?.id);
}
}}
>
save your withdrawal details
</a>,
]}
/>
</p> </p>
<VegaTransactionDetails tx={tx} /> <VegaTransactionDetails tx={tx} />
{completeWithdrawalButton} {completeWithdrawalButton}
@ -738,26 +771,31 @@ const VegaTxCompleteToastsContent = ({ tx }: VegaTxToastContentProps) => {
} }
if (tx.order && tx.order.rejectionReason) { if (tx.order && tx.order.rejectionReason) {
const rejectionReason = getRejectionReason(tx.order); const rejectionReason = getRejectionReason(tx.order, t);
return ( return (
<> <>
<ToastHeading>{getOrderToastTitle(tx.order.status)}</ToastHeading> <ToastHeading>{getOrderToastTitle(tx.order.status, t)}</ToastHeading>
{rejectionReason ? ( {rejectionReason ? (
<p> <p>
{t('Your order has been %s because: %s', [ {tx.order.status === Schema.OrderStatus.STATUS_STOPPED
tx.order.status === Schema.OrderStatus.STATUS_STOPPED ? t('Your order has been stopped because: {{rejectionReason}}', {
? 'stopped' nsSeparator: '*',
: 'rejected', replace: {
rejectionReason, rejectionReason,
])} },
})
: t('Your order has been rejected because: {{rejectionReason}}', {
nsSeparator: '*',
replace: {
rejectionReason,
},
})}
</p> </p>
) : ( ) : (
<p> <p>
{t('Your order has been %s.', [ {tx.order.status === Schema.OrderStatus.STATUS_STOPPED
tx.order.status === Schema.OrderStatus.STATUS_STOPPED ? t('Your order has been stopped')
? 'stopped' : t('Your order has been rejected')}
: 'rejected',
])}
</p> </p>
)} )}
{tx.txHash && ( {tx.txHash && (
@ -778,7 +816,7 @@ const VegaTxCompleteToastsContent = ({ tx }: VegaTxToastContentProps) => {
if (isOrderSubmissionTransaction(tx.body) && tx.order?.rejectionReason) { if (isOrderSubmissionTransaction(tx.body) && tx.order?.rejectionReason) {
return ( return (
<div> <div>
<h3 className="font-bold">{getOrderToastTitle(tx.order.status)}</h3> <h3 className="font-bold">{getOrderToastTitle(tx.order.status, t)}</h3>
<p>{t('Your order was rejected.')}</p> <p>{t('Your order was rejected.')}</p>
{tx.txHash && ( {tx.txHash && (
<p className="break-all"> <p className="break-all">
@ -799,7 +837,7 @@ const VegaTxCompleteToastsContent = ({ tx }: VegaTxToastContentProps) => {
return ( return (
<div> <div>
<h3 className="font-bold">{t('Transfer complete')}</h3> <h3 className="font-bold">{t('Transfer complete')}</h3>
<p>{t('Your transaction has been confirmed ')}</p> <p>{t('Your transaction has been confirmed')}</p>
{tx.txHash && ( {tx.txHash && (
<p className="break-all"> <p className="break-all">
<ExternalLink <ExternalLink
@ -819,10 +857,10 @@ const VegaTxCompleteToastsContent = ({ tx }: VegaTxToastContentProps) => {
<> <>
<ToastHeading> <ToastHeading>
{tx.order?.status {tx.order?.status
? getOrderToastTitle(tx.order.status) ? getOrderToastTitle(tx.order.status, t)
: t('Confirmed')} : t('Confirmed')}
</ToastHeading> </ToastHeading>
<p>{t('Your transaction has been confirmed ')}</p> <p>{t('Your transaction has been confirmed')}</p>
{tx.txHash && ( {tx.txHash && (
<p className="break-all"> <p className="break-all">
<ExternalLink <ExternalLink
@ -839,6 +877,7 @@ const VegaTxCompleteToastsContent = ({ tx }: VegaTxToastContentProps) => {
}; };
const VegaTxErrorToastContent = ({ tx }: VegaTxToastContentProps) => { const VegaTxErrorToastContent = ({ tx }: VegaTxToastContentProps) => {
const t = useT();
let label = t('Error occurred'); let label = t('Error occurred');
let errorMessage = let errorMessage =
tx.error instanceof WalletError tx.error instanceof WalletError
@ -847,7 +886,7 @@ const VegaTxErrorToastContent = ({ tx }: VegaTxToastContentProps) => {
const reconnectVegaWallet = useReconnectVegaWallet(); const reconnectVegaWallet = useReconnectVegaWallet();
const orderRejection = tx.order && getRejectionReason(tx.order); const orderRejection = tx.order && getRejectionReason(tx.order, t);
const walletNoConnectionCodes = [ const walletNoConnectionCodes = [
ClientErrors.NO_SERVICE.code, ClientErrors.NO_SERVICE.code,
ClientErrors.NO_CLIENT.code, ClientErrors.NO_CLIENT.code,
@ -857,10 +896,13 @@ const VegaTxErrorToastContent = ({ tx }: VegaTxToastContentProps) => {
walletNoConnectionCodes.includes(tx.error.code); walletNoConnectionCodes.includes(tx.error.code);
if (orderRejection) { if (orderRejection) {
label = getOrderToastTitle(tx.order?.status) || t('Order rejected'); label = getOrderToastTitle(tx.order?.status, t) || t('Order rejected');
errorMessage = t('Your order has been rejected because: %s', [ errorMessage = t(
orderRejection || tx.order?.rejectionReason || ' ', 'Your order has been rejected because: {{rejectionReason}}',
]); {
rejectionReason: orderRejection || tx.order?.rejectionReason || ' ',
}
);
} }
if (walletError) { if (walletError) {
label = t('Wallet disconnected'); label = t('Wallet disconnected');

View File

@ -1,4 +1,3 @@
import { t } from '@vegaprotocol/i18n';
import { useLocalStorage } from '@vegaprotocol/react-helpers'; import { useLocalStorage } from '@vegaprotocol/react-helpers';
import { import {
Dialog, Dialog,
@ -16,6 +15,7 @@ import type { Web3ReactHooks } from '@web3-react/core';
import { useWeb3ConnectStore } from './web3-connect-store'; import { useWeb3ConnectStore } from './web3-connect-store';
import { theme } from '@vegaprotocol/tailwindcss-config'; import { theme } from '@vegaprotocol/tailwindcss-config';
import classNames from 'classnames'; import classNames from 'classnames';
import { useT } from './use-t';
interface Web3ConnectDialogProps { interface Web3ConnectDialogProps {
dialogOpen: boolean; dialogOpen: boolean;
@ -29,7 +29,9 @@ export const Web3ConnectDialog = ({
setDialogOpen, setDialogOpen,
connectors, connectors,
desiredChainId, desiredChainId,
}: Web3ConnectDialogProps) => ( }: Web3ConnectDialogProps) => {
const t = useT();
return (
<Dialog <Dialog
open={dialogOpen} open={dialogOpen}
onChange={setDialogOpen} onChange={setDialogOpen}
@ -55,7 +57,8 @@ export const Web3ConnectDialog = ({
))} ))}
</ul> </ul>
</Dialog> </Dialog>
); );
};
const ConnectButton = ({ const ConnectButton = ({
connector, connector,
@ -66,9 +69,10 @@ const ConnectButton = ({
desiredChainId?: number; desiredChainId?: number;
onClick?: () => void; onClick?: () => void;
}) => { }) => {
const t = useT();
const [connectorInstance, { useIsActivating }] = connector; const [connectorInstance, { useIsActivating }] = connector;
const isActivating = useIsActivating(); const isActivating = useIsActivating();
const info = getConnectorInfo(connectorInstance); const info = getConnectorInfo(connectorInstance, t);
const [, setEagerConnector] = useLocalStorage(ETHEREUM_EAGER_CONNECT); const [, setEagerConnector] = useLocalStorage(ETHEREUM_EAGER_CONNECT);
return ( return (
<button <button
@ -120,7 +124,7 @@ export const Web3ConnectUncontrolledDialog = () => {
); );
}; };
function getConnectorInfo(connector: Connector) { function getConnectorInfo(connector: Connector, t: ReturnType<typeof useT>) {
if (connector instanceof MetaMask) { if (connector instanceof MetaMask) {
return { return {
icon: <VegaIcon name={VegaIconNames.METAMASK} size={32} />, icon: <VegaIcon name={VegaIconNames.METAMASK} size={32} />,

View File

@ -1,4 +1,3 @@
import { t } from '@vegaprotocol/i18n';
import { import {
Button, Button,
CopyWithTooltip, CopyWithTooltip,
@ -13,6 +12,7 @@ import {
import { useWithdrawalApprovalQuery } from './__generated__/WithdrawalApproval'; import { useWithdrawalApprovalQuery } from './__generated__/WithdrawalApproval';
import omit from 'lodash/omit'; import omit from 'lodash/omit';
import { create } from 'zustand'; import { create } from 'zustand';
import { useT } from './use-t';
type WithdrawalApprovalDialogProps = { type WithdrawalApprovalDialogProps = {
withdrawalId: string | undefined; withdrawalId: string | undefined;
@ -28,6 +28,7 @@ export const WithdrawalApprovalDialog = ({
onChange, onChange,
asJson, asJson,
}: WithdrawalApprovalDialogProps) => { }: WithdrawalApprovalDialogProps) => {
const t = useT();
return ( return (
<Dialog <Dialog
title={t('Save withdrawal details')} title={t('Save withdrawal details')}
@ -48,8 +49,7 @@ export const WithdrawalApprovalDialog = ({
<div className="pr-8"> <div className="pr-8">
<p> <p>
{t( {t(
`If the network is reset or has an outage, records of your withdrawal `If the network is reset or has an outage, records of your withdrawal may be lost. It is recommended that you save these details in a safe place so you can still complete your withdrawal.`
may be lost. It is recommended that you save these details in a safe place so you can still complete your withdrawal.`
)} )}
</p> </p>
{withdrawalId ? ( {withdrawalId ? (
@ -80,16 +80,20 @@ type WithdrawalApprovalDialogContentProps = {
asJson: boolean; asJson: boolean;
}; };
const NoDataContent = ({ msg = t('No data') }) => ( const NoDataContent = ({ msg }: { msg?: string }) => {
const t = useT();
return (
<div className="py-12" data-testid="splash"> <div className="py-12" data-testid="splash">
<Splash>{msg}</Splash> <Splash>{msg || t('No data')}</Splash>
</div> </div>
); );
};
const WithdrawalApprovalDialogContent = ({ const WithdrawalApprovalDialogContent = ({
withdrawalId, withdrawalId,
asJson, asJson,
}: WithdrawalApprovalDialogContentProps) => { }: WithdrawalApprovalDialogContentProps) => {
const t = useT();
const { data, loading } = useWithdrawalApprovalQuery({ const { data, loading } = useWithdrawalApprovalQuery({
variables: { variables: {
withdrawalId, withdrawalId,

View File

@ -1,4 +1,3 @@
import { t } from '@vegaprotocol/i18n';
import { import {
getDateTimeFormat, getDateTimeFormat,
resolveNetworkName, resolveNetworkName,
@ -13,12 +12,14 @@ import {
import { useEthereumConfig } from './use-ethereum-config'; import { useEthereumConfig } from './use-ethereum-config';
import { Button, useToasts } from '@vegaprotocol/ui-toolkit'; import { Button, useToasts } from '@vegaprotocol/ui-toolkit';
import { useWeb3ConnectStore } from './web3-connect-store'; import { useWeb3ConnectStore } from './web3-connect-store';
import { useT } from './use-t';
export const VerificationStatus = ({ export const VerificationStatus = ({
state, state,
}: { }: {
state: EthWithdrawalApprovalState; state: EthWithdrawalApprovalState;
}) => { }) => {
const t = useT();
const { config } = useEthereumConfig(); const { config } = useEthereumConfig();
const openDialog = useWeb3ConnectStore((state) => state.open); const openDialog = useWeb3ConnectStore((state) => state.open);
const remove = useToasts((state) => state.remove); const remove = useToasts((state) => state.remove);
@ -38,9 +39,14 @@ export const VerificationStatus = ({
return state.failureReason === WithdrawalFailure.NoConnection ? ( return state.failureReason === WithdrawalFailure.NoConnection ? (
<> <>
<p> <p>
{t('To complete this withdrawal, connect the Ethereum wallet %s', [ {t(
truncateByChars(state.withdrawal.details?.receiverAddress || ' '), 'To complete this withdrawal, connect the Ethereum wallet {{receiverAddress}}',
])} {
receiverAddress: truncateByChars(
state.withdrawal.details?.receiverAddress || ' '
),
}
)}
</p> </p>
<Button <Button
onClick={() => { onClick={() => {
@ -56,9 +62,12 @@ export const VerificationStatus = ({
<> <>
<p>{t('Your Ethereum wallet is connected to the wrong network.')}</p> <p>{t('Your Ethereum wallet is connected to the wrong network.')}</p>
<p className="mt-2"> <p className="mt-2">
{t('Go to your Ethereum wallet and connect to the network %s', [ {t(
resolveNetworkName(config?.chain_id), 'Go to your Ethereum wallet and connect to the network {{networkName}}',
])} {
networkName: resolveNetworkName(config?.chain_id),
}
)}
</p> </p>
</> </>
); );
@ -75,7 +84,9 @@ export const VerificationStatus = ({
return ( return (
<> <>
<p>{t("The amount you're withdrawing has triggered a time delay")}</p> <p>{t("The amount you're withdrawing has triggered a time delay")}</p>
<p>{t(`Cannot be completed until ${formattedTime}`)}</p> <p>
{t(`Cannot be completed until {{time}}`, { time: formattedTime })}
</p>
</> </>
); );
} }

View File

@ -1 +1,15 @@
import '@testing-library/jest-dom'; import '@testing-library/jest-dom';
import { locales } from '@vegaprotocol/i18n';
import i18n from 'i18next';
import { initReactI18next } from 'react-i18next';
// Set up i18n instance so that components have the correct default
// en translations
i18n.use(initReactI18next).init({
// we init with resources
resources: locales,
fallbackLng: 'en',
ns: ['web3'],
defaultNS: 'web3',
});