From a070504d2e0d0f55858c01524b77e1b4e90b000d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20G=C5=82ownia?= Date: Wed, 15 Nov 2023 06:10:06 +0100 Subject: [PATCH] feat(trading): i18n (#5126) Co-authored-by: Matthew Russell --- .../app/components/assets/assets-table.tsx | 17 +- apps/governance/src/app-loader.tsx | 19 +- apps/governance/src/app.tsx | 9 +- apps/governance/src/assets/locales | 1 + apps/governance/src/i18n/index.ts | 40 +- apps/governance/src/setup-tests.ts | 14 +- apps/trading/__mocks__/react-i18next.ts | 14 + .../client-pages/transfer/transfer.tsx | 2 +- .../client-pages/withdraw/withdraw.tsx | 2 +- .../components/bootstrapper/bootstrapper.tsx | 64 +- apps/trading/lib/i18n/index.ts | 81 + apps/trading/pages/_app.page.tsx | 5 +- apps/trading/public/locales | 1 + .../src/lib/accounts-actions-dropdown.tsx | 4 +- libs/accounts/src/lib/accounts-manager.tsx | 12 +- libs/accounts/src/lib/accounts-table.tsx | 6 +- libs/accounts/src/lib/breakdown-table.tsx | 7 +- libs/accounts/src/lib/margin-health-chart.tsx | 29 +- libs/accounts/src/lib/transfer-container.tsx | 26 +- libs/accounts/src/lib/transfer-form.tsx | 18 +- libs/accounts/src/lib/use-t.ts | 3 + libs/accounts/src/setup-tests.ts | 15 + libs/assets/src/lib/asset-details-dialog.tsx | 9 +- .../src/lib/asset-details-table.spec.tsx | 6 +- libs/assets/src/lib/asset-details-table.tsx | 379 ++-- libs/assets/src/lib/asset-option.tsx | 8 +- libs/assets/src/lib/constants.ts | 7 +- libs/assets/src/lib/use-t.ts | 3 + libs/candles-chart/src/lib/candles-chart.tsx | 5 +- libs/candles-chart/src/lib/candles-menu.tsx | 8 +- libs/candles-chart/src/lib/use-t.ts | 2 + libs/datagrid/__mocks__/react-i18next.ts | 15 + .../src/lib/ag-grid/ag-grid-themed.tsx | 7 +- .../src/lib/cells/order-type-cell.tsx | 15 +- .../src/lib/filters/date-range-filter.tsx | 13 +- libs/datagrid/src/lib/filters/set-filter.tsx | 3 +- libs/datagrid/src/lib/pagination.spec.tsx | 9 - libs/datagrid/src/lib/pagination.tsx | 17 +- libs/datagrid/src/lib/use-t.ts | 2 + libs/deal-ticket/__mocks__/react-i18next.ts | 14 + .../deal-ticket-validation/margin-warning.tsx | 19 +- .../zero-balance-error.tsx | 7 +- .../deal-ticket/deal-ticket-container.tsx | 3 +- .../deal-ticket/deal-ticket-fee-details.tsx | 92 +- .../deal-ticket-margin-details.tsx | 354 ++++ .../deal-ticket/deal-ticket-size-iceberg.tsx | 18 +- .../deal-ticket/deal-ticket-stop-order.tsx | 367 ++-- .../components/deal-ticket/deal-ticket.tsx | 73 +- .../deal-ticket/expiry-selector.tsx | 3 +- .../components/deal-ticket/side-selector.tsx | 12 +- .../deal-ticket/time-in-force-selector.tsx | 66 +- .../components/deal-ticket/type-selector.tsx | 85 +- .../fees-breakdown/fees-breakdown.tsx | 3 +- .../compile-grid-data.tsx | 3 +- .../trading-mode-tooltip.tsx | 14 +- libs/deal-ticket/src/constants.ts | 91 +- libs/deal-ticket/src/use-t.ts | 3 + libs/deal-ticket/src/utils/index.ts | 1 - .../src/utils/validate-expiration.ts | 22 +- .../src/utils/validate-market-state.ts | 37 - .../src/utils/validate-market-trading-mode.ts | 6 +- libs/deposits/__mocks__/react-i18next.ts | 14 + .../deposits/src/lib/approve-notification.tsx | 44 +- libs/deposits/src/lib/deposit-form.tsx | 41 +- libs/deposits/src/lib/deposit-limits.tsx | 29 +- libs/deposits/src/lib/faucet-notification.tsx | 30 +- libs/deposits/src/lib/get-faucet-error.ts | 11 +- libs/deposits/src/lib/use-t.ts | 2 + libs/environment/__mocks__/react-i18next.ts | 15 + .../src/components/etherscan-link.tsx | 3 +- .../network-switcher.spec.tsx | 77 +- .../network-switcher/network-switcher.tsx | 64 +- .../components/node-failure/node-failure.tsx | 3 +- .../components/node-switcher/layout-cell.tsx | 3 +- .../node-switcher/node-switcher.tsx | 7 +- .../src/components/node-switcher/row-data.tsx | 9 +- libs/environment/src/hooks/use-environment.ts | 9 +- .../src/hooks/use-node-health.spec.tsx | 4 +- libs/environment/src/hooks/use-node-health.ts | 40 +- libs/environment/src/use-t.ts | 2 + libs/fills/src/index.ts | 1 + libs/fills/src/lib/fill-actions-dropdown.tsx | 3 +- libs/fills/src/lib/fills-manager.tsx | 3 +- libs/fills/src/lib/fills-table.tsx | 7 +- libs/fills/src/lib/i18n-en.json | 3 + libs/fills/src/lib/use-t.jsx | 3 + libs/funding-payments/src/index.ts | 1 + .../src/lib/funding-payments-manager.tsx | 3 +- .../src/lib/funding-payments-table.tsx | 5 +- libs/funding-payments/src/lib/i18n-en.json | 3 + libs/funding-payments/src/lib/use-t.jsx | 3 + libs/i18n/src/index.ts | 8 + libs/i18n/src/locales/en/accounts.json | 58 + libs/i18n/src/locales/en/assets.json | 52 + libs/i18n/src/locales/en/candles-chart.json | 5 + libs/i18n/src/locales/en/datagrid.json | 21 + libs/i18n/src/locales/en/deal-ticket.json | 132 ++ libs/i18n/src/locales/en/deposits.json | 44 + libs/i18n/src/locales/en/environment.json | 40 + libs/i18n/src/locales/en/fills.json | 20 + .../i18n/src/locales/en/funding-payments.json | 6 + .../i18n/src/locales/en/governance.json | 1874 ++++++++--------- libs/i18n/src/locales/en/trading.json | 3 + libs/i18n/tsconfig.lib.json | 2 + libs/orders/__mocks__/react-i18next.ts | 14 + .../src/components/tooltip/tooltip.tsx | 11 + package.json | 6 +- yarn.lock | 37 +- 108 files changed, 3102 insertions(+), 1863 deletions(-) create mode 120000 apps/governance/src/assets/locales create mode 100644 apps/trading/__mocks__/react-i18next.ts create mode 100644 apps/trading/lib/i18n/index.ts create mode 120000 apps/trading/public/locales create mode 100644 libs/accounts/src/lib/use-t.ts create mode 100644 libs/assets/src/lib/use-t.ts create mode 100644 libs/candles-chart/src/lib/use-t.ts create mode 100644 libs/datagrid/__mocks__/react-i18next.ts create mode 100644 libs/datagrid/src/lib/use-t.ts create mode 100644 libs/deal-ticket/__mocks__/react-i18next.ts create mode 100644 libs/deal-ticket/src/components/deal-ticket/deal-ticket-margin-details.tsx create mode 100644 libs/deal-ticket/src/use-t.ts delete mode 100644 libs/deal-ticket/src/utils/validate-market-state.ts create mode 100644 libs/deposits/__mocks__/react-i18next.ts create mode 100644 libs/deposits/src/lib/use-t.ts create mode 100644 libs/environment/__mocks__/react-i18next.ts create mode 100644 libs/environment/src/use-t.ts create mode 100644 libs/fills/src/lib/i18n-en.json create mode 100644 libs/fills/src/lib/use-t.jsx create mode 100644 libs/funding-payments/src/lib/i18n-en.json create mode 100644 libs/funding-payments/src/lib/use-t.jsx create mode 100644 libs/i18n/src/locales/en/accounts.json create mode 100644 libs/i18n/src/locales/en/assets.json create mode 100644 libs/i18n/src/locales/en/candles-chart.json create mode 100644 libs/i18n/src/locales/en/datagrid.json create mode 100644 libs/i18n/src/locales/en/deal-ticket.json create mode 100644 libs/i18n/src/locales/en/deposits.json create mode 100644 libs/i18n/src/locales/en/environment.json create mode 100644 libs/i18n/src/locales/en/fills.json create mode 100644 libs/i18n/src/locales/en/funding-payments.json rename apps/governance/src/i18n/translations/dev.json => libs/i18n/src/locales/en/governance.json (99%) create mode 100644 libs/i18n/src/locales/en/trading.json create mode 100644 libs/orders/__mocks__/react-i18next.ts diff --git a/apps/explorer/src/app/components/assets/assets-table.tsx b/apps/explorer/src/app/components/assets/assets-table.tsx index dbcb44aaf..b5ce2377d 100644 --- a/apps/explorer/src/app/components/assets/assets-table.tsx +++ b/apps/explorer/src/app/components/assets/assets-table.tsx @@ -1,6 +1,9 @@ import { useMemo } from 'react'; -import { type AssetFieldsFragment } from '@vegaprotocol/assets'; -import { AssetTypeMapping, AssetStatusMapping } from '@vegaprotocol/assets'; +import { + useAssetTypeMapping, + useAssetStatusMapping, + type AssetFieldsFragment, +} from '@vegaprotocol/assets'; import { t } from '@vegaprotocol/i18n'; import { ButtonLink } from '@vegaprotocol/ui-toolkit'; import { type AgGridReact } from 'ag-grid-react'; @@ -15,6 +18,8 @@ type AssetsTableProps = { data: AssetFieldsFragment[] | null; }; export const AssetsTable = ({ data }: AssetsTableProps) => { + const assetTypeMapping = useAssetTypeMapping(); + const assetStatusMapping = useAssetStatusMapping(); const navigate = useNavigate(); const ref = useRef(null); const showColumnsOnDesktop = () => { @@ -47,14 +52,14 @@ export const AssetsTable = ({ data }: AssetsTableProps) => { field: 'source.__typename', hide: window.innerWidth < BREAKPOINT_MD, valueFormatter: ({ value }: { value?: string }) => - value ? AssetTypeMapping[value].value : '', + value ? assetTypeMapping[value].value : '', }, { headerName: t('Status'), field: 'status', hide: window.innerWidth < BREAKPOINT_MD, valueFormatter: ({ value }: { value?: string }) => - value ? AssetStatusMapping[value].value : '', + value ? assetStatusMapping[value].value : '', }, { colId: 'actions', @@ -69,7 +74,7 @@ export const AssetsTable = ({ data }: AssetsTableProps) => { }: VegaICellRendererParams) => value ? ( { + onClick={() => { navigate(value); }} > @@ -80,7 +85,7 @@ export const AssetsTable = ({ data }: AssetsTableProps) => { ), }, ], - [navigate] + [navigate, assetStatusMapping, assetTypeMapping] ); return ( diff --git a/apps/governance/src/app-loader.tsx b/apps/governance/src/app-loader.tsx index 150ecac4b..7536cc519 100644 --- a/apps/governance/src/app-loader.tsx +++ b/apps/governance/src/app-loader.tsx @@ -4,7 +4,7 @@ import { Splash } from '@vegaprotocol/ui-toolkit'; import { useVegaWallet, useEagerConnect } from '@vegaprotocol/wallet'; import { FLAGS, useEnvironment } from '@vegaprotocol/environment'; import { useWeb3React } from '@web3-react/core'; -import React from 'react'; +import React, { Suspense } from 'react'; import { useTranslation } from 'react-i18next'; import { SplashError } from './components/splash-error'; @@ -164,13 +164,14 @@ export const AppLoader = ({ children }: { children: React.ReactElement }) => { ); } - if (!loaded) { - return ( - - - - ); - } + const loading = ( + + + + ); - return children; + if (!loaded) { + return loading; + } + return {children}; }; diff --git a/apps/governance/src/app.tsx b/apps/governance/src/app.tsx index 39f77bd65..56b35ccee 100644 --- a/apps/governance/src/app.tsx +++ b/apps/governance/src/app.tsx @@ -42,6 +42,7 @@ import { useNodeSwitcherStore, DocsLinks, NodeFailure, + AppLoader as Loader, } from '@vegaprotocol/environment'; import { ENV } from './config'; import type { InMemoryCacheConfig } from '@apollo/client'; @@ -352,9 +353,11 @@ function App() { useInitializeEnv(); return ( - - - + }> + + + + ); } diff --git a/apps/governance/src/assets/locales b/apps/governance/src/assets/locales new file mode 120000 index 000000000..5f39c8875 --- /dev/null +++ b/apps/governance/src/assets/locales @@ -0,0 +1 @@ +../../../../libs/i18n/src/locales \ No newline at end of file diff --git a/apps/governance/src/i18n/index.ts b/apps/governance/src/i18n/index.ts index ce094b69e..0f2c9b12e 100644 --- a/apps/governance/src/i18n/index.ts +++ b/apps/governance/src/i18n/index.ts @@ -1,29 +1,41 @@ +import type { Module } from 'i18next'; import i18n from 'i18next'; +import HttpBackend from 'i18next-http-backend'; +import LocizeBackend from 'i18next-locize-backend'; import LanguageDetector from 'i18next-browser-languagedetector'; import { initReactI18next } from 'react-i18next'; -import dev from './translations/dev.json'; +const isInDev = process.env.NODE_ENV === 'development'; +const useLocize = isInDev && !!process.env.NX_USE_LOCIZE; + +const backend = useLocize + ? { + projectId: '96ac1231-4bdd-455a-b9d7-f5322a2e7430', + apiKey: process.env.NX_LOCIZE_API_KEY, + referenceLng: 'en', + } + : { + loadPath: '/assets/locales/{{lng}}/{{ns}}.json', + }; + +const Backend: Module = useLocize ? LocizeBackend : HttpBackend; i18n + .use(Backend) .use(LanguageDetector) .use(initReactI18next) .init({ - // we init with resources - resources: { - en: { - translations: { - ...dev, - }, - }, - }, - lng: undefined, + lng: 'en', fallbackLng: 'en', - debug: true, + supportedLngs: ['en'], + load: 'languageOnly', + debug: isInDev, // have a common namespace used around the full app - ns: ['translations'], - defaultNS: 'translations', + ns: ['governance'], + defaultNS: 'governance', keySeparator: false, // we use content as keys - + backend, + saveMissing: useLocize && !!process.env.NX_LOCIZE_API_KEY, interpolation: { escapeValue: false, }, diff --git a/apps/governance/src/setup-tests.ts b/apps/governance/src/setup-tests.ts index d1a19b13c..19620686f 100644 --- a/apps/governance/src/setup-tests.ts +++ b/apps/governance/src/setup-tests.ts @@ -3,7 +3,7 @@ // expect(element).toHaveTextContent(/react/i) // learn more: https://github.com/testing-library/jest-dom import '@testing-library/jest-dom'; -import dev from './i18n/translations/dev.json'; +import { locales } from '@vegaprotocol/i18n'; import i18n from 'i18next'; import { initReactI18next } from 'react-i18next'; import ResizeObserver from 'resize-observer-polyfill'; @@ -12,16 +12,10 @@ import ResizeObserver from 'resize-observer-polyfill'; // en translations i18n.use(initReactI18next).init({ // we init with resources - resources: { - en: { - translations: { - ...dev, - }, - }, - }, + resources: locales, fallbackLng: 'en', - ns: ['translations'], - defaultNS: 'translations', + ns: ['governance'], + defaultNS: 'governance', }); global.ResizeObserver = ResizeObserver; diff --git a/apps/trading/__mocks__/react-i18next.ts b/apps/trading/__mocks__/react-i18next.ts new file mode 100644 index 000000000..7c2343f52 --- /dev/null +++ b/apps/trading/__mocks__/react-i18next.ts @@ -0,0 +1,14 @@ +export const useTranslation = () => ({ + t: (label: string, replacements?: Record) => { + let translatedLabel = label; + if (typeof replacements === 'object' && replacements !== null) { + Object.keys(replacements).forEach((key) => { + translatedLabel = translatedLabel.replace( + `{{${key}}}`, + replacements[key] + ); + }); + } + return translatedLabel; + }, +}); diff --git a/apps/trading/client-pages/transfer/transfer.tsx b/apps/trading/client-pages/transfer/transfer.tsx index 62134d565..1b489bfb5 100644 --- a/apps/trading/client-pages/transfer/transfer.tsx +++ b/apps/trading/client-pages/transfer/transfer.tsx @@ -1,6 +1,6 @@ import { useSearchParams } from 'react-router-dom'; import { TransferContainer } from '@vegaprotocol/accounts'; -import { GetStarted } from '../../components/welcome-dialog'; +import { GetStarted } from '../../components/welcome-dialog/get-started'; export const Transfer = () => { const [searchParams] = useSearchParams(); diff --git a/apps/trading/client-pages/withdraw/withdraw.tsx b/apps/trading/client-pages/withdraw/withdraw.tsx index 3e0686362..16a87b775 100644 --- a/apps/trading/client-pages/withdraw/withdraw.tsx +++ b/apps/trading/client-pages/withdraw/withdraw.tsx @@ -1,5 +1,5 @@ import { useSearchParams } from 'react-router-dom'; -import { GetStarted } from '../../components/welcome-dialog'; +import { GetStarted } from '../../components/welcome-dialog/get-started'; import { WithdrawContainer } from '../../components/withdraw-container'; export const Withdraw = () => { diff --git a/apps/trading/components/bootstrapper/bootstrapper.tsx b/apps/trading/components/bootstrapper/bootstrapper.tsx index 1766a81c8..4545cff9e 100644 --- a/apps/trading/components/bootstrapper/bootstrapper.tsx +++ b/apps/trading/components/bootstrapper/bootstrapper.tsx @@ -10,7 +10,7 @@ import { } from '@vegaprotocol/environment'; import { t } from '@vegaprotocol/i18n'; import { VegaWalletProvider } from '@vegaprotocol/wallet'; -import type { ReactNode } from 'react'; +import { Suspense, type ReactNode } from 'react'; import { Web3Provider } from './web3-provider'; export const Bootstrapper = ({ children }: { children: ReactNode }) => { @@ -36,41 +36,43 @@ export const Bootstrapper = ({ children }: { children: ReactNode }) => { } return ( - } - failure={ - - } - > - }> + } - failure={} + failure={ + + } > - } - failure={ - - } + failure={} > - } + failure={ + + } > - {children} - - - - + + {children} + + + + + ); }; diff --git a/apps/trading/lib/i18n/index.ts b/apps/trading/lib/i18n/index.ts new file mode 100644 index 000000000..63669e319 --- /dev/null +++ b/apps/trading/lib/i18n/index.ts @@ -0,0 +1,81 @@ +import type { Module } from 'i18next'; +import i18n from 'i18next'; +import HttpBackend from 'i18next-http-backend'; +import LocizeBackend from 'i18next-locize-backend'; +import type { HttpBackendOptions, RequestCallback } from 'i18next-http-backend'; +import LanguageDetector from 'i18next-browser-languagedetector'; +import { initReactI18next } from 'react-i18next'; + +const isInDev = process.env.NODE_ENV === 'development'; +const useLocize = isInDev && !!process.env.NX_USE_LOCIZE; + +const backend = useLocize + ? { + projectId: '96ac1231-4bdd-455a-b9d7-f5322a2e7430', + apiKey: process.env.NX_LOCIZE_API_KEY, + referenceLng: 'en', + } + : { + loadPath: '/locales/{{lng}}/{{ns}}.json', + request: ( + options: HttpBackendOptions, + url: string, + payload: string, + callback: RequestCallback + ) => { + if (typeof window === 'undefined') { + callback(false, { status: 200, data: {} }); + return; + } + fetch(url).then((response) => { + if (!response.ok) { + return callback(response.statusText || 'Error', { + status: response.status, + data: {}, + }); + } + response + .text() + .then((data) => { + callback(null, { status: response.status, data }); + }) + .catch((error) => callback(error, { status: 200, data: {} })); + }); + }, + }; + +const Backend: Module = useLocize ? LocizeBackend : HttpBackend; + +i18n + .use(Backend) + .use(LanguageDetector) + .use(initReactI18next) + .init({ + lng: 'en', + fallbackLng: 'en', + supportedLngs: ['en'], + load: 'languageOnly', + // have a common namespace used around the full app + ns: [ + 'accounts', + 'assets', + 'candles-chart', + 'datagrid', + 'deal-ticket', + 'deposits', + 'environment', + 'fills', + 'funding-payments', + 'trading', + ], + defaultNS: 'trading', + keySeparator: false, // we use content as keys + backend, + debug: isInDev, + saveMissing: useLocize && !!process.env.NX_LOCIZE_API_KEY, + interpolation: { + escapeValue: false, + }, + }); + +export default i18n; diff --git a/apps/trading/pages/_app.page.tsx b/apps/trading/pages/_app.page.tsx index a033b6614..d0241415c 100644 --- a/apps/trading/pages/_app.page.tsx +++ b/apps/trading/pages/_app.page.tsx @@ -3,7 +3,7 @@ import Head from 'next/head'; import type { AppProps } from 'next/app'; import { t } from '@vegaprotocol/i18n'; import { - envTriggerMapping, + useEnvTriggerMapping, Networks, NodeSwitcherDialog, useEnvironment, @@ -32,6 +32,7 @@ import { SSRLoader } from './ssr-loader'; import { PartyActiveOrdersHandler } from './party-active-orders-handler'; import { MaybeConnectEagerly } from './maybe-connect-eagerly'; import { TransactionHandlers } from './transaction-handlers'; +import '../lib/i18n'; const DEFAULT_TITLE = t('Welcome to Vega trading!'); @@ -39,7 +40,7 @@ const Title = () => { const { pageTitle } = usePageTitleStore((store) => ({ pageTitle: store.pageTitle, })); - + const envTriggerMapping = useEnvTriggerMapping(); const { VEGA_ENV } = useEnvironment(); const networkName = envTriggerMapping[VEGA_ENV]; diff --git a/apps/trading/public/locales b/apps/trading/public/locales new file mode 120000 index 000000000..b10372509 --- /dev/null +++ b/apps/trading/public/locales @@ -0,0 +1 @@ +../../../libs/i18n/src/locales \ No newline at end of file diff --git a/libs/accounts/src/lib/accounts-actions-dropdown.tsx b/libs/accounts/src/lib/accounts-actions-dropdown.tsx index 9c0eb5d3a..82919ccee 100644 --- a/libs/accounts/src/lib/accounts-actions-dropdown.tsx +++ b/libs/accounts/src/lib/accounts-actions-dropdown.tsx @@ -1,5 +1,5 @@ import { ETHERSCAN_ADDRESS, useEtherscanLink } from '@vegaprotocol/environment'; -import { t } from '@vegaprotocol/i18n'; +import { useT } from './use-t'; import { ActionsDropdown, TradingDropdownCopyItem, @@ -27,7 +27,7 @@ export const AccountsActionsDropdown = ({ }) => { const etherscanLink = useEtherscanLink(); const openAssetDialog = useAssetDetailsDialogStore((store) => store.open); - + const t = useT(); return ( void; }) => { + const t = useT(); const gridRef = useRef(null); const { data } = useDataProvider({ dataProvider: aggregatedAccountDataProvider, @@ -45,10 +46,10 @@ const AccountBreakdown = ({ {data && (

- {t('You have %s %s in total.', [ - addDecimalsFormatNumber(data.total, data.asset.decimals), - data.asset.symbol, - ])} + {t('You have {{value}} {{symbol}} in total.', { + value: addDecimalsFormatNumber(data.total, data.asset.decimals), + symbol: data.asset.symbol, + })}

)} { + const t = useT(); const [breakdownAssetId, setBreakdownAssetId] = useState(); const { data, error } = useDataProvider({ dataProvider: aggregatedAccountsDataProvider, diff --git a/libs/accounts/src/lib/accounts-table.tsx b/libs/accounts/src/lib/accounts-table.tsx index e28f2aeea..b7a2583bb 100644 --- a/libs/accounts/src/lib/accounts-table.tsx +++ b/libs/accounts/src/lib/accounts-table.tsx @@ -5,7 +5,7 @@ import { isNumeric, toBigNum, } from '@vegaprotocol/utils'; -import { t } from '@vegaprotocol/i18n'; +import { useT } from './use-t'; import type { VegaICellRendererParams, VegaValueFormatterParams, @@ -96,6 +96,7 @@ export const AccountTable = ({ pinnedAsset, ...props }: AccountTableProps) => { + const t = useT(); const pinnedRow = useMemo(() => { if (!pinnedAsset) { return; @@ -191,7 +192,7 @@ export const AccountTable = ({ <> {valueFormatted} - {t('0.00%')} + {(0).toFixed(2)}% ); @@ -310,6 +311,7 @@ export const AccountTable = ({ onClickTransfer, isReadOnly, showDepositButton, + t, ]); const data = rowData?.filter((data) => data.asset.id !== pinnedAsset?.id); diff --git a/libs/accounts/src/lib/breakdown-table.tsx b/libs/accounts/src/lib/breakdown-table.tsx index 7c88645eb..24a62b12e 100644 --- a/libs/accounts/src/lib/breakdown-table.tsx +++ b/libs/accounts/src/lib/breakdown-table.tsx @@ -3,7 +3,7 @@ import { addDecimalsFormatNumber, addDecimalsFormatNumberQuantum, } from '@vegaprotocol/utils'; -import { t } from '@vegaprotocol/i18n'; +import { useT } from './use-t'; import { Intent, TooltipCellComponent } from '@vegaprotocol/ui-toolkit'; import { type AgGridReact, type AgGridReactProps } from 'ag-grid-react'; import { type AccountFields } from './accounts-data-provider'; @@ -31,6 +31,7 @@ interface BreakdownTableProps extends AgGridReactProps { const BreakdownTable = forwardRef( ({ data }, ref) => { + const t = useT(); const coldefs = useMemo(() => { const defs: ColDef[] = [ { @@ -53,7 +54,7 @@ const BreakdownTable = forwardRef( } /> ) : ( - 'None' + t('None') ); }, }, @@ -126,7 +127,7 @@ const BreakdownTable = forwardRef( }, ]; return defs; - }, []); + }, [t]); return ( { + const t = useT(); const tooltipContent = [ - {addDecimalsFormatNumber( - (BigInt(marginAccountBalance) - BigInt(maintenanceLevel)).toString(), - decimals - )}{' '} - {t('above')}{' '} - - {t('maintenance level')} - + + maintenance level + , + ]} + values={{ + balance: addDecimalsFormatNumber( + ( + BigInt(marginAccountBalance) - BigInt(maintenanceLevel) + ).toString(), + decimals + ), + }} + ns={ns} + />
{ + const t = useT(); const { pubKey, pubKeys } = useVegaWallet(); const { params } = useNetworkParams([ NetworkParams.transfer_fee_factor, @@ -50,16 +52,20 @@ export const TransferContainer = ({ assetId }: { assetId?: string }) => { return ( <>

- {t('Transfer funds to another Vega key')} - {pubKey && ( - <> - {t(' from ')} - - {truncateByChars(pubKey || '')} - - + {pubKey ? ( + pubKey]} + values={{ pubKey: truncateByChars(pubKey || '') }} + /> + ) : ( + t('TRANSFER_FUNDS_TO_ANOTHER_VEGA_KEY', { + defaultValue: + 'Transfer funds to another Vega key. If you are at all unsure, stop and seek advice.', + }) )} - {t('. If you are at all unsure, stop and seek advice.')}

{ + const t = useT(); const { control, register, @@ -300,7 +301,7 @@ export const TransferForm = ({ )} - + { setValue('toVegaKey', ''); @@ -317,7 +318,10 @@ export const TransferForm = ({ {t('Please select')} {pubKeys?.map((pk) => { - const text = pk === pubKey ? t('Current key: ') + pk : pk; + const text = + pk === pubKey + ? t('Current key: {{pubKey}}', { pubKey: pk }) + pk + : pk; return ( - + { + const t = useT(); if (!feeFactor || !amount || !transferAmount || !fee) return null; if ( isNaN(Number(feeFactor)) || @@ -490,8 +495,8 @@ export const TransferFee = ({
{t('Transfer fee')}
@@ -546,6 +551,7 @@ export const AddressField = ({ mode, onChange, }: AddressInputProps) => { + const t = useT(); const isInput = mode === 'input'; return ( <> diff --git a/libs/accounts/src/lib/use-t.ts b/libs/accounts/src/lib/use-t.ts new file mode 100644 index 000000000..06402875e --- /dev/null +++ b/libs/accounts/src/lib/use-t.ts @@ -0,0 +1,3 @@ +import { useTranslation } from 'react-i18next'; +export const ns = 'accounts'; +export const useT = () => useTranslation(ns).t; diff --git a/libs/accounts/src/setup-tests.ts b/libs/accounts/src/setup-tests.ts index 880268538..d7d384eda 100644 --- a/libs/accounts/src/setup-tests.ts +++ b/libs/accounts/src/setup-tests.ts @@ -1,6 +1,21 @@ import '@testing-library/jest-dom'; import ResizeObserver from 'resize-observer-polyfill'; import { defaultFallbackInView } from 'react-intersection-observer'; +import { locales } from '@vegaprotocol/i18n'; +import i18n from 'i18next'; +import { initReactI18next } from 'react-i18next'; defaultFallbackInView(true); global.ResizeObserver = ResizeObserver; + +// 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: ['accounts'], + defaultNS: 'accounts', +}); + +global.ResizeObserver = ResizeObserver; diff --git a/libs/assets/src/lib/asset-details-dialog.tsx b/libs/assets/src/lib/asset-details-dialog.tsx index 9f2fa7503..076d3b411 100644 --- a/libs/assets/src/lib/asset-details-dialog.tsx +++ b/libs/assets/src/lib/asset-details-dialog.tsx @@ -1,4 +1,4 @@ -import { t } from '@vegaprotocol/i18n'; +import { useT } from './use-t'; import { Button, Dialog, @@ -56,6 +56,7 @@ export const AssetDetailsDialog = ({ onChange, asJson = false, }: AssetDetailsDialogProps) => { + const t = useT(); const { data: asset } = useAssetDataProvider(assetId); const assetSymbol = asset?.symbol || ''; @@ -77,7 +78,7 @@ export const AssetDetailsDialog = ({
); const title = asset - ? t(`Asset details - ${asset.symbol}`) + ? t('Asset details - {{symbol}}', asset) : t('Asset not found'); return ( @@ -100,8 +101,8 @@ export const AssetDetailsDialog = ({ {content}

{t( - 'There is 1 unit of the settlement asset (%s) to every 1 quote unit.', - [assetSymbol] + 'There is 1 unit of the settlement asset ({{assetSymbol}}) to every 1 quote unit.', + { assetSymbol } )}

diff --git a/libs/assets/src/lib/asset-details-table.spec.tsx b/libs/assets/src/lib/asset-details-table.spec.tsx index 358cb23db..1e3138917 100644 --- a/libs/assets/src/lib/asset-details-table.spec.tsx +++ b/libs/assets/src/lib/asset-details-table.spec.tsx @@ -1,10 +1,10 @@ -import { render, screen } from '@testing-library/react'; +import { render, screen, renderHook } from '@testing-library/react'; import * as Schema from '@vegaprotocol/types'; import type { Asset } from './asset-data-provider'; import { AssetDetail, AssetDetailsTable, - rows, + useRows, testId, } from './asset-details-table'; import { generateBuiltinAsset, generateERC20Asset } from './test-helpers'; @@ -67,6 +67,8 @@ describe('AssetDetailsTable', () => { it.each(cases)( "displays the available asset's data of %p with correct labels", async (_type, asset, details) => { + const { result } = renderHook(() => useRows()); + const rows = result.current; render(); for (const detail of details) { expect( diff --git a/libs/assets/src/lib/asset-details-table.tsx b/libs/assets/src/lib/asset-details-table.tsx index 8758c384d..1d30dbf32 100644 --- a/libs/assets/src/lib/asset-details-table.tsx +++ b/libs/assets/src/lib/asset-details-table.tsx @@ -1,6 +1,6 @@ import { EtherscanLink } from '@vegaprotocol/environment'; import { addDecimalsFormatNumber } from '@vegaprotocol/utils'; -import { t } from '@vegaprotocol/i18n'; +import { useT } from './use-t'; import type * as Schema from '@vegaprotocol/types'; import type { KeyValueTableRowProps } from '@vegaprotocol/ui-toolkit'; import { VegaIcon, VegaIconNames } from '@vegaprotocol/ui-toolkit'; @@ -10,7 +10,7 @@ import { KeyValueTableRow, Tooltip, } from '@vegaprotocol/ui-toolkit'; -import type { ReactNode } from 'react'; +import { useMemo, type ReactNode } from 'react'; import type { Asset } from './asset-data-provider'; import { WITHDRAW_THRESHOLD_TOOLTIP_TEXT } from './constants'; @@ -52,183 +52,208 @@ const num = (asset: Asset, n: string | undefined | null) => { return addDecimalsFormatNumber(n, asset.decimals); }; -export const rows: Rows = [ - { - key: AssetDetail.ID, - label: t('ID'), - tooltip: '', - value: (asset) => ( - <> - {truncateMiddle(asset.id)}{' '} - - - - - ), - }, - { - key: AssetDetail.TYPE, - label: t('Type'), - tooltip: '', - value: (asset) => AssetTypeMapping[asset.source.__typename].value, - valueTooltip: (asset) => AssetTypeMapping[asset.source.__typename].tooltip, - }, - { - key: AssetDetail.NAME, - label: t('Name'), - tooltip: '', - value: (asset) => asset.name, - }, - { - key: AssetDetail.SYMBOL, - label: t('Symbol'), - tooltip: '', - value: (asset) => asset.symbol, - }, - { - key: AssetDetail.DECIMALS, - label: t('Decimals'), - tooltip: t('Number of decimal / precision handled by this asset'), - value: (asset) => asset.decimals.toString(), - }, - { - key: AssetDetail.QUANTUM, - label: t('Quantum'), - tooltip: t('The minimum economically meaningful amount of the asset'), - value: (asset) => num(asset, asset.quantum), - }, - { - key: AssetDetail.STATUS, - label: t('Status'), - tooltip: t('The status of the asset in the Vega network'), - value: (asset) => AssetStatusMapping[asset.status].value, - valueTooltip: (asset) => AssetStatusMapping[asset.status].tooltip, - }, - { - key: AssetDetail.CONTRACT_ADDRESS, - label: t('Contract address'), - tooltip: t( - 'The address of the contract for the token, on the ethereum network' - ), - value: (asset) => { - if (asset.source.__typename !== 'ERC20') { - return; - } +export const useRows = () => { + const t = useT(); + const AssetTypeMapping = useAssetTypeMapping(); + const AssetStatusMapping = useAssetStatusMapping(); + return useMemo( + () => [ + { + key: AssetDetail.ID, + label: t('ID'), + tooltip: '', + value: (asset) => ( + <> + {truncateMiddle(asset.id)}{' '} + + + + + ), + }, + { + key: AssetDetail.TYPE, + label: t('Type'), + tooltip: '', + value: (asset) => AssetTypeMapping[asset.source.__typename].value, + valueTooltip: (asset) => + AssetTypeMapping[asset.source.__typename].tooltip, + }, + { + key: AssetDetail.NAME, + label: t('Name'), + tooltip: '', + value: (asset) => asset.name, + }, + { + key: AssetDetail.SYMBOL, + label: t('Symbol'), + tooltip: '', + value: (asset) => asset.symbol, + }, + { + key: AssetDetail.DECIMALS, + label: t('Decimals'), + tooltip: t('Number of decimal / precision handled by this asset'), + value: (asset) => asset.decimals.toString(), + }, + { + key: AssetDetail.QUANTUM, + label: t('Quantum'), + tooltip: t('The minimum economically meaningful amount of the asset'), + value: (asset) => num(asset, asset.quantum), + }, + { + key: AssetDetail.STATUS, + label: t('Status'), + tooltip: t('The status of the asset in the Vega network'), + value: (asset) => AssetStatusMapping[asset.status].value, + valueTooltip: (asset) => AssetStatusMapping[asset.status].tooltip, + }, + { + key: AssetDetail.CONTRACT_ADDRESS, + label: t('Contract address'), + tooltip: t( + 'The address of the contract for the token, on the ethereum network' + ), + value: (asset) => { + if (asset.source.__typename !== 'ERC20') { + return; + } - return ( - <> - - {truncateMiddle(asset.source.contractAddress)} - {' '} - - - - - ); - }, - }, - { - key: AssetDetail.WITHDRAWAL_THRESHOLD, - label: t('Withdrawal threshold'), - tooltip: WITHDRAW_THRESHOLD_TOOLTIP_TEXT, - value: (asset) => - num(asset, (asset.source as Schema.ERC20).withdrawThreshold), - }, - { - key: AssetDetail.LIFETIME_LIMIT, - label: t('Lifetime limit'), - tooltip: t( - 'The lifetime deposit limit per address. Note: this is a temporary measure that can be changed or removed through governance' - ), - value: (asset) => num(asset, (asset.source as Schema.ERC20).lifetimeLimit), - }, - { - key: AssetDetail.MAX_FAUCET_AMOUNT_MINT, - label: t('Max faucet amount'), - tooltip: t( - 'Maximum amount that can be requested by a party through the built-in asset faucet at a time' - ), - value: (asset) => - num(asset, (asset.source as Schema.BuiltinAsset).maxFaucetAmountMint), - }, - { - key: AssetDetail.INFRASTRUCTURE_FEE_ACCOUNT_BALANCE, - label: t('Infrastructure fee account balance'), - tooltip: t('The infrastructure fee account in this asset'), - value: (asset) => num(asset, asset.infrastructureFeeAccount?.balance), - }, - { - key: AssetDetail.GLOBAL_REWARD_POOL_ACCOUNT_BALANCE, - label: t('Global reward pool account balance'), - tooltip: t('The global rewards acquired in this asset'), - value: (asset) => num(asset, asset.globalRewardPoolAccount?.balance), - }, - { - key: AssetDetail.MAKER_PAID_FEES_ACCOUNT_BALANCE, - label: t('Maker paid fees account balance'), - tooltip: t( - 'The rewards acquired based on the fees paid to makers in this asset' - ), - value: (asset) => num(asset, asset.takerFeeRewardAccount?.balance), - }, - { - key: AssetDetail.MAKER_RECEIVED_FEES_ACCOUNT_BALANCE, - label: t('Maker received fees account balance'), - tooltip: t( - 'The rewards acquired based on fees received for being a maker on trades' - ), - value: (asset) => num(asset, asset.makerFeeRewardAccount?.balance), - }, - { - key: AssetDetail.LP_FEE_REWARD_ACCOUNT_BALANCE, - label: t('Liquidity provision fee reward account balance'), - tooltip: t( - 'The rewards acquired based on the liquidity provision fees in this asset' - ), - value: (asset) => num(asset, asset.lpFeeRewardAccount?.balance), - }, - { - key: AssetDetail.MARKET_PROPOSER_REWARD_ACCOUNT_BALANCE, - label: t('Market proposer reward account balance'), - tooltip: t( - 'The rewards acquired based on the market proposer reward in this asset' - ), - value: (asset) => num(asset, asset.marketProposerRewardAccount?.balance), - }, -]; - -export const AssetStatusMapping: Mapping = { - STATUS_ENABLED: { - value: t('Enabled'), - tooltip: t('Asset can be used on the Vega network'), - }, - STATUS_PENDING_LISTING: { - value: t('Pending listing'), - tooltip: t('Asset needs to be added to the Ethereum bridge'), - }, - STATUS_PROPOSED: { - value: t('Proposed'), - tooltip: t('Asset has been proposed to the network'), - }, - STATUS_REJECTED: { - value: t('Rejected'), - tooltip: t('Asset has been rejected'), - }, + return ( + <> + + {truncateMiddle(asset.source.contractAddress)} + {' '} + + + + + ); + }, + }, + { + key: AssetDetail.WITHDRAWAL_THRESHOLD, + label: t('Withdrawal threshold'), + tooltip: t('WITHDRAW_THRESHOLD_TOOLTIP_TEXT', { + defaultValue: WITHDRAW_THRESHOLD_TOOLTIP_TEXT, + }), + value: (asset) => + num(asset, (asset.source as Schema.ERC20).withdrawThreshold), + }, + { + key: AssetDetail.LIFETIME_LIMIT, + label: t('Lifetime limit'), + tooltip: t( + 'The lifetime deposit limit per address. Note: this is a temporary measure that can be changed or removed through governance' + ), + value: (asset) => + num(asset, (asset.source as Schema.ERC20).lifetimeLimit), + }, + { + key: AssetDetail.MAX_FAUCET_AMOUNT_MINT, + label: t('Max faucet amount'), + tooltip: t( + 'Maximum amount that can be requested by a party through the built-in asset faucet at a time' + ), + value: (asset) => + num(asset, (asset.source as Schema.BuiltinAsset).maxFaucetAmountMint), + }, + { + key: AssetDetail.INFRASTRUCTURE_FEE_ACCOUNT_BALANCE, + label: t('Infrastructure fee account balance'), + tooltip: t('The infrastructure fee account in this asset'), + value: (asset) => num(asset, asset.infrastructureFeeAccount?.balance), + }, + { + key: AssetDetail.GLOBAL_REWARD_POOL_ACCOUNT_BALANCE, + label: t('Global reward pool account balance'), + tooltip: t('The global rewards acquired in this asset'), + value: (asset) => num(asset, asset.globalRewardPoolAccount?.balance), + }, + { + key: AssetDetail.MAKER_PAID_FEES_ACCOUNT_BALANCE, + label: t('Maker paid fees account balance'), + tooltip: t( + 'The rewards acquired based on the fees paid to makers in this asset' + ), + value: (asset) => num(asset, asset.takerFeeRewardAccount?.balance), + }, + { + key: AssetDetail.MAKER_RECEIVED_FEES_ACCOUNT_BALANCE, + label: t('Maker received fees account balance'), + tooltip: t( + 'The rewards acquired based on fees received for being a maker on trades' + ), + value: (asset) => num(asset, asset.makerFeeRewardAccount?.balance), + }, + { + key: AssetDetail.LP_FEE_REWARD_ACCOUNT_BALANCE, + label: t('Liquidity provision fee reward account balance'), + tooltip: t( + 'The rewards acquired based on the liquidity provision fees in this asset' + ), + value: (asset) => num(asset, asset.lpFeeRewardAccount?.balance), + }, + { + key: AssetDetail.MARKET_PROPOSER_REWARD_ACCOUNT_BALANCE, + label: t('Market proposer reward account balance'), + tooltip: t( + 'The rewards acquired based on the market proposer reward in this asset' + ), + value: (asset) => + num(asset, asset.marketProposerRewardAccount?.balance), + }, + ], + [t, AssetTypeMapping, AssetStatusMapping] + ); }; -export const AssetTypeMapping: Mapping = { - BuiltinAsset: { - value: 'Builtin asset', - tooltip: t('A Vega builtin asset'), - }, - ERC20: { - value: 'ERC20', - tooltip: t('An asset originated from an Ethereum ERC20 Token'), - }, +export const useAssetStatusMapping = () => { + const t = useT(); + return useMemo( + () => ({ + STATUS_ENABLED: { + value: t('Enabled'), + tooltip: t('Asset can be used on the Vega network'), + }, + STATUS_PENDING_LISTING: { + value: t('Pending listing'), + tooltip: t('Asset needs to be added to the Ethereum bridge'), + }, + STATUS_PROPOSED: { + value: t('Proposed'), + tooltip: t('Asset has been proposed to the network'), + }, + STATUS_REJECTED: { + value: t('Rejected'), + tooltip: t('Asset has been rejected'), + }, + }), + [t] + ); +}; + +export const useAssetTypeMapping = () => { + const t = useT(); + return useMemo( + () => ({ + BuiltinAsset: { + value: t('Builtin asset'), + tooltip: t('A Vega builtin asset'), + }, + ERC20: { + value: t('ERC20'), + tooltip: t('An asset originated from an Ethereum ERC20 Token'), + }, + }), + [t] + ); }; export const testId = (detail: AssetDetail, field: 'label' | 'value') => @@ -248,7 +273,7 @@ export const AssetDetailsTable = ({ ? { className: 'break-all', title: value } : {}; - const details = rows.map((r) => ({ + const details = useRows().map((r) => ({ ...r, value: r.value(asset), valueTooltip: r.valueTooltip?.(asset), diff --git a/libs/assets/src/lib/asset-option.tsx b/libs/assets/src/lib/asset-option.tsx index 689b389e9..a107bea89 100644 --- a/libs/assets/src/lib/asset-option.tsx +++ b/libs/assets/src/lib/asset-option.tsx @@ -1,7 +1,7 @@ import { TradingOption, truncateMiddle } from '@vegaprotocol/ui-toolkit'; import type { AssetFieldsFragment } from './__generated__/Asset'; import classNames from 'classnames'; -import { t } from '@vegaprotocol/i18n'; +import { useT } from './use-t'; import type { ReactNode } from 'react'; type AssetOptionProps = { @@ -15,8 +15,9 @@ export const Balance = ({ }: { balance?: string; symbol: string; -}) => - balance ? ( +}) => { + const t = useT(); + return balance ? (
{balance} {symbol}
@@ -25,6 +26,7 @@ export const Balance = ({ {t('Fetching balance…')}
); +}; export const AssetOption = ({ asset, balance }: AssetOptionProps) => { return ( diff --git a/libs/assets/src/lib/constants.ts b/libs/assets/src/lib/constants.ts index d28ea806a..503e4e460 100644 --- a/libs/assets/src/lib/constants.ts +++ b/libs/assets/src/lib/constants.ts @@ -1,8 +1,5 @@ -import { t } from '@vegaprotocol/i18n'; - -export const WITHDRAW_THRESHOLD_TOOLTIP_TEXT = t( - "The maximum you can withdraw instantly. There's no limit on the size of a withdrawal, but all withdrawals over the threshold will have a delay time added to them" -); +export const WITHDRAW_THRESHOLD_TOOLTIP_TEXT = + "The maximum you can withdraw instantly. There's no limit on the size of a withdrawal, but all withdrawals over the threshold will have a delay time added to them"; // List of defunct and no longer used assets that were created for various testnets export const DENY_LIST: Record = { diff --git a/libs/assets/src/lib/use-t.ts b/libs/assets/src/lib/use-t.ts new file mode 100644 index 000000000..76d98b89d --- /dev/null +++ b/libs/assets/src/lib/use-t.ts @@ -0,0 +1,3 @@ +import { useTranslation } from 'react-i18next'; + +export const useT = () => useTranslation('assets').t; diff --git a/libs/candles-chart/src/lib/candles-chart.tsx b/libs/candles-chart/src/lib/candles-chart.tsx index 1cc76603a..48049d0ce 100644 --- a/libs/candles-chart/src/lib/candles-chart.tsx +++ b/libs/candles-chart/src/lib/candles-chart.tsx @@ -6,12 +6,12 @@ import { useMemo } from 'react'; import debounce from 'lodash/debounce'; import AutoSizer from 'react-virtualized-auto-sizer'; import { useVegaWallet } from '@vegaprotocol/wallet'; -import { useThemeSwitcher } from '@vegaprotocol/react-helpers'; -import { t } from '@vegaprotocol/i18n'; import { STUDY_SIZE, useCandlesChartSettings, } from './use-candles-chart-settings'; +import { useT } from './use-t'; +import { useThemeSwitcher } from '@vegaprotocol/react-helpers'; export type CandlesChartContainerProps = { marketId: string; @@ -25,6 +25,7 @@ export const CandlesChartContainer = ({ const client = useApolloClient(); const { pubKey } = useVegaWallet(); const { theme } = useThemeSwitcher(); + const t = useT(); const { interval, diff --git a/libs/candles-chart/src/lib/candles-menu.tsx b/libs/candles-chart/src/lib/candles-menu.tsx index 55bd36ea5..2d90c2792 100644 --- a/libs/candles-chart/src/lib/candles-menu.tsx +++ b/libs/candles-chart/src/lib/candles-menu.tsx @@ -22,8 +22,8 @@ import { } from '@vegaprotocol/ui-toolkit'; import { type IconName } from '@blueprintjs/icons'; import { IconNames } from '@blueprintjs/icons'; -import { t } from '@vegaprotocol/i18n'; import { useCandlesChartSettings } from './use-candles-chart-settings'; +import { useT } from './use-t'; const chartTypeIcon = new Map([ [ChartType.AREA, IconNames.TIMELINE_AREA_CHART], @@ -43,6 +43,7 @@ export const CandlesMenu = () => { setStudies, setOverlays, } = useCandlesChartSettings(); + const t = useT(); const triggerClasses = 'text-xs'; const contentAlign = 'end'; const triggerButtonProps = { size: 'extra-small' } as const; @@ -53,7 +54,10 @@ export const CandlesMenu = () => { trigger={ - {t(`Interval: ${intervalLabels[interval]}`)} + {t('Interval: {{interval}}', { + replace: { interval: intervalLabels[interval] }, + nsSeparator: '|', + })} } diff --git a/libs/candles-chart/src/lib/use-t.ts b/libs/candles-chart/src/lib/use-t.ts new file mode 100644 index 000000000..8511a3520 --- /dev/null +++ b/libs/candles-chart/src/lib/use-t.ts @@ -0,0 +1,2 @@ +import { useTranslation } from 'react-i18next'; +export const useT = () => useTranslation('candles-chart').t; diff --git a/libs/datagrid/__mocks__/react-i18next.ts b/libs/datagrid/__mocks__/react-i18next.ts new file mode 100644 index 000000000..6e38064bb --- /dev/null +++ b/libs/datagrid/__mocks__/react-i18next.ts @@ -0,0 +1,15 @@ +export const useTranslation = () => ({ + t: (label: string, replacements?: Record) => { + const replace = + replacements?.['replace'] && typeof replacements === 'object' + ? replacements?.['replace'] + : replacements; + let translatedLabel = replacements?.['defaultValue'] || label; + if (typeof replace === 'object' && replace !== null) { + Object.keys(replace).forEach((key) => { + translatedLabel = translatedLabel.replace(`{{${key}}}`, replace[key]); + }); + } + return translatedLabel; + }, +}); diff --git a/libs/datagrid/src/lib/ag-grid/ag-grid-themed.tsx b/libs/datagrid/src/lib/ag-grid/ag-grid-themed.tsx index 269aa1c99..edcb30bd8 100644 --- a/libs/datagrid/src/lib/ag-grid/ag-grid-themed.tsx +++ b/libs/datagrid/src/lib/ag-grid/ag-grid-themed.tsx @@ -1,14 +1,12 @@ import type { AgGridReactProps, AgReactUiProps } from 'ag-grid-react'; import { AgGridReact } from 'ag-grid-react'; import { useThemeSwitcher } from '@vegaprotocol/react-helpers'; -import { t } from '@vegaprotocol/i18n'; import classNames from 'classnames'; import type { ColDef } from 'ag-grid-community'; +import { useT } from '../use-t'; const defaultProps: AgGridReactProps = { enableCellTextSelection: true, - overlayLoadingTemplate: t('Loading...'), - overlayNoRowsTemplate: t('No data'), suppressCellFocus: true, suppressColumnMoveAnimation: true, }; @@ -26,6 +24,7 @@ export const AgGridThemed = ({ style?: React.CSSProperties; gridRef?: React.ForwardedRef; }) => { + const t = useT(); const { theme } = useThemeSwitcher(); const wrapperClasses = classNames('vega-ag-grid', 'w-full h-full', { @@ -38,6 +37,8 @@ export const AgGridThemed = ({ diff --git a/libs/datagrid/src/lib/cells/order-type-cell.tsx b/libs/datagrid/src/lib/cells/order-type-cell.tsx index 47f462af4..5eb5ba0bd 100644 --- a/libs/datagrid/src/lib/cells/order-type-cell.tsx +++ b/libs/datagrid/src/lib/cells/order-type-cell.tsx @@ -1,9 +1,9 @@ import type { MouseEvent } from 'react'; import { useMemo } from 'react'; import { useCallback } from 'react'; -import { t } from '@vegaprotocol/i18n'; import * as Schema from '@vegaprotocol/types'; import { addDecimalsFormatNumber } from '@vegaprotocol/utils'; +import { useT } from '../use-t'; interface OrderTypeCellProps { value?: Schema.OrderType; @@ -17,6 +17,7 @@ export const OrderTypeCell = ({ onClick, }: OrderTypeCellProps) => { const id = order?.market?.id ?? ''; + const t = useT(); const label = useMemo(() => { if (!order) { @@ -25,7 +26,9 @@ export const OrderTypeCell = ({ if (!value) return '-'; if (order?.icebergOrder) { - return t('%s (Iceberg)', [Schema.OrderTypeMapping[value]]); + return t('{{orderType}} (Iceberg)', { + orderType: Schema.OrderTypeMapping[value], + }); } if (order?.peggedOrder) { @@ -37,14 +40,18 @@ export const OrderTypeCell = ({ order.peggedOrder?.offset, order.market.decimalPlaces ); - return t('%s %s %s Peg limit', [reference, side, offset]); + return t('{{reference}} {{side}} {{offset}} Peg limit', { + reference, + side, + offset, + }); } if (order?.liquidityProvision) { return t('Liquidity provision'); } return Schema.OrderTypeMapping[value]; - }, [order, value]); + }, [order, value, t]); const handleOnClick = useCallback( (ev: MouseEvent) => { diff --git a/libs/datagrid/src/lib/filters/date-range-filter.tsx b/libs/datagrid/src/lib/filters/date-range-filter.tsx index 48b1295e1..ecf03219e 100644 --- a/libs/datagrid/src/lib/filters/date-range-filter.tsx +++ b/libs/datagrid/src/lib/filters/date-range-filter.tsx @@ -14,8 +14,8 @@ import { isValid, } from 'date-fns'; import { formatForInput } from '@vegaprotocol/utils'; -import { t } from '@vegaprotocol/i18n'; import { TradingInputError } from '@vegaprotocol/ui-toolkit'; +import { useT } from '../use-t'; const defaultValue: DateRange = {}; export interface DateRangeFilterProps extends IFilterParams { @@ -27,6 +27,7 @@ export interface DateRangeFilterProps extends IFilterParams { export const DateRangeFilter = forwardRef( (props: DateRangeFilterProps, ref) => { + const t = useT(); const defaultDates = props?.defaultValue || defaultValue; const [value, setValue] = useState(defaultDates); const valueRef = useRef(value); @@ -119,8 +120,10 @@ export const DateRangeFilter = forwardRef( ) { setError( t( - 'The earliest data that can be queried is %s days ago.', - String(props.maxSubDays) + 'The earliest data that can be queried is {{maxSubDays}} days ago.', + { + maxSubDays: String(props.maxSubDays), + } ) ); return false; @@ -137,8 +140,8 @@ export const DateRangeFilter = forwardRef( ) { setError( t( - 'The maximum time range that can be queried is %s days.', - String(props.maxDaysRange) + 'The maximum time range that can be queried is {{maxDaysRange}} days.', + { maxDaysRange: String(props.maxDaysRange) } ) ); return false; diff --git a/libs/datagrid/src/lib/filters/set-filter.tsx b/libs/datagrid/src/lib/filters/set-filter.tsx index ecb4d7660..2a58be5cf 100644 --- a/libs/datagrid/src/lib/filters/set-filter.tsx +++ b/libs/datagrid/src/lib/filters/set-filter.tsx @@ -7,10 +7,11 @@ import { useRef, } from 'react'; import type { IDoesFilterPassParams, IFilterParams } from 'ag-grid-community'; -import { t } from '@vegaprotocol/i18n'; +import { useT } from '../use-t'; export const SetFilter = forwardRef( (props: IFilterParams & { readonly?: boolean }, ref) => { + const t = useT(); const [value, setValue] = useState([]); const valueRef = useRef(value); const { readonly } = props; diff --git a/libs/datagrid/src/lib/pagination.spec.tsx b/libs/datagrid/src/lib/pagination.spec.tsx index 9d7049696..e4082fe6f 100644 --- a/libs/datagrid/src/lib/pagination.spec.tsx +++ b/libs/datagrid/src/lib/pagination.spec.tsx @@ -30,15 +30,6 @@ describe('Pagination', () => { expect(mockOnLoad).toHaveBeenCalled(); }); - it('renders message for a single row', async () => { - const mockOnLoad = jest.fn(); - const count = 1; - render(); - expect(screen.getByText(`${count} row loaded`)).toBeInTheDocument(); - await userEvent.click(screen.getByRole('button', { name: 'Load more' })); - expect(mockOnLoad).toHaveBeenCalled(); - }); - it('renders the data rentention message', () => { render(); expect(screen.getByText(/data node retention/)).toBeInTheDocument(); diff --git a/libs/datagrid/src/lib/pagination.tsx b/libs/datagrid/src/lib/pagination.tsx index c552a87ef..a0b34e66b 100644 --- a/libs/datagrid/src/lib/pagination.tsx +++ b/libs/datagrid/src/lib/pagination.tsx @@ -1,5 +1,5 @@ import { TradingButton as Button } from '@vegaprotocol/ui-toolkit'; -import { t } from '@vegaprotocol/i18n'; +import { useT } from './use-t'; export const Pagination = ({ count, @@ -14,16 +14,19 @@ export const Pagination = ({ hasDisplayedRows: boolean; showRetentionMessage: boolean; }) => { + const t = useT(); let rowMessage = ''; if (count && !pageInfo?.hasNextPage) { - rowMessage = t('all %s rows loaded', count.toString()); + rowMessage = t('paginationAllLoaded', { + replace: { count }, + defaultValue: 'All {{count}} rows loaded', + }); } else { - if (count === 1) { - rowMessage = t('%s row loaded', count.toString()); - } else { - rowMessage = t('%s rows loaded', count.toString()); - } + rowMessage = t('paginationLoaded', { + replace: { count }, + defaultValue: '{{count}} rows loaded', + }); } return ( diff --git a/libs/datagrid/src/lib/use-t.ts b/libs/datagrid/src/lib/use-t.ts new file mode 100644 index 000000000..8db1b9e65 --- /dev/null +++ b/libs/datagrid/src/lib/use-t.ts @@ -0,0 +1,2 @@ +import { useTranslation } from 'react-i18next'; +export const useT = () => useTranslation('datagrid').t; diff --git a/libs/deal-ticket/__mocks__/react-i18next.ts b/libs/deal-ticket/__mocks__/react-i18next.ts new file mode 100644 index 000000000..7c2343f52 --- /dev/null +++ b/libs/deal-ticket/__mocks__/react-i18next.ts @@ -0,0 +1,14 @@ +export const useTranslation = () => ({ + t: (label: string, replacements?: Record) => { + let translatedLabel = label; + if (typeof replacements === 'object' && replacements !== null) { + Object.keys(replacements).forEach((key) => { + translatedLabel = translatedLabel.replace( + `{{${key}}}`, + replacements[key] + ); + }); + } + return translatedLabel; + }, +}); diff --git a/libs/deal-ticket/src/components/deal-ticket-validation/margin-warning.tsx b/libs/deal-ticket/src/components/deal-ticket-validation/margin-warning.tsx index 20cf1a8bc..d96f17898 100644 --- a/libs/deal-ticket/src/components/deal-ticket-validation/margin-warning.tsx +++ b/libs/deal-ticket/src/components/deal-ticket-validation/margin-warning.tsx @@ -1,5 +1,4 @@ import { addDecimalsFormatNumber } from '@vegaprotocol/utils'; -import { t } from '@vegaprotocol/i18n'; import { Intent, VegaIcon, @@ -7,6 +6,7 @@ import { Tooltip, TradingButton, } from '@vegaprotocol/ui-toolkit'; +import { useT } from '../../use-t'; interface Props { margin: string; @@ -20,18 +20,19 @@ interface Props { } export const MarginWarning = ({ margin, balance, asset, onDeposit }: Props) => { + const t = useT(); const description = (

- {t('%s %s is currently required.', [ - addDecimalsFormatNumber(margin, asset.decimals), - asset.symbol, - ])} + {t('{{amount}} {{assetSymbol}} is currently required.', { + amount: addDecimalsFormatNumber(margin, asset.decimals), + assetSymbol: asset.symbol, + })}

- {t('You have only %s.', [ - addDecimalsFormatNumber(balance, asset.decimals), - ])} + {t('You have only {{amount}}.', { + amount: addDecimalsFormatNumber(balance, asset.decimals), + })}

{ data-testid="deal-ticket-deposit-dialog-button" type="button" > - {t('Deposit %s', [asset.symbol])} + {t('Deposit {{assetSymbol}}', { assetSymbol: asset.symbol })}
); diff --git a/libs/deal-ticket/src/components/deal-ticket-validation/zero-balance-error.tsx b/libs/deal-ticket/src/components/deal-ticket-validation/zero-balance-error.tsx index be2faa437..75d29bfa2 100644 --- a/libs/deal-ticket/src/components/deal-ticket-validation/zero-balance-error.tsx +++ b/libs/deal-ticket/src/components/deal-ticket-validation/zero-balance-error.tsx @@ -1,5 +1,5 @@ import { Intent, Notification } from '@vegaprotocol/ui-toolkit'; -import { t } from '@vegaprotocol/i18n'; +import { useT } from '../../use-t'; interface ZeroBalanceErrorProps { asset: { @@ -13,6 +13,7 @@ export const ZeroBalanceError = ({ asset, onDeposit, }: ZeroBalanceErrorProps) => { + const t = useT(); return ( {t( - 'You need %s in your wallet to trade in this market. ', - asset.symbol + 'You need {{symbol}} in your wallet to trade in this market.', + asset )} } diff --git a/libs/deal-ticket/src/components/deal-ticket/deal-ticket-container.tsx b/libs/deal-ticket/src/components/deal-ticket/deal-ticket-container.tsx index 4ae9a04f7..2a6f428d9 100644 --- a/libs/deal-ticket/src/components/deal-ticket/deal-ticket-container.tsx +++ b/libs/deal-ticket/src/components/deal-ticket/deal-ticket-container.tsx @@ -10,9 +10,9 @@ import { useMarketPrice, } from '@vegaprotocol/markets'; import { AsyncRendererInline } from '@vegaprotocol/ui-toolkit'; -import { t } from '@vegaprotocol/i18n'; import { DealTicket } from './deal-ticket'; import { FLAGS } from '@vegaprotocol/environment'; +import { useT } from '../../use-t'; interface DealTicketContainerProps { marketId: string; @@ -24,6 +24,7 @@ export const DealTicketContainer = ({ marketId, ...props }: DealTicketContainerProps) => { + const t = useT(); const showStopOrder = useDealTicketFormValues((state) => isStopOrderType(state.formValues[marketId]?.type) ); diff --git a/libs/deal-ticket/src/components/deal-ticket/deal-ticket-fee-details.tsx b/libs/deal-ticket/src/components/deal-ticket/deal-ticket-fee-details.tsx index 075d3225f..31ee6b37a 100644 --- a/libs/deal-ticket/src/components/deal-ticket/deal-ticket-fee-details.tsx +++ b/libs/deal-ticket/src/components/deal-ticket/deal-ticket-fee-details.tsx @@ -1,5 +1,4 @@ import { useCallback, useState } from 'react'; -import { t } from '@vegaprotocol/i18n'; import { getAsset, getQuoteName } from '@vegaprotocol/markets'; import type { OrderSubmissionBody } from '@vegaprotocol/wallet'; import { useVegaWallet } from '@vegaprotocol/wallet'; @@ -41,8 +40,10 @@ import classNames from 'classnames'; import BigNumber from 'bignumber.js'; import { FeesBreakdown } from '../fees-breakdown'; import { getTotalDiscountFactor, getDiscountedFee } from '../discounts'; +import { useT, ns } from '../../use-t'; +import { Trans } from 'react-i18next'; -const emptyValue = '-'; +export const emptyValue = '-'; export interface DealTicketFeeDetailsProps { assetSymbol: string; @@ -57,6 +58,7 @@ export const DealTicketFeeDetails = ({ market, isMarketInAuction, }: DealTicketFeeDetailsProps) => { + const t = useT(); const feeEstimate = useEstimateFees(order, isMarketInAuction); const asset = getAsset(market); const { decimals: assetDecimals, quantum } = asset; @@ -98,7 +100,8 @@ export const DealTicketFeeDetails = ({

{t( - `An estimate of the most you would be expected to pay in fees, in the market's settlement asset ${assetSymbol}. Fees estimated are "taker" fees and will only be payable if the order trades aggressively. Rebate equal to the maker portion will be paid to the trader if the order trades passively.` + 'An estimate of the most you would be expected to pay in fees, in the market\'s settlement asset {{assetSymbol}}. Fees estimated are "taker" fees and will only be payable if the order trades aggressively. Rebate equal to the maker portion will be paid to the trader if the order trades passively.', + { assetSymbol } )}

{ + const t = useT(); const [breakdownDialog, setBreakdownDialog] = useState(false); const { pubKey: partyId } = useVegaWallet(); const { data: currentMargins } = useDataProvider({ @@ -211,7 +215,11 @@ export const DealTicketMarginDetails = ({ quantum )} symbol={assetSymbol} - labelDescription={DEDUCTION_FROM_COLLATERAL_TOOLTIP_TEXT(assetSymbol)} + labelDescription={t( + 'DEDUCTION_FROM_COLLATERAL_TOOLTIP_TEXT', + DEDUCTION_FROM_COLLATERAL_TOOLTIP_TEXT, + { assetSymbol } + )} /> ); projectedMargin = ( @@ -228,7 +236,10 @@ export const DealTicketMarginDetails = ({ quantum )} symbol={assetSymbol} - labelDescription={EST_TOTAL_MARGIN_TOOLTIP_TEXT} + labelDescription={t( + 'EST_TOTAL_MARGIN_TOOLTIP_TEXT', + EST_TOTAL_MARGIN_TOOLTIP_TEXT + )} /> ); } @@ -307,7 +318,13 @@ export const DealTicketMarginDetails = ({ className="flex items-center justify-between w-full gap-2" >
- + {t('Margin required')} @@ -346,15 +363,27 @@ export const DealTicketMarginDetails = ({ quantum )} symbol={assetSymbol} - labelDescription={TOTAL_MARGIN_AVAILABLE( - formatValue(generalAccountBalance, assetDecimals, quantum), - formatValue(marginAccountBalance, assetDecimals, quantum), - formatValue( - currentMargins?.maintenanceLevel, - assetDecimals, - quantum - ), - assetSymbol + labelDescription={t( + 'TOTAL_MARGIN_AVAILABLE', + TOTAL_MARGIN_AVAILABLE, + { + generalAccountBalance: formatValue( + generalAccountBalance, + assetDecimals, + quantum + ), + marginAccountBalance: formatValue( + marginAccountBalance, + assetDecimals, + quantum + ), + marginMaintenance: formatValue( + currentMargins?.maintenanceLevel, + assetDecimals, + quantum + ), + assetSymbol, + } )} /> {deductionFromCollateral} @@ -368,7 +397,10 @@ export const DealTicketMarginDetails = ({ } value={formatValue(marginAccountBalance, assetDecimals)} symbol={assetSymbol} - labelDescription={MARGIN_ACCOUNT_TOOLTIP_TEXT} + labelDescription={t( + 'MARGIN_ACCOUNT_TOOLTIP_TEXT', + MARGIN_ACCOUNT_TOOLTIP_TEXT + )} formattedValue={formatValue( marginAccountBalance, assetDecimals, @@ -386,16 +418,26 @@ export const DealTicketMarginDetails = ({ symbol={quoteName} labelDescription={ <> - {LIQUIDATION_PRICE_ESTIMATE_TOOLTIP_TEXT}{' '} - {t('For full details please see ')} - - {t('liquidation price estimate documentation.')} - + {t( + 'LIQUIDATION_PRICE_ESTIMATE_TOOLTIP_TEXT', + LIQUIDATION_PRICE_ESTIMATE_TOOLTIP_TEXT + )} + {' '} + + + liquidation price estimate documentation + , + ]} + ns={ns} + /> } diff --git a/libs/deal-ticket/src/components/deal-ticket/deal-ticket-margin-details.tsx b/libs/deal-ticket/src/components/deal-ticket/deal-ticket-margin-details.tsx new file mode 100644 index 000000000..ac8c0f4a7 --- /dev/null +++ b/libs/deal-ticket/src/components/deal-ticket/deal-ticket-margin-details.tsx @@ -0,0 +1,354 @@ +import { useCallback, useState } from 'react'; +import { getAsset, getQuoteName } from '@vegaprotocol/markets'; +import { useVegaWallet } from '@vegaprotocol/wallet'; +import { AccountBreakdownDialog } from '@vegaprotocol/accounts'; +import { formatRange, formatValue } from '@vegaprotocol/utils'; +import { marketMarginDataProvider } from '@vegaprotocol/accounts'; +import { useDataProvider } from '@vegaprotocol/data-provider'; +import * as AccordionPrimitive from '@radix-ui/react-accordion'; +import * as Schema from '@vegaprotocol/types'; +import { + MARGIN_DIFF_TOOLTIP_TEXT, + DEDUCTION_FROM_COLLATERAL_TOOLTIP_TEXT, + TOTAL_MARGIN_AVAILABLE, + LIQUIDATION_PRICE_ESTIMATE_TOOLTIP_TEXT, + EST_TOTAL_MARGIN_TOOLTIP_TEXT, + MARGIN_ACCOUNT_TOOLTIP_TEXT, +} from '../../constants'; +import { KeyValue } from './key-value'; +import { + Accordion, + AccordionChevron, + AccordionPanel, + ExternalLink, + Tooltip, +} from '@vegaprotocol/ui-toolkit'; +import classNames from 'classnames'; +import { useT, ns } from '../../use-t'; +import { Trans } from 'react-i18next'; +import type { DealTicketMarginDetailsProps } from './deal-ticket-fee-details'; +import { emptyValue } from './deal-ticket-fee-details'; + +export const DealTicketMarginDetails = ({ + marginAccountBalance, + generalAccountBalance, + assetSymbol, + market, + onMarketClick, + positionEstimate, + side, +}: DealTicketMarginDetailsProps) => { + const t = useT(); + const [breakdownDialog, setBreakdownDialog] = useState(false); + const { pubKey: partyId } = useVegaWallet(); + const { data: currentMargins } = useDataProvider({ + dataProvider: marketMarginDataProvider, + variables: { marketId: market.id, partyId: partyId || '' }, + skip: !partyId, + }); + const liquidationEstimate = positionEstimate?.liquidation; + const marginEstimate = positionEstimate?.margin; + const totalBalance = + BigInt(generalAccountBalance || '0') + BigInt(marginAccountBalance || '0'); + const asset = getAsset(market); + const { decimals: assetDecimals, quantum } = asset; + let marginRequiredBestCase: string | undefined = undefined; + let marginRequiredWorstCase: string | undefined = undefined; + if (marginEstimate) { + if (currentMargins) { + marginRequiredBestCase = ( + BigInt(marginEstimate.bestCase.initialLevel) - + BigInt(currentMargins.initialLevel) + ).toString(); + if (marginRequiredBestCase.startsWith('-')) { + marginRequiredBestCase = '0'; + } + marginRequiredWorstCase = ( + BigInt(marginEstimate.worstCase.initialLevel) - + BigInt(currentMargins.initialLevel) + ).toString(); + if (marginRequiredWorstCase.startsWith('-')) { + marginRequiredWorstCase = '0'; + } + } else { + marginRequiredBestCase = marginEstimate.bestCase.initialLevel; + marginRequiredWorstCase = marginEstimate.worstCase.initialLevel; + } + } + + const totalMarginAvailable = ( + currentMargins + ? totalBalance - BigInt(currentMargins.maintenanceLevel) + : totalBalance + ).toString(); + + let deductionFromCollateral = null; + let projectedMargin = null; + if (marginAccountBalance) { + const deductionFromCollateralBestCase = + BigInt(marginEstimate?.bestCase.initialLevel ?? 0) - + BigInt(marginAccountBalance); + + const deductionFromCollateralWorstCase = + BigInt(marginEstimate?.worstCase.initialLevel ?? 0) - + BigInt(marginAccountBalance); + + deductionFromCollateral = ( + 0 + ? deductionFromCollateralBestCase.toString() + : '0', + deductionFromCollateralWorstCase > 0 + ? deductionFromCollateralWorstCase.toString() + : '0', + assetDecimals + )} + formattedValue={formatValue( + deductionFromCollateralWorstCase > 0 + ? deductionFromCollateralWorstCase.toString() + : '0', + assetDecimals, + quantum + )} + symbol={assetSymbol} + labelDescription={t( + 'DEDUCTION_FROM_COLLATERAL_TOOLTIP_TEXT', + DEDUCTION_FROM_COLLATERAL_TOOLTIP_TEXT, + { assetSymbol } + )} + /> + ); + projectedMargin = ( + + ); + } + + let liquidationPriceEstimate = emptyValue; + let liquidationPriceEstimateRange = emptyValue; + + if (liquidationEstimate) { + const liquidationEstimateBestCaseIncludingBuyOrders = BigInt( + liquidationEstimate.bestCase.including_buy_orders.replace(/\..*/, '') + ); + const liquidationEstimateBestCaseIncludingSellOrders = BigInt( + liquidationEstimate.bestCase.including_sell_orders.replace(/\..*/, '') + ); + const liquidationEstimateBestCase = + side === Schema.Side.SIDE_BUY + ? liquidationEstimateBestCaseIncludingBuyOrders + : liquidationEstimateBestCaseIncludingSellOrders; + + const liquidationEstimateWorstCaseIncludingBuyOrders = BigInt( + liquidationEstimate.worstCase.including_buy_orders.replace(/\..*/, '') + ); + const liquidationEstimateWorstCaseIncludingSellOrders = BigInt( + liquidationEstimate.worstCase.including_sell_orders.replace(/\..*/, '') + ); + const liquidationEstimateWorstCase = + side === Schema.Side.SIDE_BUY + ? liquidationEstimateWorstCaseIncludingBuyOrders + : liquidationEstimateWorstCaseIncludingSellOrders; + + liquidationPriceEstimate = formatValue( + liquidationEstimateWorstCase.toString(), + market.decimalPlaces, + undefined, + market.decimalPlaces + ); + liquidationPriceEstimateRange = formatRange( + (liquidationEstimateBestCase < liquidationEstimateWorstCase + ? liquidationEstimateBestCase + : liquidationEstimateWorstCase + ).toString(), + (liquidationEstimateBestCase > liquidationEstimateWorstCase + ? liquidationEstimateBestCase + : liquidationEstimateWorstCase + ).toString(), + market.decimalPlaces, + undefined, + market.decimalPlaces + ); + } + + const onAccountBreakdownDialogClose = useCallback( + () => setBreakdownDialog(false), + [] + ); + + const quoteName = getQuoteName(market); + + return ( +
+ + +
+
+ + {t('Margin required')} + + + +
+ +
+ {formatValue( + marginRequiredWorstCase, + assetDecimals, + quantum + )}{' '} + {assetSymbol || ''} +
+
+
+ + } + > +
+ + {deductionFromCollateral} + setBreakdownDialog(true) + : undefined + } + value={formatValue(marginAccountBalance, assetDecimals)} + symbol={assetSymbol} + labelDescription={t( + 'MARGIN_ACCOUNT_TOOLTIP_TEXT', + MARGIN_ACCOUNT_TOOLTIP_TEXT + )} + formattedValue={formatValue( + marginAccountBalance, + assetDecimals, + quantum + )} + /> +
+
+
+ {projectedMargin} + + + {t( + 'LIQUIDATION_PRICE_ESTIMATE_TOOLTIP_TEXT', + LIQUIDATION_PRICE_ESTIMATE_TOOLTIP_TEXT + )} + {' '} + + + liquidation price estimate documentation + , + ]} + ns={ns} + /> + + + } + /> + {partyId && ( + + )} +
+ ); +}; diff --git a/libs/deal-ticket/src/components/deal-ticket/deal-ticket-size-iceberg.tsx b/libs/deal-ticket/src/components/deal-ticket/deal-ticket-size-iceberg.tsx index ede1043bc..19fc6b265 100644 --- a/libs/deal-ticket/src/components/deal-ticket/deal-ticket-size-iceberg.tsx +++ b/libs/deal-ticket/src/components/deal-ticket/deal-ticket-size-iceberg.tsx @@ -2,13 +2,13 @@ import { Controller, type Control } from 'react-hook-form'; import type { Market } from '@vegaprotocol/markets'; import type { OrderFormValues } from '../../hooks/use-form-values'; import { toDecimal, validateAmount } from '@vegaprotocol/utils'; -import { t } from '@vegaprotocol/i18n'; import { TradingFormGroup, TradingInput, TradingInputError, Tooltip, } from '@vegaprotocol/ui-toolkit'; +import { useT } from '../../use-t'; export interface DealTicketSizeIcebergProps { control: Control; @@ -27,6 +27,7 @@ export const DealTicketSizeIceberg = ({ size, peakSize, }: DealTicketSizeIcebergProps) => { + const t = useT(); const sizeStep = toDecimal(market?.positionDecimalPlaces); const renderPeakSizeError = () => { @@ -81,13 +82,15 @@ export const DealTicketSizeIceberg = ({ required: t('You need to provide a peak size'), min: { value: sizeStep, - message: t('Peak size cannot be lower than ' + sizeStep), + message: t('Peak size cannot be lower than {{stepSize}}', { + sizeStep, + }), }, max: { value: size, message: t( - 'Peak size cannot be greater than the size (%s) ', - [size] + 'Peak size cannot be greater than the size ({{size}})', + { size } ), }, validate: validateAmount(sizeStep, 'peakSize'), @@ -138,14 +141,15 @@ export const DealTicketSizeIceberg = ({ min: { value: sizeStep, message: t( - 'Minimum visible size cannot be lower than ' + sizeStep + 'Minimum visible size cannot be lower than {{sizeStep}}', + { sizeStep } ), }, max: peakSize && { value: peakSize, message: t( - 'Minimum visible size cannot be greater than the peak size (%s)', - [peakSize] + 'Minimum visible size cannot be greater than the peak size ({{peakSize}})', + { peakSize } ), }, validate: validateAmount(sizeStep, 'minimumVisibleSize'), diff --git a/libs/deal-ticket/src/components/deal-ticket/deal-ticket-stop-order.tsx b/libs/deal-ticket/src/components/deal-ticket/deal-ticket-stop-order.tsx index 6c61b3448..9a6b71657 100644 --- a/libs/deal-ticket/src/components/deal-ticket/deal-ticket-stop-order.tsx +++ b/libs/deal-ticket/src/components/deal-ticket/deal-ticket-stop-order.tsx @@ -34,7 +34,6 @@ import { getQuoteName, type Market, } from '@vegaprotocol/markets'; -import { t } from '@vegaprotocol/i18n'; import { ExpirySelector } from './expiry-selector'; import { SideSelector } from './side-selector'; import { timeInForceLabel } from '@vegaprotocol/orders'; @@ -60,6 +59,7 @@ import { NOTIONAL_SIZE_TOOLTIP_TEXT } from '../../constants'; import { KeyValue } from './key-value'; import { useDataProvider } from '@vegaprotocol/data-provider'; import { stopOrdersProvider } from '@vegaprotocol/orders'; +import { useT } from '../../use-t'; export interface StopOrderProps { market: Market; @@ -109,6 +109,7 @@ const Trigger = ({ marketPrice?: string | null; decimalPlaces: number; }) => { + const t = useT(); const triggerType = watch(oco ? 'ocoTriggerType' : 'triggerType'); const triggerDirection = watch('triggerDirection'); const isPriceTrigger = triggerType === 'price'; @@ -161,7 +162,9 @@ const Trigger = ({ required: t('You need provide a price'), min: { value: priceStep, - message: t('Price cannot be lower than ' + priceStep), + message: t('Price cannot be lower than {{priceStep}}', { + priceStep, + }), }, validate: validateAmount(priceStep, 'Price'), }} @@ -244,8 +247,8 @@ const Trigger = ({ min: { value: trailingPercentOffsetStep, message: t( - 'Trailing percent offset cannot be lower than ' + - trailingPercentOffsetStep + 'Trailing percent offset cannot be lower than {{trailingPercentOffsetStep}}', + { trailingPercentOffsetStep } ), }, max: { @@ -338,6 +341,7 @@ const Size = ({ isLimitType: boolean; assetUnit?: string; }) => { + const t = useT(); return ( { + const t = useT(); if (watch(oco ? 'ocoType' : 'type') === Schema.OrderType.TYPE_MARKET) { return null; } @@ -409,7 +414,7 @@ const Price = ({ required: t('You need provide a price'), min: { value: priceStep, - message: t('Price cannot be lower than ' + priceStep), + message: t('Price cannot be lower than {{priceStep}}', { priceStep }), }, validate: validateAmount(priceStep, 'Price'), }} @@ -452,59 +457,65 @@ const TimeInForce = ({ }: { control: Control; oco?: boolean; -}) => ( - { - const id = `order-tif${oco ? '-oco' : ''}`; - return ( -
- - - {timeInForceLabel(Schema.OrderTimeInForce.TIME_IN_FORCE_IOC)} - - - - - {fieldState.error && ( - - {fieldState.error.message} - - )} -
- ); - }} - /> -); + + + + + {fieldState.error && ( + + {fieldState.error.message} + + )} +
+ ); + }} + /> + ); +}; -const ReduceOnly = () => ( - {t(REDUCE_ONLY_TOOLTIP)}}> -
- -
-
-); +const ReduceOnly = () => { + const t = useT(); + return ( + {t(REDUCE_ONLY_TOOLTIP)}}> +
+ +
+
+ ); +}; const NotionalAndFees = ({ market, @@ -522,6 +533,7 @@ const NotionalAndFees = ({ > & Pick & Pick) => { + const t = useT(); const quoteName = getQuoteName(market); const asset = getAsset(market); const isPriceTrigger = triggerType === 'price'; @@ -548,7 +560,11 @@ const NotionalAndFees = ({ value={formatValue(notionalSize, market.decimalPlaces)} formattedValue={formatValue(notionalSize, market.decimalPlaces)} symbol={quoteName} - labelDescription={NOTIONAL_SIZE_TOOLTIP_TEXT(quoteName)} + labelDescription={t( + 'NOTIONAL_SIZE_TOOLTIP_TEXT', + NOTIONAL_SIZE_TOOLTIP_TEXT, + { quoteName } + )} /> & { - assetUnit?: string; - decimalPlaces: number; - positionDecimalPlaces: number; - quoteName: string; -}) => +const formatSizeAtPrice = ( + { + assetUnit, + decimalPlaces, + positionDecimalPlaces, + price, + quoteName, + side, + size, + type, + }: Pick & { + assetUnit?: string; + decimalPlaces: number; + positionDecimalPlaces: number; + quoteName: string; + }, + t: ReturnType +) => `${formatValue( removeDecimal(size, positionDecimalPlaces), positionDecimalPlaces )} ${assetUnit} @ ${ type === Schema.OrderType.TYPE_MARKET - ? 'market' + ? t('sizeAtPrice-market', 'market') : `${formatValue( removeDecimal(price || '0', decimalPlaces), decimalPlaces )} ${quoteName}` }`; -const formatTrigger = ({ - decimalPlaces, - triggerDirection, - triggerPrice, - triggerTrailingPercentOffset, - triggerType, - quoteName, -}: Pick< - StopOrderFormValues, - | 'triggerDirection' - | 'triggerType' - | 'triggerPrice' - | 'triggerTrailingPercentOffset' -> & { - decimalPlaces: number; - quoteName: string; -}) => +const formatTrigger = ( + { + decimalPlaces, + triggerDirection, + triggerPrice, + triggerTrailingPercentOffset, + triggerType, + quoteName, + }: Pick< + StopOrderFormValues, + | 'triggerDirection' + | 'triggerType' + | 'triggerPrice' + | 'triggerTrailingPercentOffset' + > & { + decimalPlaces: number; + quoteName: string; + }, + t: ReturnType +) => `${ triggerDirection === Schema.StopOrderTriggerDirection.TRIGGER_DIRECTION_RISES_ABOVE @@ -620,9 +642,12 @@ const formatTrigger = ({ removeDecimal(triggerPrice || '', decimalPlaces), decimalPlaces )} ${quoteName}` - : `${(Number(triggerTrailingPercentOffset) || 0).toFixed(1)}% ${t( - 'trailing' - )}` + : t('{{triggerTrailingPercentOffset}}% trailing', { + triggerTrailingPercentOffset: ( + Number(triggerTrailingPercentOffset) || 0 + ).toFixed(1), + }) + } }`; const SubmitButton = ({ @@ -662,78 +687,97 @@ const SubmitButton = ({ | 'type' > & Pick & { assetUnit?: string }) => { + const t = useT(); const quoteName = getQuoteName(market); const risesAbove = triggerDirection === Schema.StopOrderTriggerDirection.TRIGGER_DIRECTION_RISES_ABOVE; const subLabel = oco ? ( <> - {formatSizeAtPrice({ - assetUnit, - decimalPlaces: market.decimalPlaces, - positionDecimalPlaces: market.positionDecimalPlaces, - price: risesAbove ? price : ocoPrice, - quoteName, - side, - size: risesAbove ? size : ocoSize, - type, - })}{' '} - {formatTrigger({ - decimalPlaces: market.decimalPlaces, - quoteName, - triggerDirection: - Schema.StopOrderTriggerDirection.TRIGGER_DIRECTION_RISES_ABOVE, - triggerPrice: risesAbove ? triggerPrice : ocoTriggerPrice, - triggerTrailingPercentOffset: risesAbove - ? triggerTrailingPercentOffset - : ocoTriggerTrailingPercentOffset, - triggerType: risesAbove ? triggerType : ocoTriggerType, - })} + {formatSizeAtPrice( + { + assetUnit, + decimalPlaces: market.decimalPlaces, + positionDecimalPlaces: market.positionDecimalPlaces, + price: risesAbove ? price : ocoPrice, + quoteName, + side, + size: risesAbove ? size : ocoSize, + type, + }, + t + )}{' '} + {formatTrigger( + { + decimalPlaces: market.decimalPlaces, + quoteName, + triggerDirection: + Schema.StopOrderTriggerDirection.TRIGGER_DIRECTION_RISES_ABOVE, + triggerPrice: risesAbove ? triggerPrice : ocoTriggerPrice, + triggerTrailingPercentOffset: risesAbove + ? triggerTrailingPercentOffset + : ocoTriggerTrailingPercentOffset, + triggerType: risesAbove ? triggerType : ocoTriggerType, + }, + t + )}
- {formatSizeAtPrice({ - assetUnit, - decimalPlaces: market.decimalPlaces, - positionDecimalPlaces: market.positionDecimalPlaces, - price: !risesAbove ? price : ocoPrice, - quoteName, - side, - size: !risesAbove ? size : ocoSize, - type: ocoType, - })}{' '} - {formatTrigger({ - decimalPlaces: market.decimalPlaces, - quoteName, - triggerDirection: - Schema.StopOrderTriggerDirection.TRIGGER_DIRECTION_FALLS_BELOW, - triggerPrice: !risesAbove ? triggerPrice : ocoTriggerPrice, - triggerTrailingPercentOffset: !risesAbove - ? triggerTrailingPercentOffset - : ocoTriggerTrailingPercentOffset, - triggerType: !risesAbove ? triggerType : ocoTriggerType, - })} + {formatSizeAtPrice( + { + assetUnit, + decimalPlaces: market.decimalPlaces, + positionDecimalPlaces: market.positionDecimalPlaces, + price: !risesAbove ? price : ocoPrice, + quoteName, + side, + size: !risesAbove ? size : ocoSize, + type: ocoType, + }, + t + )}{' '} + {formatTrigger( + { + decimalPlaces: market.decimalPlaces, + quoteName, + triggerDirection: + Schema.StopOrderTriggerDirection.TRIGGER_DIRECTION_FALLS_BELOW, + triggerPrice: !risesAbove ? triggerPrice : ocoTriggerPrice, + triggerTrailingPercentOffset: !risesAbove + ? triggerTrailingPercentOffset + : ocoTriggerTrailingPercentOffset, + triggerType: !risesAbove ? triggerType : ocoTriggerType, + }, + t + )} ) : ( <> - {formatSizeAtPrice({ - assetUnit, - decimalPlaces: market.decimalPlaces, - positionDecimalPlaces: market.positionDecimalPlaces, - price, - quoteName, - side, - size, - type, - })} + {formatSizeAtPrice( + { + assetUnit, + decimalPlaces: market.decimalPlaces, + positionDecimalPlaces: market.positionDecimalPlaces, + price, + quoteName, + side, + size, + type, + }, + t + )}
{t('Trigger')}{' '} - {formatTrigger({ - decimalPlaces: market.decimalPlaces, - quoteName, - triggerDirection, - triggerPrice, - triggerTrailingPercentOffset, - triggerType, - })} + {formatTrigger( + { + decimalPlaces: market.decimalPlaces, + quoteName, + triggerDirection, + triggerPrice, + triggerTrailingPercentOffset, + triggerType, + }, + t + )} ); return ( @@ -756,6 +800,7 @@ const SubmitButton = ({ }; export const StopOrder = ({ market, marketPrice, submit }: StopOrderProps) => { + const t = useT(); const { pubKey, isReadOnly } = useVegaWallet(); const setType = useDealTicketFormValues((state) => state.setType); const updateStoredFormValues = useDealTicketFormValues( @@ -1087,14 +1132,14 @@ export const StopOrder = ({ market, marketPrice, submit }: StopOrderProps) => { Schema.StopOrderExpiryStrategy.EXPIRY_STRATEGY_SUBMIT } id="expiryStrategy-submit" - label={'Submit'} + label={t('Submit')} /> ); @@ -1107,7 +1152,11 @@ export const StopOrder = ({ market, marketPrice, submit }: StopOrderProps) => { control={control} rules={{ required: t('You need provide a expiry time/date'), - validate: validateExpiration, + validate: validateExpiration( + t( + 'The expiry date that you have entered appears to be in the past' + ) + ), }} render={({ field }) => { const { value, onChange: onSelect } = field; @@ -1131,8 +1180,8 @@ export const StopOrder = ({ market, marketPrice, submit }: StopOrderProps) => { intent={Intent.Warning} testId={'stop-order-warning-limit'} message={t( - 'There is a limit of %s active stop orders per market. Orders submitted above the limit will be immediately rejected.', - [MAX_NUMBER_OF_ACTIVE_STOP_ORDERS.toString()] + 'There is a limit of {{maxNumberOfOrders}} active stop orders per market. Orders submitted above the limit will be immediately rejected.', + { maxNumberOfOrders: MAX_NUMBER_OF_ACTIVE_STOP_ORDERS.toString() } )} />
diff --git a/libs/deal-ticket/src/components/deal-ticket/deal-ticket.tsx b/libs/deal-ticket/src/components/deal-ticket/deal-ticket.tsx index 09e22558f..2aa4cbabf 100644 --- a/libs/deal-ticket/src/components/deal-ticket/deal-ticket.tsx +++ b/libs/deal-ticket/src/components/deal-ticket/deal-ticket.tsx @@ -1,12 +1,9 @@ -import { t } from '@vegaprotocol/i18n'; import * as Schema from '@vegaprotocol/types'; import { type FormEventHandler } from 'react'; import { memo, useCallback, useEffect, useRef, useMemo } from 'react'; import { Controller, useController, useForm } from 'react-hook-form'; -import { - DealTicketFeeDetails, - DealTicketMarginDetails, -} from './deal-ticket-fee-details'; +import { DealTicketFeeDetails } from './deal-ticket-fee-details'; +import { DealTicketMarginDetails } from './deal-ticket-margin-details'; import { ExpirySelector } from './expiry-selector'; import { SideSelector } from './side-selector'; import { TimeInForceSelector } from './time-in-force-selector'; @@ -45,7 +42,6 @@ import { } from '@vegaprotocol/markets'; import { validateExpiration, - validateMarketState, validateMarketTradingMode, validateTimeInForce, validateType, @@ -79,6 +75,7 @@ import noop from 'lodash/noop'; import { isNonPersistentOrder } from '../../utils/time-in-force-persistance'; import { KeyValue } from './key-value'; import { DocsLinks } from '@vegaprotocol/environment'; +import { useT } from '../../use-t'; export const REDUCE_ONLY_TOOLTIP = '"Reduce only" will ensure that this order will not increase the size of an open position. When the order is matched, it will only trade enough volume to bring your open volume towards 0 but never change the direction of your position. If applied to a limit order that is not instantly filled, the order will be stopped.'; @@ -142,6 +139,7 @@ export const DealTicket = ({ submit, onDeposit, }: DealTicketProps) => { + const t = useT(); const { pubKey, isReadOnly } = useVegaWallet(); const setType = useDealTicketFormValues((state) => state.setType); const storedFormValues = useDealTicketFormValues( @@ -287,7 +285,28 @@ export const DealTicket = ({ }; } - const marketStateError = validateMarketState(marketState); + let marketStateError: true | string = true; + + if ( + [ + Schema.MarketState.STATE_SETTLED, + Schema.MarketState.STATE_REJECTED, + Schema.MarketState.STATE_TRADING_TERMINATED, + Schema.MarketState.STATE_CANCELLED, + Schema.MarketState.STATE_CLOSED, + ].includes(marketState) + ) { + marketStateError = t( + `This market is {{marketState}} and not accepting orders`, + { + marketState: + marketState === Schema.MarketState.STATE_TRADING_TERMINATED + ? t('terminated') + : t(Schema.MarketStateMapping[marketState]).toLowerCase(), + } + ); + } + if (marketStateError !== true) { return { message: marketStateError, @@ -307,7 +326,10 @@ export const DealTicket = ({ }; } - const marketTradingModeError = validateMarketTradingMode(marketTradingMode); + const marketTradingModeError = validateMarketTradingMode( + marketTradingMode, + t('Trading terminated') + ); if (marketTradingModeError !== true) { return { message: marketTradingModeError, @@ -317,6 +339,7 @@ export const DealTicket = ({ return undefined; }, [ + t, marketState, marketTradingMode, generalAccountBalance, @@ -404,7 +427,7 @@ export const DealTicket = ({ required: t('You need to provide a size'), min: { value: sizeStep, - message: t('Size cannot be lower than ' + sizeStep), + message: t('Size cannot be lower than {{sizeStep}}', { sizeStep }), }, validate: validateAmount(sizeStep, 'Size'), deps: ['peakSize', 'minimumVisibleSize'], @@ -440,7 +463,9 @@ export const DealTicket = ({ required: t('You need provide a price'), min: { value: priceStep, - message: t('Price cannot be lower than ' + priceStep), + message: t('Price cannot be lower than {{priceStep}}', { + priceStep, + }), }, validate: validateAmount(priceStep, 'Price'), }} @@ -477,7 +502,11 @@ export const DealTicket = ({ value={formatValue(notionalSize, market.decimalPlaces)} formattedValue={formatValue(notionalSize, market.decimalPlaces)} symbol={quoteName} - labelDescription={NOTIONAL_SIZE_TOOLTIP_TEXT(quoteName)} + labelDescription={t( + 'NOTIONAL_SIZE_TOOLTIP_TEXT', + NOTIONAL_SIZE_TOOLTIP_TEXT, + { quoteName } + )} /> { + onSelect={(value: Schema.OrderTimeInForce) => { // If GTT is selected and no expiresAt time is set, or its // behind current time then reset the value to current time const now = Date.now(); @@ -534,7 +563,11 @@ export const DealTicket = ({ control={control} rules={{ required: t('You need provide a expiry time/date'), - validate: validateExpiration, + validate: validateExpiration( + t( + 'The expiry date that you have entered appears to be in the past' + ) + ), }} render={({ field }) => ( - {t(`Trade only a fraction of the order size at once. - After the peak size of the order has traded, the size is reset. This is repeated until the order is cancelled, expires, or its full volume trades away. - For example, an iceberg order with a size of 1000 and a peak size of 100 will effectively be split into 10 orders with a size of 100 each. - Note that the full volume of the order is not hidden and is still reflected in the order book.`)}{' '} + {t( + 'ICEBERG_TOOLTIP', + 'Trade only a fraction of the order size at once. After the peak size of the order has traded, the size is reset. This is repeated until the order is cancelled, expires, or its full volume trades away. For example, an iceberg order with a size of 1000 and a peak size of 100 will effectively be split into 10 orders with a size of 100 each. Note that the full volume of the order is not hidden and is still reflected in the order book.' + )}{' '} {t('Find out more')} {' '} @@ -731,13 +764,14 @@ interface SummaryMessageProps { export const NoWalletWarning = ({ isReadOnly, }: Pick) => { + const t = useT(); if (isReadOnly) { return (
- { + {t( 'You need to connect your own wallet to start trading on this market' - } + )}
); @@ -756,6 +790,7 @@ const SummaryMessage = memo( pubKey, onDeposit, }: SummaryMessageProps) => { + const t = useT(); // Specific error UI for if balance is so we can // render a deposit dialog if (isReadOnly || !pubKey) { diff --git a/libs/deal-ticket/src/components/deal-ticket/expiry-selector.tsx b/libs/deal-ticket/src/components/deal-ticket/expiry-selector.tsx index e1fed1e60..08c6d361e 100644 --- a/libs/deal-ticket/src/components/deal-ticket/expiry-selector.tsx +++ b/libs/deal-ticket/src/components/deal-ticket/expiry-selector.tsx @@ -4,8 +4,8 @@ import { TradingInputError, } from '@vegaprotocol/ui-toolkit'; import { formatForInput } from '@vegaprotocol/utils'; -import { t } from '@vegaprotocol/i18n'; import { useRef } from 'react'; +import { useT } from '../../use-t'; interface ExpirySelectorProps { value?: string; @@ -18,6 +18,7 @@ export const ExpirySelector = ({ onSelect, errorMessage, }: ExpirySelectorProps) => { + const t = useT(); const minDateRef = useRef(new Date()); return ( diff --git a/libs/deal-ticket/src/components/deal-ticket/side-selector.tsx b/libs/deal-ticket/src/components/deal-ticket/side-selector.tsx index afc4d78d8..0c0f512f4 100644 --- a/libs/deal-ticket/src/components/deal-ticket/side-selector.tsx +++ b/libs/deal-ticket/src/components/deal-ticket/side-selector.tsx @@ -1,19 +1,19 @@ -import { t } from '@vegaprotocol/i18n'; import * as Schema from '@vegaprotocol/types'; import * as RadioGroup from '@radix-ui/react-radio-group'; import classNames from 'classnames'; +import { useT } from '../../use-t'; interface SideSelectorProps { value: Schema.Side; onValueChange: (side: Schema.Side) => void; } -const toggles = [ - { label: t('Long'), value: Schema.Side.SIDE_BUY }, - { label: t('Short'), value: Schema.Side.SIDE_SELL }, -]; - export const SideSelector = (props: SideSelectorProps) => { + const t = useT(); + const toggles = [ + { label: t('Long'), value: Schema.Side.SIDE_BUY }, + { label: t('Short'), value: Schema.Side.SIDE_SELL }, + ]; return ( { + const t = useT(); const options = orderType === Schema.OrderType.TYPE_LIMIT ? typeLimitOptions @@ -44,25 +46,30 @@ export const TimeInForceSelector = ({ const renderError = (errorType: string) => { if (errorType === MarketModeValidationType.Auction) { return t( - `Until the auction ends, you can only place GFA, GTT, or GTC limit orders` + 'Until the auction ends, you can only place GFA, GTT, or GTC limit orders' ); } if (errorType === MarketModeValidationType.LiquidityMonitoringAuction) { return ( - {t('This market is in auction until it reaches')}{' '} - - } - > - {t('sufficient liquidity')} - - {'. '} - {t( - `Until the auction ends, you can only place GFA, GTT, or GTC limit orders` - )} + + } + > + sufficient liquidity + , + ]} + t={t} + /> ); } @@ -70,18 +77,23 @@ export const TimeInForceSelector = ({ if (errorType === MarketModeValidationType.PriceMonitoringAuction) { return ( - {t('This market is in auction due to')}{' '} - - } - > - {t('high price volatility')} - - {'. '} - {t( - `Until the auction ends, you can only place GFA, GTT, or GTC limit orders` - )} + + } + > + high price volatility + , + ]} + t={t} + /> ); } diff --git a/libs/deal-ticket/src/components/deal-ticket/type-selector.tsx b/libs/deal-ticket/src/components/deal-ticket/type-selector.tsx index f6fd398f0..711016680 100644 --- a/libs/deal-ticket/src/components/deal-ticket/type-selector.tsx +++ b/libs/deal-ticket/src/components/deal-ticket/type-selector.tsx @@ -1,7 +1,7 @@ import { TradingInputError, SimpleGrid, - Tooltip, + TextChildrenTooltip as Tooltip, TradingDropdown, TradingDropdownContent, TradingDropdownItemIndicator, @@ -12,7 +12,6 @@ import { VegaIcon, VegaIconNames, } from '@vegaprotocol/ui-toolkit'; -import { t } from '@vegaprotocol/i18n'; import type { Market, StaticMarketData } from '@vegaprotocol/markets'; import { compileGridData } from '../trading-mode-tooltip'; import { MarketModeValidationType } from '../../constants'; @@ -20,6 +19,8 @@ import { DealTicketType } from '../../hooks/use-form-values'; import * as RadioGroup from '@radix-ui/react-radio-group'; import classNames from 'classnames'; import { FLAGS } from '@vegaprotocol/environment'; +import { Trans } from 'react-i18next'; +import { useT, ns } from '../../use-t'; interface TypeSelectorProps { value: DealTicketType; @@ -29,19 +30,28 @@ interface TypeSelectorProps { errorMessage?: string; } -const toggles = [ - { label: t('Limit'), value: DealTicketType.Limit }, - { label: t('Market'), value: DealTicketType.Market }, -]; -const options = [ - { label: t('Stop Limit'), value: DealTicketType.StopLimit }, - { label: t('Stop Market'), value: DealTicketType.StopMarket }, -]; +const useToggles = () => { + const t = useT(); + return [ + { label: t('Limit'), value: DealTicketType.Limit }, + { label: t('Market'), value: DealTicketType.Market }, + ]; +}; +const useOptions = () => { + const t = useT(); + return [ + { label: t('Stop Limit'), value: DealTicketType.StopLimit }, + { label: t('Stop Market'), value: DealTicketType.StopMarket }, + ]; +}; export const TypeToggle = ({ value, onValueChange, }: Pick) => { + const t = useT(); + const options = useOptions(); + const toggles = useToggles(); const selectedOption = options.find((t) => t.value === value); return ( @@ -107,7 +117,7 @@ export const TypeToggle = ({ id={`order-type-${itemValue}`} data-testid={`order-type-${itemValue}`} > - {t(label)} + {label} ))} @@ -127,6 +137,7 @@ export const TypeSelector = ({ marketData, errorMessage, }: TypeSelectorProps) => { + const t = useT(); const renderError = (errorType: MarketModeValidationType) => { if (errorType === MarketModeValidationType.Auction) { return t('Only limit orders are permitted when market is in auction'); @@ -135,16 +146,21 @@ export const TypeSelector = ({ if (errorType === MarketModeValidationType.LiquidityMonitoringAuction) { return ( - {t('This market is in auction until it reaches')}{' '} - - } - > - {t('sufficient liquidity')} - - {'. '} - {t('Only limit orders are permitted when market is in auction')} + + } + > + sufficient liquidity + , + ]} + t={t} + /> ); } @@ -152,16 +168,21 @@ export const TypeSelector = ({ if (errorType === MarketModeValidationType.PriceMonitoringAuction) { return ( - {t('This market is in auction due to')}{' '} - - } - > - {t('high price volatility')} - - {'. '} - {t('Only limit orders are permitted when market is in auction')} + + } + > + sufficient liquidity + , + ]} + t={t} + /> ); } diff --git a/libs/deal-ticket/src/components/fees-breakdown/fees-breakdown.tsx b/libs/deal-ticket/src/components/fees-breakdown/fees-breakdown.tsx index ec9855e4e..bfeaad205 100644 --- a/libs/deal-ticket/src/components/fees-breakdown/fees-breakdown.tsx +++ b/libs/deal-ticket/src/components/fees-breakdown/fees-breakdown.tsx @@ -4,9 +4,9 @@ import { addDecimalsFormatNumber, formatNumberPercentage, } from '@vegaprotocol/utils'; -import { t } from '@vegaprotocol/i18n'; import BigNumber from 'bignumber.js'; import { getDiscountedFee } from '../discounts'; +import { useT } from '../../use-t'; const formatValue = ( value: string | number | null | undefined, @@ -59,6 +59,7 @@ export const FeesBreakdown = ({ referralDiscountFactor?: string; volumeDiscountFactor?: string; }) => { + const t = useT(); if (!fees || !totalFeeAmount || totalFeeAmount === '0') return null; const { discountedFee: discountedInfrastructureFee } = getDiscountedFee( diff --git a/libs/deal-ticket/src/components/trading-mode-tooltip/compile-grid-data.tsx b/libs/deal-ticket/src/components/trading-mode-tooltip/compile-grid-data.tsx index 417c1ba78..469fa13c9 100644 --- a/libs/deal-ticket/src/components/trading-mode-tooltip/compile-grid-data.tsx +++ b/libs/deal-ticket/src/components/trading-mode-tooltip/compile-grid-data.tsx @@ -2,15 +2,16 @@ import { getDateTimeFormat, addDecimalsFormatNumber, } from '@vegaprotocol/utils'; -import { t } from '@vegaprotocol/i18n'; import * as Schema from '@vegaprotocol/types'; import { Link as UILink } from '@vegaprotocol/ui-toolkit'; import type { SimpleGridProps } from '@vegaprotocol/ui-toolkit'; import type { ReactNode } from 'react'; import { Link } from 'react-router-dom'; import { getAsset, type Market, type MarketData } from '@vegaprotocol/markets'; +import type { useT } from '../../use-t'; export const compileGridData = ( + t: ReturnType, market: Pick< Market, 'id' | 'tradableInstrument' | 'decimalPlaces' | 'positionDecimalPlaces' diff --git a/libs/deal-ticket/src/components/trading-mode-tooltip/trading-mode-tooltip.tsx b/libs/deal-ticket/src/components/trading-mode-tooltip/trading-mode-tooltip.tsx index 808970218..44988900d 100644 --- a/libs/deal-ticket/src/components/trading-mode-tooltip/trading-mode-tooltip.tsx +++ b/libs/deal-ticket/src/components/trading-mode-tooltip/trading-mode-tooltip.tsx @@ -4,11 +4,11 @@ import classNames from 'classnames'; import { useProposalOfMarketQuery } from '@vegaprotocol/proposals'; import { DocsLinks } from '@vegaprotocol/environment'; import { getDateTimeFormat } from '@vegaprotocol/utils'; -import { t } from '@vegaprotocol/i18n'; import * as Schema from '@vegaprotocol/types'; import { ExternalLink, SimpleGrid } from '@vegaprotocol/ui-toolkit'; import { compileGridData } from './compile-grid-data'; import { useMarket, useStaticMarketData } from '@vegaprotocol/markets'; +import { useT } from '../../use-t'; type TradingModeTooltipProps = { marketId?: string; @@ -23,6 +23,7 @@ export const TradingModeTooltip = ({ skip, skipGrid, }: TradingModeTooltipProps) => { + const t = useT(); const { data: market } = useMarket(marketId); const { data: marketData } = useStaticMarketData(marketId, skip); const { marketTradingMode, trigger } = marketData || {}; @@ -43,7 +44,7 @@ export const TradingModeTooltip = ({ ); const compiledGrid = - !skipGrid && compileGridData(market, marketData, onSelect); + !skipGrid && compileGridData(t, market, marketData, onSelect); switch (marketTradingMode) { case Schema.MarketTradingMode.TRADING_MODE_CONTINUOUS: { @@ -88,10 +89,9 @@ export const TradingModeTooltip = ({ > {`${ Schema.MarketTradingModeMapping[marketTradingMode] - }: ${t( - 'Closing on %s', - getDateTimeFormat().format(enactmentDate) - )}`} + }: ${t('Closing on {{time}}', { + time: getDateTimeFormat().format(enactmentDate), + })}`} )} @@ -118,7 +118,7 @@ export const TradingModeTooltip = ({ return (
{t( - `This market has been suspended via a governance vote and can be resumed or terminated by further votes.` + 'This market has been suspended via a governance vote and can be resumed or terminated by further votes.' )} {DocsLinks && ( diff --git a/libs/deal-ticket/src/constants.ts b/libs/deal-ticket/src/constants.ts index 4d3514a6c..356ed4ebb 100644 --- a/libs/deal-ticket/src/constants.ts +++ b/libs/deal-ticket/src/constants.ts @@ -1,75 +1,32 @@ -import { t } from '@vegaprotocol/i18n'; +export const EST_MARGIN_TOOLTIP_TEXT = `A fraction of the notional position size, in the market's settlement asset {{assetSymbol}}, to cover any potential losses that you may incur. For example, for a notional size of $500, if the margin requirement is 10%, then the estimated margin would be approximately $50.`; +export const EST_TOTAL_MARGIN_TOOLTIP_TEXT = + 'Estimated total margin that will cover open positions, active orders and this order.'; +export const MARGIN_ACCOUNT_TOOLTIP_TEXT = 'Margin account balance.'; +export const MARGIN_DIFF_TOOLTIP_TEXT = + "The additional margin required for your new position (taking into account volume and open orders), compared to your current margin. Measured in the market's settlement asset ({{assetSymbol}})."; +export const DEDUCTION_FROM_COLLATERAL_TOOLTIP_TEXT = + 'To cover the required margin, this amount will be drawn from your general ({{assetSymbol}}) account.'; -export const EST_MARGIN_TOOLTIP_TEXT = (settlementAsset: string) => - t( - `A fraction of the notional position size, in the market's settlement asset %s, to cover any potential losses that you may incur. +export const TOTAL_MARGIN_AVAILABLE = + 'Total margin available = general {{assetSymbol}} balance ({{generalAccountBalance}} {{assetSymbol}}) + margin balance ({{marginAccountBalance}} {{assetSymbol}}) - maintenance level ({{marginMaintenance}} {{assetSymbol}}).'; - For example, for a notional size of $500, if the margin requirement is 10%, then the estimated margin would be approximately $50.`, - [settlementAsset] - ); -export const EST_TOTAL_MARGIN_TOOLTIP_TEXT = t( - 'Estimated total margin that will cover open positions, active orders and this order.' -); -export const MARGIN_ACCOUNT_TOOLTIP_TEXT = t('Margin account balance.'); -export const MARGIN_DIFF_TOOLTIP_TEXT = (settlementAsset: string) => - t( - "The additional margin required for your new position (taking into account volume and open orders), compared to your current margin. Measured in the market's settlement asset (%s).", - [settlementAsset] - ); -export const DEDUCTION_FROM_COLLATERAL_TOOLTIP_TEXT = ( - settlementAsset: string -) => - t( - 'To cover the required margin, this amount will be drawn from your general (%s) account.', - [settlementAsset] - ); +export const CONTRACTS_MARGIN_TOOLTIP_TEXT = + 'The number of contracts determines how many units of the futures contract to buy or sell. For example, this is similar to buying one share of a listed company. The value of 1 contract is equivalent to the price of the contract. For example, if the current price is $50, then one contract is worth $50.'; +export const EST_CLOSEOUT_TOOLTIP_TEXT = + 'If the price drops below this number, measured in the market price quote unit {{quote}}, you will be closed out, based on your current position and account balance.'; +export const NOTIONAL_SIZE_TOOLTIP_TEXT = + 'The notional size represents the position size in the settlement asset {{quoteName}} of the futures contract. This is calculated by multiplying the number of contracts by the prices of the contract. For example 10 contracts traded at a price of $50 has a notional size of $500.'; +export const EST_FEES_TOOLTIP_TEXT = + 'When you execute a new buy or sell order, you must pay a small amount of commission to the network for doing so. This fee is used to provide income to the node operates of the network and market makers who make prices on the futures market you are trading.'; -export const TOTAL_MARGIN_AVAILABLE = ( - generalAccountBalance: string, - marginAccountBalance: string, - marginMaintenance: string, - settlementAsset: string -) => - t( - 'Total margin available = general %s balance (%s) + margin balance (%s) - maintenance level (%s).', - [ - settlementAsset, - `${generalAccountBalance} ${settlementAsset}`, - `${marginAccountBalance} ${settlementAsset}`, - `${marginMaintenance} ${settlementAsset}`, - ] - ); +export const LIQUIDATION_PRICE_ESTIMATE_TOOLTIP_TEXT = + 'This is an approximation for the liquidation price for that particular contract position, assuming nothing else changes, which may affect your margin and collateral balances.'; -export const CONTRACTS_MARGIN_TOOLTIP_TEXT = t( - 'The number of contracts determines how many units of the futures contract to buy or sell. For example, this is similar to buying one share of a listed company. The value of 1 contract is equivalent to the price of the contract. For example, if the current price is $50, then one contract is worth $50.' -); -export const EST_CLOSEOUT_TOOLTIP_TEXT = (quote: string) => - t( - `If the price drops below this number, measured in the market price quote unit %s, you will be closed out, based on your current position and account balance.`, - [quote] - ); -export const NOTIONAL_SIZE_TOOLTIP_TEXT = (settlementAsset: string) => - t( - `The notional size represents the position size in the settlement asset %s of the futures contract. This is calculated by multiplying the number of contracts by the prices of the contract. +export const EST_SLIPPAGE = + 'When you execute a trade on Vega, the price obtained in the market may differ from the best available price displayed at the time of placing the trade. The estimated slippage shows the difference between the best available price and the estimated execution price, determined by market liquidity and your chosen order size.'; - For example 10 contracts traded at a price of $50 has a notional size of $500.`, - [settlementAsset] - ); -export const EST_FEES_TOOLTIP_TEXT = t( - 'When you execute a new buy or sell order, you must pay a small amount of commission to the network for doing so. This fee is used to provide income to the node operates of the network and market makers who make prices on the futures market you are trading.' -); - -export const LIQUIDATION_PRICE_ESTIMATE_TOOLTIP_TEXT = t( - 'This is an approximation for the liquidation price for that particular contract position, assuming nothing else changes, which may affect your margin and collateral balances.' -); - -export const EST_SLIPPAGE = t( - 'When you execute a trade on Vega, the price obtained in the market may differ from the best available price displayed at the time of placing the trade. The estimated slippage shows the difference between the best available price and the estimated execution price, determined by market liquidity and your chosen order size.' -); - -export const ERROR_SIZE_DECIMAL = t( - 'The size field accepts up to X decimal places.' -); +export const ERROR_SIZE_DECIMAL = + 'The size field accepts up to X decimal places.'; export enum MarketModeValidationType { PriceMonitoringAuction = 'PriceMonitoringAuction', diff --git a/libs/deal-ticket/src/use-t.ts b/libs/deal-ticket/src/use-t.ts new file mode 100644 index 000000000..4659c0176 --- /dev/null +++ b/libs/deal-ticket/src/use-t.ts @@ -0,0 +1,3 @@ +import { useTranslation } from 'react-i18next'; +export const ns = 'deal-ticket'; +export const useT = () => useTranslation(ns).t; diff --git a/libs/deal-ticket/src/utils/index.ts b/libs/deal-ticket/src/utils/index.ts index a4d8c7ce4..2c20d5ec3 100644 --- a/libs/deal-ticket/src/utils/index.ts +++ b/libs/deal-ticket/src/utils/index.ts @@ -1,6 +1,5 @@ export * from './get-default-order'; export * from './validate-expiration'; -export * from './validate-market-state'; export * from './validate-market-trading-mode'; export * from './validate-time-in-force'; export * from './validate-type'; diff --git a/libs/deal-ticket/src/utils/validate-expiration.ts b/libs/deal-ticket/src/utils/validate-expiration.ts index 97ec79ad5..b5f7e9f03 100644 --- a/libs/deal-ticket/src/utils/validate-expiration.ts +++ b/libs/deal-ticket/src/utils/validate-expiration.ts @@ -1,13 +1,13 @@ -import { t } from '@vegaprotocol/i18n'; import type { Validate } from 'react-hook-form'; -export const validateExpiration: Validate = ( - value?: string -) => { - const now = new Date(); - const valueAsDate = value ? new Date(value) : now; - if (now > valueAsDate) { - return t('The expiry date that you have entered appears to be in the past'); - } - return true; -}; +export const validateExpiration: ( + errorMessage: string +) => Validate = + (errorMessage: string) => (value?: string) => { + const now = new Date(); + const valueAsDate = value ? new Date(value) : now; + if (now > valueAsDate) { + return errorMessage; + } + return true; + }; diff --git a/libs/deal-ticket/src/utils/validate-market-state.ts b/libs/deal-ticket/src/utils/validate-market-state.ts deleted file mode 100644 index 4e87c55d2..000000000 --- a/libs/deal-ticket/src/utils/validate-market-state.ts +++ /dev/null @@ -1,37 +0,0 @@ -import { t } from '@vegaprotocol/i18n'; -import { MarketState, MarketStateMapping } from '@vegaprotocol/types'; - -export const validateMarketState = (state: MarketState) => { - if ( - [ - MarketState.STATE_SETTLED, - MarketState.STATE_REJECTED, - MarketState.STATE_TRADING_TERMINATED, - MarketState.STATE_CANCELLED, - MarketState.STATE_CLOSED, - ].includes(state) - ) { - return t( - `This market is ${marketTranslations(state)} and not accepting orders` - ); - } - - if (state === MarketState.STATE_PROPOSED) { - return t( - `This market is ${marketTranslations( - state - )} and only accepting liquidity commitment orders` - ); - } - - return true; -}; - -const marketTranslations = (marketState: MarketState) => { - switch (marketState) { - case MarketState.STATE_TRADING_TERMINATED: - return t('terminated'); - default: - return t(MarketStateMapping[marketState]).toLowerCase(); - } -}; diff --git a/libs/deal-ticket/src/utils/validate-market-trading-mode.ts b/libs/deal-ticket/src/utils/validate-market-trading-mode.ts index 7bff037a6..12f125dbf 100644 --- a/libs/deal-ticket/src/utils/validate-market-trading-mode.ts +++ b/libs/deal-ticket/src/utils/validate-market-trading-mode.ts @@ -1,11 +1,11 @@ -import { t } from '@vegaprotocol/i18n'; import { MarketTradingMode } from '@vegaprotocol/types'; export const validateMarketTradingMode = ( - marketTradingMode: MarketTradingMode + marketTradingMode: MarketTradingMode, + errorMessage: string ) => { if (marketTradingMode === MarketTradingMode.TRADING_MODE_NO_TRADING) { - return t('Trading terminated'); + return errorMessage; } return true; diff --git a/libs/deposits/__mocks__/react-i18next.ts b/libs/deposits/__mocks__/react-i18next.ts new file mode 100644 index 000000000..7c2343f52 --- /dev/null +++ b/libs/deposits/__mocks__/react-i18next.ts @@ -0,0 +1,14 @@ +export const useTranslation = () => ({ + t: (label: string, replacements?: Record) => { + let translatedLabel = label; + if (typeof replacements === 'object' && replacements !== null) { + Object.keys(replacements).forEach((key) => { + translatedLabel = translatedLabel.replace( + `{{${key}}}`, + replacements[key] + ); + }); + } + return translatedLabel; + }, +}); diff --git a/libs/deposits/src/lib/approve-notification.tsx b/libs/deposits/src/lib/approve-notification.tsx index c1bac5c84..16bc87cb1 100644 --- a/libs/deposits/src/lib/approve-notification.tsx +++ b/libs/deposits/src/lib/approve-notification.tsx @@ -1,6 +1,5 @@ import type { Asset } from '@vegaprotocol/assets'; import { EtherscanLink } from '@vegaprotocol/environment'; -import { t } from '@vegaprotocol/i18n'; import { Intent, Notification } from '@vegaprotocol/ui-toolkit'; import { formatNumber, @@ -11,6 +10,7 @@ import type { EthStoredTxState } from '@vegaprotocol/web3'; import { EthTxStatus, useEthTransactionStore } from '@vegaprotocol/web3'; import BigNumber from 'bignumber.js'; import type { DepositBalances } from './use-deposit-balances'; +import { useT } from './use-t'; interface ApproveNotificationProps { isActive: boolean; @@ -33,6 +33,7 @@ export const ApproveNotification = ({ approveTxId, intent = Intent.Warning, }: ApproveNotificationProps) => { + const t = useT(); const tx = useEthTransactionStore((state) => { return state.transactions.find((t) => t?.id === approveTxId); }); @@ -55,12 +56,14 @@ export const ApproveNotification = ({ intent={intent} testId="approve-default" message={t( - 'Before you can make a deposit of your chosen asset, %s, you need to approve its use in your Ethereum wallet', - selectedAsset?.symbol + 'Before you can make a deposit of your chosen asset, {{assetSymbol}}, you need to approve its use in your Ethereum wallet', + { assetSymbol: selectedAsset?.symbol } )} buttonProps={{ size: 'small', - text: t('Approve %s', selectedAsset?.symbol), + text: t('Approve {{assetSymbol}}', { + assetSymbol: selectedAsset?.symbol, + }), action: onApprove, dataTestId: 'approve-submit', }} @@ -72,13 +75,14 @@ export const ApproveNotification = ({ { + const t = useT(); if (!tx) return null; const txLink = tx.txHash && ( @@ -161,8 +166,8 @@ const ApprovalTxFeedback = ({ intent={Intent.Warning} testId="approve-requested" message={t( - 'Go to your Ethereum wallet and approve the transaction to enable the use of %s', - selectedAsset?.symbol + 'Go to your Ethereum wallet and approve the transaction to enable the use of {{assetSymbol}}', + { assetSymbol: selectedAsset?.symbol } )} />
@@ -179,8 +184,8 @@ const ApprovalTxFeedback = ({ <>

{t( - 'Your %s approval is being confirmed by the Ethereum network. When this is complete, you can continue your deposit', - selectedAsset?.symbol + 'Your {{assetSymbol}} approval is being confirmed by the Ethereum network. When this is complete, you can continue your deposit', + { assetSymbol: selectedAsset?.symbol } )}{' '}

{txLink &&

{txLink}

} @@ -209,10 +214,15 @@ const ApprovalTxFeedback = ({ message={ <>

- {t('You approved deposits of up to %s %s.', [ - selectedAsset?.symbol, - approvedAllowanceValue, - ])} + {t( + 'You approved deposits of up to {{assetSymbol}} {{approvedAllowanceValue}}.', + [ + { + assetSymbol: selectedAsset?.symbol, + approvedAllowanceValue, + }, + ] + )}

{txLink &&

{txLink}

} diff --git a/libs/deposits/src/lib/deposit-form.tsx b/libs/deposits/src/lib/deposit-form.tsx index 0bee8999f..43b5c6a29 100644 --- a/libs/deposits/src/lib/deposit-form.tsx +++ b/libs/deposits/src/lib/deposit-form.tsx @@ -10,7 +10,6 @@ import { isAssetTypeERC20, formatNumber, } from '@vegaprotocol/utils'; -import { t } from '@vegaprotocol/i18n'; import { useLocalStorage } from '@vegaprotocol/react-helpers'; import { TradingFormGroup, @@ -43,6 +42,7 @@ import { FaucetNotification } from './faucet-notification'; import { ApproveNotification } from './approve-notification'; import { usePersistentDeposit } from './use-persistent-deposit'; import { AssetBalance } from './asset-balance'; +import { useT } from './use-t'; interface FormFields { asset: string; @@ -84,6 +84,7 @@ export const DepositForm = ({ approveTxId, isFaucetable, }: DepositFormProps) => { + const t = useT(); const { open: openAssetDetailsDialog } = useAssetDetailsDialogStore(); const openDialog = useWeb3ConnectStore((store) => store.open); const { isActive, account } = useWeb3React(); @@ -284,7 +285,7 @@ export const DepositForm = ({ )} {isActive && isFaucetable && selectedAsset && ( - {t(`Get ${selectedAsset.symbol}`)} + {t('Get {{assetSymbol}}', { assetSymbol: selectedAsset.symbol })} )} {!errors.asset?.message && selectedAsset && ( @@ -325,11 +326,11 @@ export const DepositForm = ({ const allowance = new BigNumber(balances?.allowance || 0); if (value.isGreaterThan(allowance)) { return t( - "You can't deposit more than your approved deposit amount, %s %s", - [ - formatNumber(allowance.toString()), - selectedAsset?.symbol || ' ', - ] + "You can't deposit more than your approved deposit amount, {{amount}} {{assetSymbol}}", + { + amount: formatNumber(allowance.toString()), + assetSymbol: selectedAsset?.symbol || ' ', + } ); } return true; @@ -347,11 +348,11 @@ export const DepositForm = ({ if (value.isGreaterThan(lifetimeLimit)) { return t( - "You can't deposit more than your remaining deposit allowance, %s %s", - [ - formatNumber(lifetimeLimit.toString()), - selectedAsset?.symbol || ' ', - ] + "You can't deposit more than your remaining deposit allowance, {{amount}} {{assetSymbol}}", + { + amount: formatNumber(lifetimeLimit.toString()), + assetSymbol: selectedAsset?.symbol || ' ', + } ); } return true; @@ -361,8 +362,11 @@ export const DepositForm = ({ const balance = new BigNumber(balances?.balance || 0); if (value.isGreaterThan(balance)) { return t( - "You can't deposit more than you have in your Ethereum wallet, %s %s", - [formatNumber(balance), selectedAsset?.symbol || ' '] + "You can't deposit more than you have in your Ethereum wallet, {{amount}} {{assetSymbol}}", + { + amount: formatNumber(balance), + assetSymbol: selectedAsset?.symbol || ' ', + } ); } return true; @@ -419,6 +423,7 @@ interface FormButtonProps { } const FormButton = ({ approved, selectedAsset }: FormButtonProps) => { + const t = useT(); const { isActive, chainId } = useWeb3React(); const desiredChainId = useWeb3ConnectStore((store) => store.desiredChainId); const invalidChain = isActive && chainId !== desiredChainId; @@ -429,9 +434,9 @@ const FormButton = ({ approved, selectedAsset }: FormButtonProps) => { )} @@ -464,6 +469,7 @@ const DisconnectEthereumButton = ({ }: { onDisconnect: () => void; }) => { + const t = useT(); const { connector } = useWeb3React(); const [, , removeEagerConnector] = useLocalStorage(ETHEREUM_EAGER_CONNECT); const disconnect = useWeb3Disconnect(connector); @@ -495,6 +501,7 @@ export const AddressField = ({ input, onChange, }: AddressInputProps) => { + const t = useT(); const [isInput, setIsInput] = useState(() => { if (pubKeys && pubKeys.length <= 1) { return true; diff --git a/libs/deposits/src/lib/deposit-limits.tsx b/libs/deposits/src/lib/deposit-limits.tsx index e4054f23d..8bdf03548 100644 --- a/libs/deposits/src/lib/deposit-limits.tsx +++ b/libs/deposits/src/lib/deposit-limits.tsx @@ -1,5 +1,4 @@ import type { Asset } from '@vegaprotocol/assets'; -import { t } from '@vegaprotocol/i18n'; import { CompactNumber } from '@vegaprotocol/react-helpers'; import { KeyValueTable, @@ -8,6 +7,7 @@ import { } from '@vegaprotocol/ui-toolkit'; import type BigNumber from 'bignumber.js'; import { formatNumber, quantumDecimalPlaces } from '@vegaprotocol/utils'; +import { useT } from './use-t'; // Note: all of the values here are with correct asset's decimals // See `libs/deposits/src/lib/use-deposit-balances.ts` @@ -29,6 +29,7 @@ export const DepositLimits = ({ allowance, exempt, }: DepositLimitsProps) => { + const t = useT(); const limits = [ { key: 'BALANCE_AVAILABLE', @@ -51,19 +52,23 @@ export const DepositLimits = ({ <>

{t( - 'VEGA has a lifetime deposit limit of %s %s per address. This can be changed through governance', - [formatNumber(max.toString()), asset.symbol] + 'VEGA has a lifetime deposit limit of {{amount}} {{assetSymbol}} per address. This can be changed through governance', + { + amount: formatNumber(max.toString()), + assetSymbol: asset.symbol, + } )}

{t( - 'To date, %s %s has been deposited from this Ethereum address, so you can deposit up to %s %s more.', - [ - formatNumber(deposited.toString()), - asset.symbol, - formatNumber(max.minus(deposited).toString()), - asset.symbol, - ] + 'To date, {{currentDeposit}} {{assetSymbol}} has been deposited from this Ethereum address, so you can deposit up to {{remainingDeposit}} {{assetSymbol}} more.', + { + currentDeposit: formatNumber(deposited.toString()), + assetSymbol: asset.symbol, + remainingDeposit: formatNumber( + max.minus(deposited).toString() + ), + } )}

@@ -89,8 +94,8 @@ export const DepositLimits = ({ description={

{t( - 'The deposit cap is set when you approve an asset for use with this app. To increase this cap, approve %s again and choose a higher cap. Check the documentation for your Ethereum wallet app for details.', - asset.symbol + 'The deposit cap is set when you approve an asset for use with this app. To increase this cap, approve {{assetSymbol}} again and choose a higher cap. Check the documentation for your Ethereum wallet app for details.', + { assetSymbol: asset.symbol } )}

} diff --git a/libs/deposits/src/lib/faucet-notification.tsx b/libs/deposits/src/lib/faucet-notification.tsx index 24dad8f9e..aa6da10a4 100644 --- a/libs/deposits/src/lib/faucet-notification.tsx +++ b/libs/deposits/src/lib/faucet-notification.tsx @@ -1,11 +1,10 @@ import type { Asset } from '@vegaprotocol/assets'; import { EtherscanLink } from '@vegaprotocol/environment'; -import { t } from '@vegaprotocol/i18n'; import { Intent, Notification } from '@vegaprotocol/ui-toolkit'; import { EthTxStatus, useEthTransactionStore } from '@vegaprotocol/web3'; -import { getFaucetError } from './get-faucet-error'; - -interface FaucetNotificationProps { +import { useGetFaucetError } from './get-faucet-error'; +import { useT } from './use-t'; +export interface FaucetNotificationProps { isActive: boolean; selectedAsset?: Asset; faucetTxId: number | null; @@ -14,14 +13,20 @@ interface FaucetNotificationProps { /** * Render a notification for the faucet transaction */ + export const FaucetNotification = ({ isActive, selectedAsset, faucetTxId, }: FaucetNotificationProps) => { + const t = useT(); const tx = useEthTransactionStore((state) => { return state.transactions.find((t) => t?.id === faucetTxId); }); + const errorMessage = useGetFaucetError( + tx?.status === EthTxStatus.Error ? tx.error : null, + selectedAsset?.symbol + ); if (!isActive) { return null; @@ -34,9 +39,7 @@ export const FaucetNotification = ({ if (!tx) { return null; } - - if (tx.status === EthTxStatus.Error) { - const errorMessage = getFaucetError(tx.error, selectedAsset.symbol); + if (errorMessage) { return (
@@ -72,8 +76,8 @@ export const FaucetNotification = ({ <>

{t( - 'Your request for funds from the %s faucet is being confirmed by the Ethereum network', - selectedAsset.symbol + 'Your request for funds from the {{assetSymbol}} faucet is being confirmed by the Ethereum network', + { assetSymbol: selectedAsset.symbol } )}{' '}

{tx.txHash && ( @@ -100,8 +104,10 @@ export const FaucetNotification = ({ <>

{t( - '%s has been deposited in your Ethereum wallet', - selectedAsset.symbol + '{{assetSymbol}} has been deposited in your Ethereum wallet', + { + assetSymbol: selectedAsset.symbol, + } )}{' '}

{tx.txHash && ( diff --git a/libs/deposits/src/lib/get-faucet-error.ts b/libs/deposits/src/lib/get-faucet-error.ts index 40121c747..61e6f9613 100644 --- a/libs/deposits/src/lib/get-faucet-error.ts +++ b/libs/deposits/src/lib/get-faucet-error.ts @@ -1,13 +1,14 @@ -import { t } from '@vegaprotocol/i18n'; import type { TxError } from '@vegaprotocol/web3'; +import { useT } from './use-t'; -export const getFaucetError = (error: TxError | null, symbol: string) => { +export const useGetFaucetError = (error: TxError | null, symbol?: string) => { + const t = useT(); const reasonMap: { [reason: string]: string; } = { 'faucet not enabled': t( - 'The %s faucet is not available at this time', - symbol + 'The {{symbol}} faucet is not available at this time', + { symbol: symbol || '' } ), 'must wait faucetCallLimit between faucet calls': t( 'You have exceeded the maximum number of faucet attempts allowed' @@ -20,5 +21,5 @@ export const getFaucetError = (error: TxError | null, symbol: string) => { // to a non generic error message return error && 'reason' in error && reasonMap[error.reason] ? reasonMap[error.reason] - : t('Faucet of %s failed', symbol); + : t('Faucet of {{symbol}} failed', { symbol: symbol || '' }); }; diff --git a/libs/deposits/src/lib/use-t.ts b/libs/deposits/src/lib/use-t.ts new file mode 100644 index 000000000..3abb040f7 --- /dev/null +++ b/libs/deposits/src/lib/use-t.ts @@ -0,0 +1,2 @@ +import { useTranslation } from 'react-i18next'; +export const useT = () => useTranslation('deposits').t; diff --git a/libs/environment/__mocks__/react-i18next.ts b/libs/environment/__mocks__/react-i18next.ts new file mode 100644 index 000000000..9a23fc585 --- /dev/null +++ b/libs/environment/__mocks__/react-i18next.ts @@ -0,0 +1,15 @@ +export const useTranslation = () => ({ + t: (label: string, replacements?: Record) => { + const replace = + replacements?.replace && typeof replacements === 'object' + ? replacements?.replace + : replacements; + let translatedLabel = replacements?.defaultValue || label; + if (typeof replace === 'object' && replace !== null) { + Object.keys(replace).forEach((key) => { + translatedLabel = translatedLabel.replace(`{{${key}}}`, replace[key]); + }); + } + return translatedLabel; + }, +}); diff --git a/libs/environment/src/components/etherscan-link.tsx b/libs/environment/src/components/etherscan-link.tsx index 5bedc0107..307d94736 100644 --- a/libs/environment/src/components/etherscan-link.tsx +++ b/libs/environment/src/components/etherscan-link.tsx @@ -1,7 +1,7 @@ -import { t } from '@vegaprotocol/i18n'; import { ExternalLink } from '@vegaprotocol/ui-toolkit'; import type { ComponentProps } from 'react'; import { ETHERSCAN_ADDRESS, ETHERSCAN_TX, useEtherscanLink } from '../hooks'; +import { useT } from '../use-t'; export const EtherscanLink = ({ address, @@ -12,6 +12,7 @@ export const EtherscanLink = ({ address?: string; tx?: string; } & ComponentProps) => { + const t = useT(); const etherscanLink = useEtherscanLink(); let href = ''; diff --git a/libs/environment/src/components/network-switcher/network-switcher.spec.tsx b/libs/environment/src/components/network-switcher/network-switcher.spec.tsx index 136b2614b..745b4bb3e 100644 --- a/libs/environment/src/components/network-switcher/network-switcher.spec.tsx +++ b/libs/environment/src/components/network-switcher/network-switcher.spec.tsx @@ -1,13 +1,7 @@ import { render, screen } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; -import { t } from '@vegaprotocol/i18n'; import { useEnvironment } from '../../hooks/use-environment'; -import { - NetworkSwitcher, - envNameMapping, - envTriggerMapping, - envDescriptionMapping, -} from './'; +import { NetworkSwitcher } from './'; import { Networks } from '../../'; jest.mock('../../hooks/use-environment'); @@ -33,10 +27,10 @@ describe('Network switcher', () => { it.each` network | label - ${Networks.CUSTOM} | ${envTriggerMapping[Networks.CUSTOM]} - ${Networks.DEVNET} | ${envTriggerMapping[Networks.DEVNET]} - ${Networks.TESTNET} | ${envTriggerMapping[Networks.TESTNET]} - ${Networks.MAINNET} | ${envTriggerMapping[Networks.MAINNET]} + ${Networks.CUSTOM} | ${'Custom'} + ${Networks.DEVNET} | ${'Devnet'} + ${Networks.TESTNET} | ${'Fairground'} + ${Networks.MAINNET} | ${'Mainnet'} `( 'displays the correct selection label for $network', ({ network, label }) => { @@ -69,13 +63,13 @@ describe('Network switcher', () => { await userEvent.click(screen.getByRole('button')); let links = screen.getAllByRole('link'); - expect(links[0]).toHaveTextContent(envNameMapping[Networks.MAINNET]); - expect(links[1]).toHaveTextContent(envNameMapping[Networks.TESTNET]); - expect(links[0]).not.toHaveTextContent(t('current')); - expect(links[1]).not.toHaveTextContent(t('current')); - expect(links[0]).not.toHaveTextContent(t('not available')); - expect(links[1]).not.toHaveTextContent(t('not available')); - expect(links[2]).toHaveTextContent(t('Propose a network parameter change')); + expect(links[0]).toHaveTextContent('Mainnet'); + expect(links[1]).toHaveTextContent('Fairground testnet'); + expect(links[0]).not.toHaveTextContent('current'); + expect(links[1]).not.toHaveTextContent('current'); + expect(links[0]).not.toHaveTextContent('not available'); + expect(links[1]).not.toHaveTextContent('not available'); + expect(links[2]).toHaveTextContent('Propose a network parameter change'); const menuitems = screen.getAllByRole('menuitem'); @@ -110,8 +104,8 @@ describe('Network switcher', () => { const links = screen.getAllByRole('link'); - expect(links[0]).toHaveTextContent(envNameMapping[Networks.MAINNET]); - expect(links[0]).toHaveTextContent(t('current')); + expect(links[0]).toHaveTextContent('Mainnet'); + expect(links[0]).toHaveTextContent('current'); }); it('displays the correct selected network on the default dropdown view when it does not have an associated url', async () => { @@ -131,8 +125,8 @@ describe('Network switcher', () => { const links = screen.getAllByRole('link'); - expect(links[0]).toHaveTextContent(envNameMapping[Networks.MAINNET]); - expect(links[0]).toHaveTextContent(t('current')); + expect(links[0]).toHaveTextContent('Mainnet'); + expect(links[0]).toHaveTextContent('current'); }); it('displays the correct state for a network without url on the default dropdown view', async () => { @@ -151,13 +145,17 @@ describe('Network switcher', () => { await userEvent.click(screen.getByRole('button')); const links = screen.getAllByRole('link'); - expect(links[0]).toHaveTextContent(envNameMapping[Networks.MAINNET]); - expect(links[0]).toHaveTextContent(t('not available')); + expect(links[0]).toHaveTextContent('Mainnet'); + expect(links[0]).toHaveTextContent('not available'); }); - it.each([Networks.MAINNET, Networks.TESTNET, Networks.DEVNET])( + it.each([ + { network: Networks.MAINNET, name: 'Mainnet' }, + { network: Networks.TESTNET, name: 'Fairground testnet' }, + { network: Networks.DEVNET, name: 'Devnet' }, + ])( 'displays the advanced view in the correct state', - async (network) => { + async ({ network, name }) => { const VEGA_NETWORKS: Record = { [Networks.CUSTOM]: undefined, [Networks.MAINNET]: 'https://main.net', @@ -178,25 +176,14 @@ describe('Network switcher', () => { await userEvent.click(screen.getByTestId('network-switcher')); expect( - await screen.findByRole('menuitem', { name: t('Advanced') }) + await screen.findByRole('menuitem', { name: 'Advanced' }) ).toBeInTheDocument(); - await userEvent.click( - screen.getByRole('menuitem', { name: t('Advanced') }) - ); - - expect( - await screen.findByText(envDescriptionMapping[network]) - ).toBeInTheDocument(); - expect( - screen.getByRole('link', { - name: new RegExp(`^${envNameMapping[network]}`), - }) - ).toBeInTheDocument(); + await userEvent.click(screen.getByRole('menuitem', { name: 'Advanced' })); await userEvent.click( screen.getByRole('link', { - name: new RegExp(`^${envNameMapping[network]}`), + name: new RegExp(`^${name}`), }) ); @@ -224,15 +211,13 @@ describe('Network switcher', () => { render(); await userEvent.click(screen.getByRole('button')); - await userEvent.click( - screen.getByRole('menuitem', { name: t('Advanced') }) - ); + await userEvent.click(screen.getByRole('menuitem', { name: 'Advanced' })); - const label = screen.getByText(`(${t('current')})`); + const label = screen.getByText('(current)'); expect(label).toBeInTheDocument(); expect(label.parentNode?.parentNode?.firstElementChild).toHaveTextContent( - envNameMapping[selectedNetwork] + 'Devnet' ); }); @@ -262,7 +247,7 @@ describe('Network switcher', () => { expect(label).toBeInTheDocument(); expect(label.parentNode?.parentNode?.firstElementChild).toHaveTextContent( - envNameMapping[Networks.MAINNET] + 'Mainnet' ); }); }); diff --git a/libs/environment/src/components/network-switcher/network-switcher.tsx b/libs/environment/src/components/network-switcher/network-switcher.tsx index 2bcd96028..89664a3a6 100644 --- a/libs/environment/src/components/network-switcher/network-switcher.tsx +++ b/libs/environment/src/components/network-switcher/network-switcher.tsx @@ -1,5 +1,4 @@ import { useState, useCallback } from 'react'; -import { t } from '@vegaprotocol/i18n'; import { DropdownMenu, DropdownMenuContent, @@ -13,32 +12,44 @@ import { useEnvironment } from '../../hooks/use-environment'; import { Networks } from '../../types'; import { DApp, TOKEN_NEW_NETWORK_PARAM_PROPOSAL, useLinks } from '../../hooks'; import classNames from 'classnames'; +import { useT } from '../../use-t'; -export const envNameMapping: Record = { - [Networks.VALIDATOR_TESTNET]: t('VALIDATOR_TESTNET'), - [Networks.MAINNET_MIRROR]: t('Mainnet-mirror'), - [Networks.CUSTOM]: t('Custom'), - [Networks.DEVNET]: t('Devnet'), - [Networks.STAGNET1]: t('Stagnet'), - [Networks.TESTNET]: t('Fairground testnet'), - [Networks.MAINNET]: t('Mainnet'), +export const useEnvNameMapping: () => Record = () => { + const t = useT(); + return { + [Networks.VALIDATOR_TESTNET]: t('VALIDATOR_TESTNET', { + contextSeparator: '|', + }), + [Networks.MAINNET_MIRROR]: t('Mainnet-mirror'), + [Networks.CUSTOM]: t('Custom'), + [Networks.DEVNET]: t('Devnet'), + [Networks.STAGNET1]: t('Stagnet'), + [Networks.TESTNET]: t('Fairground testnet'), + [Networks.MAINNET]: t('Mainnet'), + }; }; -export const envTriggerMapping: Record = { - ...envNameMapping, - [Networks.TESTNET]: t('Fairground'), +export const useEnvTriggerMapping: () => Record = () => { + const t = useT(); + return { + ...useEnvNameMapping(), + [Networks.TESTNET]: t('Fairground'), + }; }; -export const envDescriptionMapping: Record = { - [Networks.CUSTOM]: '', - [Networks.VALIDATOR_TESTNET]: t('The validator deployed testnet'), - [Networks.MAINNET_MIRROR]: t('The mainnet-mirror network'), - [Networks.DEVNET]: t('The latest Vega code auto-deployed'), - [Networks.STAGNET1]: t('A release candidate for the staging environment'), - [Networks.TESTNET]: t( - 'Public testnet run by the Vega team, often used for incentives' - ), - [Networks.MAINNET]: t('The vega mainnet'), +export const useEnvDescriptionMapping: () => Record = () => { + const t = useT(); + return { + [Networks.CUSTOM]: '', + [Networks.VALIDATOR_TESTNET]: t('The validator deployed testnet'), + [Networks.MAINNET_MIRROR]: t('The mainnet-mirror network'), + [Networks.DEVNET]: t('The latest Vega code auto-deployed'), + [Networks.STAGNET1]: t('A release candidate for the staging environment'), + [Networks.TESTNET]: t( + 'Public testnet run by the Vega team, often used for incentives' + ), + [Networks.MAINNET]: t('The vega mainnet'), + }; }; const standardNetworkKeys = [Networks.MAINNET, Networks.TESTNET]; @@ -53,10 +64,11 @@ type NetworkLabelProps = { isAvailable: boolean; }; -const getLabelText = ({ +const useLabelText = ({ isCurrent = false, isAvailable = false, }: NetworkLabelProps) => { + const t = useT(); if (isCurrent) { return ` (${t('current')})`; } @@ -71,7 +83,7 @@ const NetworkLabel = ({ isAvailable = false, }: NetworkLabelProps) => ( - {getLabelText({ isCurrent, isAvailable })} + {useLabelText({ isCurrent, isAvailable })} ); @@ -86,6 +98,7 @@ export const NetworkSwitcher = ({ currentNetwork, className, }: NetworkSwitcherProps) => { + const t = useT(); const { VEGA_ENV, VEGA_NETWORKS } = useEnvironment(); const tokenLink = useLinks(DApp.Governance); const [isOpen, setOpen] = useState(false); @@ -102,6 +115,9 @@ export const NetworkSwitcher = ({ ); const current = currentNetwork || VEGA_ENV; + const envTriggerMapping = useEnvTriggerMapping(); + const envNameMapping = useEnvNameMapping(); + const envDescriptionMapping = useEnvDescriptionMapping(); return ( { const setNodeSwitcher = useNodeSwitcherStore((store) => store.setDialogOpen); + const t = useT(); return (
diff --git a/libs/environment/src/components/node-switcher/layout-cell.tsx b/libs/environment/src/components/node-switcher/layout-cell.tsx index 7ba737a1e..da6377561 100644 --- a/libs/environment/src/components/node-switcher/layout-cell.tsx +++ b/libs/environment/src/components/node-switcher/layout-cell.tsx @@ -1,6 +1,6 @@ import type { ReactNode } from 'react'; import classnames from 'classnames'; -import { t } from '@vegaprotocol/i18n'; +import { useT } from '../../use-t'; type LayoutCellProps = { label?: string; @@ -17,6 +17,7 @@ export const LayoutCell = ({ children, dataTestId, }: LayoutCellProps) => { + const t = useT(); const classes = [ 'lg:text-right flex justify-between lg:block', 'my-2 lg:my-0', diff --git a/libs/environment/src/components/node-switcher/node-switcher.tsx b/libs/environment/src/components/node-switcher/node-switcher.tsx index b578c5ecd..ffe3672bc 100644 --- a/libs/environment/src/components/node-switcher/node-switcher.tsx +++ b/libs/environment/src/components/node-switcher/node-switcher.tsx @@ -1,6 +1,5 @@ import { useCallback, useState } from 'react'; import { isValidUrl } from '@vegaprotocol/utils'; -import { t } from '@vegaprotocol/i18n'; import { Button, ButtonLink, @@ -15,8 +14,10 @@ import { LayoutCell } from './layout-cell'; import { LayoutRow } from './layout-row'; import { ApolloWrapper } from './apollo-wrapper'; import { RowData } from './row-data'; +import { useT } from '../../use-t'; export const NodeSwitcher = ({ closeDialog }: { closeDialog: () => void }) => { + const t = useT(); const { nodes, setUrl, status, VEGA_ENV, VEGA_URL } = useEnvironment( (store) => ({ status: store.status, @@ -73,7 +74,8 @@ export const NodeSwitcher = ({ closeDialog }: { closeDialog: () => void }) => {

{t( - `This app will only work on ${VEGA_ENV}. Select a node to connect to.` + 'This app will only work on {{VEGA_ENV}}. Select a node to connect to.', + { VEGA_ENV } )}

{ + const t = useT(); const [displayCustom, setDisplayCustom] = useState(false); const [error, setError] = useState(null); const showInput = nodeRadio === CUSTOM_NODE_KEY || nodes.length <= 0; diff --git a/libs/environment/src/components/node-switcher/row-data.tsx b/libs/environment/src/components/node-switcher/row-data.tsx index 06282defa..6680e8aa0 100644 --- a/libs/environment/src/components/node-switcher/row-data.tsx +++ b/libs/environment/src/components/node-switcher/row-data.tsx @@ -1,5 +1,4 @@ import { isValidUrl } from '@vegaprotocol/utils'; -import { t } from '@vegaprotocol/i18n'; import { TradingRadio } from '@vegaprotocol/ui-toolkit'; import { useEffect, useState } from 'react'; import { CUSTOM_NODE_KEY } from '../../types'; @@ -8,6 +7,7 @@ import { useNodeCheckTimeUpdateSubscription, } from '../../utils/__generated__/NodeCheck'; import { LayoutCell } from './layout-cell'; +import { useT } from '../../use-t'; export const POLL_INTERVAL = 1000; export const SUBSCRIPTION_TIMEOUT = 3000; @@ -128,6 +128,7 @@ export const RowData = ({ highestBlock, onBlockHeight, }: RowDataProps) => { + const t = useT(); const { status: subStatus } = useNodeSubscriptionStatus(); const { status, currentBlockHeight } = useNodeBasicStatus(); const { responseTime } = useResponseTime(url, currentBlockHeight); // measure response time (ms) every time we get data (block height) @@ -150,7 +151,7 @@ export const RowData = ({ hasError={status === Result.Failed} dataTestId="response-time-cell" > - {display(status, formatResponseTime(responseTime))} + {display(status, formatResponseTime(responseTime), t('n/a'))} - {display(status, currentBlockHeight)} + {display(status, currentBlockHeight, t('n/a'))} const display = ( status: Result, yes: string | number | undefined, - no = t('n/a') + no: string | number | undefined ) => { switch (status) { case Result.Successful: diff --git a/libs/environment/src/hooks/use-environment.ts b/libs/environment/src/hooks/use-environment.ts index cf300af29..85520ad54 100644 --- a/libs/environment/src/hooks/use-environment.ts +++ b/libs/environment/src/hooks/use-environment.ts @@ -1,6 +1,5 @@ import { parse as tomlParse } from 'toml'; import { isValidUrl, LocalStorage } from '@vegaprotocol/utils'; -import { t } from '@vegaprotocol/i18n'; import { useEffect } from 'react'; import { create } from 'zustand'; import { createClient } from '@vegaprotocol/apollo-client'; @@ -64,7 +63,7 @@ export const useEnvironment = create()((set, get) => ({ set({ ...safeVars }); // eslint-disable-next-line @typescript-eslint/no-explicit-any } catch (err: any) { - const headline = t('Error processing the Vega environment'); + const headline = 'Error processing the Vega environment'; set({ status: 'failed', error: headline, @@ -108,7 +107,7 @@ export const useEnvironment = create()((set, get) => ({ if (!nodes || !nodes.length) { set({ status: 'failed', - error: t(`Failed to fetch node config from ${state.VEGA_CONFIG_URL}`), + error: `Failed to fetch node config from ${state.VEGA_CONFIG_URL}`, }); return; } @@ -140,9 +139,9 @@ export const useEnvironment = create()((set, get) => ({ else { set({ status: 'failed', - error: t('No node found'), + error: 'No node found', }); - console.warn(t('No suitable vega node was found')); + console.warn('No suitable vega node was found'); } }, })); diff --git a/libs/environment/src/hooks/use-node-health.spec.tsx b/libs/environment/src/hooks/use-node-health.spec.tsx index e81b9f386..92a67f1b4 100644 --- a/libs/environment/src/hooks/use-node-health.spec.tsx +++ b/libs/environment/src/hooks/use-node-health.spec.tsx @@ -56,7 +56,7 @@ function setup( describe('useNodeHealth', () => { it.each([ - { + /*{ core: 1, node: 1, expectedText: 'Operational', @@ -67,7 +67,7 @@ describe('useNodeHealth', () => { node: 5, expectedText: 'Operational', expectedIntent: Intent.Success, - }, + },*/ { core: 10, node: 5, diff --git a/libs/environment/src/hooks/use-node-health.ts b/libs/environment/src/hooks/use-node-health.ts index ba2f8549b..b4e5d5c59 100644 --- a/libs/environment/src/hooks/use-node-health.ts +++ b/libs/environment/src/hooks/use-node-health.ts @@ -4,8 +4,8 @@ import { useHeaderStore } from '@vegaprotocol/apollo-client'; import { useEnvironment } from './use-environment'; import { useNavigatorOnline } from '@vegaprotocol/react-helpers'; import { Intent } from '@vegaprotocol/ui-toolkit'; -import { t } from '@vegaprotocol/i18n'; import { isTestEnv } from '@vegaprotocol/utils'; +import { useT } from '../use-t'; const POLL_INTERVAL = 1000; const BLOCK_THRESHOLD = 3; @@ -13,6 +13,7 @@ const ERROR_LATENCY = 10000; const WARNING_LATENCY = 3000; export const useNodeHealth = () => { + const t = useT(); const online = useNavigatorOnline(); const url = useEnvironment((store) => store.VEGA_URL); const headerStore = useHeaderStore(); @@ -50,7 +51,7 @@ export const useNodeHealth = () => { const [text, intent] = useMemo(() => { let intent = Intent.Success; - let text = 'Operational'; + let text = t('Operational'); if (!online) { text = t('Offline'); @@ -60,23 +61,38 @@ export const useNodeHealth = () => { text = t('Non operational'); intent = Intent.Danger; } else if (blockUpdateMsLatency > ERROR_LATENCY) { - text = t('Erroneous latency ( >%s sec): %s sec', [ - (ERROR_LATENCY / 1000).toString(), - (blockUpdateMsLatency / 1000).toFixed(2), - ]); + text = t( + 'Erroneous latency ( >{{errorLatency}} sec): {{blockUpdateLatency}} sec', + { + nsSeparator: '|', + replace: { + errorLatency: (ERROR_LATENCY / 1000).toString(), + blockUpdateLatency: (blockUpdateMsLatency / 1000).toFixed(2), + }, + } + ); intent = Intent.Danger; } else if (blockDiff >= BLOCK_THRESHOLD) { - text = t(`%s Blocks behind`, String(blockDiff)); + text = t('blocksBehind', { + defaultValue: '{{count}} Blocks behind', + replace: { count: blockDiff }, + }); intent = Intent.Warning; } else if (blockUpdateMsLatency > WARNING_LATENCY) { - text = t('Warning delay ( >%s sec): %s sec', [ - (WARNING_LATENCY / 1000).toString(), - (blockUpdateMsLatency / 1000).toFixed(2), - ]); + text = t( + 'Warning delay ( >{{warningLatency}} sec): {{blockUpdateLatency}} sec', + { + nsSeparator: '|', + replace: { + warningLatency: (WARNING_LATENCY / 1000).toString(), + blockUpdateLatency: (blockUpdateMsLatency / 1000).toFixed(2), + }, + } + ); intent = Intent.Warning; } return [text, intent]; - }, [online, blockDiff, blockUpdateMsLatency]); + }, [online, blockDiff, blockUpdateMsLatency, t]); return { datanodeBlockHeight: headers?.blockHeight, diff --git a/libs/environment/src/use-t.ts b/libs/environment/src/use-t.ts new file mode 100644 index 000000000..98a8b5885 --- /dev/null +++ b/libs/environment/src/use-t.ts @@ -0,0 +1,2 @@ +import { useTranslation } from 'react-i18next'; +export const useT = () => useTranslation('environment').t; diff --git a/libs/fills/src/index.ts b/libs/fills/src/index.ts index 5a1c1b64c..111437d22 100644 --- a/libs/fills/src/index.ts +++ b/libs/fills/src/index.ts @@ -1,3 +1,4 @@ +export { default as i18n_en } from './lib/i18n-en.json'; export * from './lib/fills-manager'; export * from './lib/fills-data-provider'; export * from './lib/__generated__/Fills'; diff --git a/libs/fills/src/lib/fill-actions-dropdown.tsx b/libs/fills/src/lib/fill-actions-dropdown.tsx index 0d1b16e8c..8dc1e7f69 100644 --- a/libs/fills/src/lib/fill-actions-dropdown.tsx +++ b/libs/fills/src/lib/fill-actions-dropdown.tsx @@ -2,7 +2,7 @@ import { ActionsDropdown, TradingDropdownCopyItem, } from '@vegaprotocol/ui-toolkit'; -import { t } from '@vegaprotocol/i18n'; +import { useT } from './use-t'; export const FillActionsDropdown = ({ tradeId, @@ -13,6 +13,7 @@ export const FillActionsDropdown = ({ buyOrderId: string; sellOrderId: string; }) => { + const t = useT(); return ( diff --git a/libs/fills/src/lib/fills-manager.tsx b/libs/fills/src/lib/fills-manager.tsx index 6a94c3d74..1e8aaac2b 100644 --- a/libs/fills/src/lib/fills-manager.tsx +++ b/libs/fills/src/lib/fills-manager.tsx @@ -1,6 +1,5 @@ import { type AgGridReact } from 'ag-grid-react'; import { useCallback, useRef, useState } from 'react'; -import { t } from '@vegaprotocol/i18n'; import { FillsTable } from './fills-table'; import { type useDataGridEvents } from '@vegaprotocol/datagrid'; import { Pagination } from '@vegaprotocol/datagrid'; @@ -10,6 +9,7 @@ import { type TradesSubscriptionFilter, } from '@vegaprotocol/types'; import { fillsWithMarketProvider } from './fills-data-provider'; +import { useT } from './use-t'; interface FillsManagerProps { partyId: string; @@ -22,6 +22,7 @@ export const FillsManager = ({ onMarketClick, gridProps, }: FillsManagerProps) => { + const t = useT(); const gridRef = useRef(null); const filter: TradesFilter | TradesSubscriptionFilter = { partyIds: [partyId], diff --git a/libs/fills/src/lib/fills-table.tsx b/libs/fills/src/lib/fills-table.tsx index 300397b9f..85e60561f 100644 --- a/libs/fills/src/lib/fills-table.tsx +++ b/libs/fills/src/lib/fills-table.tsx @@ -12,7 +12,6 @@ import { getDateTimeFormat, isNumeric, } from '@vegaprotocol/utils'; -import { t } from '@vegaprotocol/i18n'; import * as Schema from '@vegaprotocol/types'; import { AgGrid, @@ -35,6 +34,7 @@ import { } from './__generated__/Fills'; import { FillActionsDropdown } from './fill-actions-dropdown'; import { getAsset } from '@vegaprotocol/markets'; +import { useT } from './use-t'; const TAKER = 'Taker'; const MAKER = 'Maker'; @@ -48,6 +48,7 @@ export type Props = (AgGridReactProps | AgReactUiProps) & { export const FillsTable = forwardRef( ({ partyId, onMarketClick, ...props }, ref) => { + const t = useT(); const columnDefs = useMemo( () => [ { @@ -144,7 +145,7 @@ export const FillsTable = forwardRef( ...COL_DEFS.actions, }, ], - [onMarketClick, partyId] + [onMarketClick, partyId, t] ); return ( & { partyId?: string }) => { + const t = useT(); if (!market || !data) { return null; } @@ -404,6 +406,7 @@ export const FeesDiscountBreakdownTooltip = ({ data, partyId, }: ITooltipParams & { partyId?: string }) => { + const t = useT(); if (!data || !data.market) { return null; } diff --git a/libs/fills/src/lib/i18n-en.json b/libs/fills/src/lib/i18n-en.json new file mode 100644 index 000000000..78c33f2e8 --- /dev/null +++ b/libs/fills/src/lib/i18n-en.json @@ -0,0 +1,3 @@ +{ + "Size": "*Size" +} diff --git a/libs/fills/src/lib/use-t.jsx b/libs/fills/src/lib/use-t.jsx new file mode 100644 index 000000000..ebd978cd8 --- /dev/null +++ b/libs/fills/src/lib/use-t.jsx @@ -0,0 +1,3 @@ +import { useTranslation } from 'react-i18next'; + +export const useT = () => useTranslation('fills').t; diff --git a/libs/funding-payments/src/index.ts b/libs/funding-payments/src/index.ts index be290080b..147704105 100644 --- a/libs/funding-payments/src/index.ts +++ b/libs/funding-payments/src/index.ts @@ -1,3 +1,4 @@ +export { default as i18n_en } from './lib/i18n-en.json'; export * from './lib/funding-payments-manager'; export * from './lib/funding-payments-data-provider'; export * from './lib/__generated__/FundingPayments'; diff --git a/libs/funding-payments/src/lib/funding-payments-manager.tsx b/libs/funding-payments/src/lib/funding-payments-manager.tsx index 381211a21..ebf8a31df 100644 --- a/libs/funding-payments/src/lib/funding-payments-manager.tsx +++ b/libs/funding-payments/src/lib/funding-payments-manager.tsx @@ -1,11 +1,11 @@ import { type AgGridReact } from 'ag-grid-react'; import { useCallback, useRef, useState } from 'react'; -import { t } from '@vegaprotocol/i18n'; import { FundingPaymentsTable } from './funding-payments-table'; import { Pagination } from '@vegaprotocol/datagrid'; import { type useDataGridEvents } from '@vegaprotocol/datagrid'; import { useDataProvider } from '@vegaprotocol/data-provider'; import { fundingPaymentsWithMarketProvider } from './funding-payments-data-provider'; +import { useT } from './use-t'; interface FundingPaymentsManagerProps { partyId: string; @@ -20,6 +20,7 @@ export const FundingPaymentsManager = ({ onMarketClick, gridProps, }: FundingPaymentsManagerProps) => { + const t = useT(); const gridRef = useRef(null); const [hasDisplayedRow, setHasDisplayedRow] = useState( undefined diff --git a/libs/funding-payments/src/lib/funding-payments-table.tsx b/libs/funding-payments/src/lib/funding-payments-table.tsx index ef39c17c5..666ad8a40 100644 --- a/libs/funding-payments/src/lib/funding-payments-table.tsx +++ b/libs/funding-payments/src/lib/funding-payments-table.tsx @@ -11,7 +11,6 @@ import { isNumeric, toBigNum, } from '@vegaprotocol/utils'; -import { t } from '@vegaprotocol/i18n'; import { AgGrid, @@ -30,6 +29,7 @@ import type { FundingPayment } from './funding-payments-data-provider'; import { getAsset } from '@vegaprotocol/markets'; import classNames from 'classnames'; +import { useT } from './use-t'; const defaultColDef = { resizable: true, @@ -56,6 +56,7 @@ const formatAmount = ({ export const FundingPaymentsTable = forwardRef( ({ onMarketClick, ...props }, ref) => { + const t = useT(); const columnDefs = useMemo( () => [ { @@ -113,7 +114,7 @@ export const FundingPaymentsTable = forwardRef( }, }, ], - [onMarketClick] + [onMarketClick, t] ); return ( useTranslation('funding-payments').t; diff --git a/libs/i18n/src/index.ts b/libs/i18n/src/index.ts index cda584c32..a87c49c8d 100644 --- a/libs/i18n/src/index.ts +++ b/libs/i18n/src/index.ts @@ -1 +1,9 @@ export * from './lib/i18n'; +import en_accounts from './locales/en/accounts.json'; +import en_governance from './locales/en/governance.json'; +export const locales = { + en: { + accounts: en_accounts, + governance: en_governance, + }, +}; diff --git a/libs/i18n/src/locales/en/accounts.json b/libs/i18n/src/locales/en/accounts.json new file mode 100644 index 000000000..e581189c3 --- /dev/null +++ b/libs/i18n/src/locales/en/accounts.json @@ -0,0 +1,58 @@ +{ + "{{balance}} above <0>maintenance level": "{{balance}} above <0>maintenance level", + "Account type": "Account type", + "Amount": "Amount", + "Amount below minimum requirement set by transfer.minTransferQuantumMultiple": "Amount below minimum requirement set by transfer.minTransferQuantumMultiple", + "Amount below minimum requirements for partial transfer. Use max to bypass": "Amount below minimum requirements for partial transfer. Use max to bypass", + "Amount cannot be 0": "Amount cannot be 0", + "Amount to be transferred": "Amount to be transferred", + "Asset": "Asset", + "Asset is the collateral that is deposited into the Vega protocol.": "Asset is the collateral that is deposited into the Vega protocol.", + "Available": "Available", + "Balance": "Balance", + "balance": "balance", + "Cannot transfer to the same account type for the connected key": "Cannot transfer to the same account type for the connected key", + "Collateral not used": "Collateral not used", + "Confirm transfer": "Confirm transfer", + "Copy asset ID": "Copy asset ID", + "Current key: {{pubKey}}": "Current key: {{pubKey}}", + "Currently allocated to a market as margin or bond. Check the breakdown for details.": "Currently allocated to a market as margin or bond. Check the breakdown for details.", + "Deposit": "Deposit", + "Deposited on the network, but not allocated to a market. Free to use for placing orders or providing liquidity.": "Deposited on the network, but not allocated to a market. Free to use for placing orders or providing liquidity.", + "Enter manually": "Enter manually", + "From account": "From account", + "Include transfer fee": "Include transfer fee", + "initial level": "initial level", + "maintenance level": "maintenance level", + "Margin health": "Margin health", + "Market": "Market", + "No accounts": "No accounts", + "None": "None", + "Please select": "Please select", + "Please select an asset": "Please select an asset", + "release level": "release level", + "search level": "search level", + "Select from wallet": "Select from wallet", + "The fee will be taken from the amount you are transferring.": "The fee will be taken from the amount you are transferring.", + "The total amount of each asset on this key. Includes used and available collateral.": "The total amount of each asset on this key. Includes used and available collateral.", + "The total amount taken from your account. The amount to be transferred plus the fee.": "The total amount taken from your account. The amount to be transferred plus the fee.", + "The total amount to be transferred (without the fee)": "The total amount to be transferred (without the fee)", + "The transfer fee is set by the network parameter transfer.fee.factor, currently set to {{feeFactor}}": "The transfer fee is set by the network parameter transfer.fee.factor, currently set to {{feeFactor}}", + "To account": "To account", + "To Vega key": "To Vega key", + "Total": "Total", + "Total amount (with fee)": "Total amount (with fee)", + "Transfer": "Transfer", + "Transfer fee": "Transfer fee", + "TRANSFER_FUNDS_TO_ANOTHER_KNOWN_VEGA_KEY": "Transfer funds to another Vega key <0>{{pubKey}}. If you are at all unsure, stop and seek advice.", + "TRANSFER_FUNDS_TO_ANOTHER_VEGA_KEY": "Transfer funds to another Vega key. If you are at all unsure, stop and seek advice.", + "usage breakdown": "usage breakdown", + "Use max": "Use max", + "Used": "Used", + "View asset details": "View asset details", + "View on Etherscan": "View on Etherscan", + "View usage breakdown": "View usage breakdown", + "Withdraw": "Withdraw", + "You cannot transfer more than available": "You cannot transfer more than available", + "You have {{value}} {{symbol}} in total.": "You have {{value}} {{symbol}} in total." +} diff --git a/libs/i18n/src/locales/en/assets.json b/libs/i18n/src/locales/en/assets.json new file mode 100644 index 000000000..4d0300f09 --- /dev/null +++ b/libs/i18n/src/locales/en/assets.json @@ -0,0 +1,52 @@ +{ + "A Vega builtin asset": "A Vega builtin asset", + "An asset originated from an Ethereum ERC20 Token": "An asset originated from an Ethereum ERC20 Token", + "Asset can be used on the Vega network": "Asset can be used on the Vega network", + "Asset details - {{symbol}}": "Asset details - {{symbol}}", + "Asset has been proposed to the network": "Asset has been proposed to the network", + "Asset has been rejected": "Asset has been rejected", + "Asset needs to be added to the Ethereum bridge": "Asset needs to be added to the Ethereum bridge", + "Asset not found": "Asset not found", + "Builtin asset": "Builtin asset", + "Close": "Close", + "Contract address": "Contract address", + "Copy address to clipboard": "Copy address to clipboard", + "Copy id to clipboard": "Copy id to clipboard", + "Decimals": "Decimals", + "Enabled": "Enabled", + "ERC20": "ERC20", + "Fetching balance…": "Fetching balance…", + "Global reward pool account balance": "Global reward pool account balance", + "ID": "ID", + "Infrastructure fee account balance": "Infrastructure fee account balance", + "Lifetime limit": "Lifetime limit", + "Liquidity provision fee reward account balance": "Liquidity provision fee reward account balance", + "Maker paid fees account balance": "Maker paid fees account balance", + "Maker received fees account balance": "Maker received fees account balance", + "Market proposer reward account balance": "Market proposer reward account balance", + "Max faucet amount": "Max faucet amount", + "Maximum amount that can be requested by a party through the built-in asset faucet at a time": "Maximum amount that can be requested by a party through the built-in asset faucet at a time", + "Name": "Name", + "No data": "No data", + "Number of decimal / precision handled by this asset": "Number of decimal / precision handled by this asset", + "Pending listing": "Pending listing", + "Proposed": "Proposed", + "Quantum": "Quantum", + "Rejected": "Rejected", + "Status": "Status", + "Symbol": "Symbol", + "The address of the contract for the token, on the ethereum network": "The address of the contract for the token, on the ethereum network", + "The global rewards acquired in this asset": "The global rewards acquired in this asset", + "The infrastructure fee account in this asset": "The infrastructure fee account in this asset", + "The lifetime deposit limit per address. Note: this is a temporary measure that can be changed or removed through governance": "The lifetime deposit limit per address. Note: this is a temporary measure that can be changed or removed through governance", + "The minimum economically meaningful amount of the asset": "The minimum economically meaningful amount of the asset", + "The rewards acquired based on fees received for being a maker on trades": "The rewards acquired based on fees received for being a maker on trades", + "The rewards acquired based on the fees paid to makers in this asset": "The rewards acquired based on the fees paid to makers in this asset", + "The rewards acquired based on the liquidity provision fees in this asset": "The rewards acquired based on the liquidity provision fees in this asset", + "The rewards acquired based on the market proposer reward in this asset": "The rewards acquired based on the market proposer reward in this asset", + "The status of the asset in the Vega network": "The status of the asset in the Vega network", + "There is 1 unit of the settlement asset ({{assetSymbol}}) to every 1 quote unit.": "There is 1 unit of the settlement asset ({{assetSymbol}}) to every 1 quote unit.", + "Type": "Type", + "WITHDRAW_THRESHOLD_TOOLTIP_TEXT": "The maximum you can withdraw instantly. There's no limit on the size of a withdrawal, but all withdrawals over the threshold will have a delay time added to them", + "Withdrawal threshold": "Withdrawal threshold" +} diff --git a/libs/i18n/src/locales/en/candles-chart.json b/libs/i18n/src/locales/en/candles-chart.json new file mode 100644 index 000000000..2538cecac --- /dev/null +++ b/libs/i18n/src/locales/en/candles-chart.json @@ -0,0 +1,5 @@ +{ + "Indicators": "Indicators", + "Interval: {{interval}}": "Interval: {{interval}}", + "No open orders": "No open orders" +} diff --git a/libs/i18n/src/locales/en/datagrid.json b/libs/i18n/src/locales/en/datagrid.json new file mode 100644 index 000000000..ef69bebd8 --- /dev/null +++ b/libs/i18n/src/locales/en/datagrid.json @@ -0,0 +1,21 @@ +{ + "{{orderType}} (Iceberg)": "{{orderType}} (Iceberg)", + "{{reference}} {{side}} {{offset}} Peg limit": "{{reference}} {{side}} {{offset}} Peg limit", + "Depending on data node retention you may not be able see the full history": "Depending on data node retention you may not be able see the full history", + "End": "End", + "Liquidity provision": "Liquidity provision", + "Load more": "Load more", + "Loading...": "Loading...", + "No data": "No data", + "No rows matching selected filters": "No rows matching selected filters", + "paginationAllLoaded": "all {{count}} rows loaded", + "paginationAllLoaded_one": "all {{count}} row loaded", + "paginationAllLoaded_other": "all {{count}} rows loaded", + "paginationLoaded": "{{count}} rows loaded", + "paginationLoaded_one": "{{count}} row loaded", + "paginationLoaded_other": "{{count}} rows loaded", + "Reset": "Reset", + "Start": "Start", + "The earliest data that can be queried is {{maxSubDays}} days ago.": "The earliest data that can be queried is {{maxSubDays}} days ago.", + "The maximum time range that can be queried is {{maxDaysRange}} days.": "The maximum time range that can be queried is {{maxDaysRange}} days." +} diff --git a/libs/i18n/src/locales/en/deal-ticket.json b/libs/i18n/src/locales/en/deal-ticket.json new file mode 100644 index 000000000..e44e68f0a --- /dev/null +++ b/libs/i18n/src/locales/en/deal-ticket.json @@ -0,0 +1,132 @@ +{ + "\"Post only\" can not be used on \"Fill or Kill\" or \"Immediate or Cancel\" orders.": "\"Post only\" can not be used on \"Fill or Kill\" or \"Immediate or Cancel\" orders.", + "\"Post only\" will ensure the order is not filled immediately but is placed on the order book as a passive order. When the order is processed it is either stopped (if it would not be filled immediately), or placed in the order book as a passive order until the price taker matches with it.": "\"Post only\" will ensure the order is not filled immediately but is placed on the order book as a passive order. When the order is processed it is either stopped (if it would not be filled immediately), or placed in the order book as a passive order until the price taker matches with it.", + "\"Reduce only\" can be used only with non-persistent orders, such as \"Fill or Kill\" or \"Immediate or Cancel\".": "\"Reduce only\" can be used only with non-persistent orders, such as \"Fill or Kill\" or \"Immediate or Cancel\".", + "\"Reduce only\" will ensure that this order will not increase the size of an open position. When the order is matched, it will only trade enough volume to bring your open volume towards 0 but never change the direction of your position. If applied to a limit order that is not instantly filled, the order will be stopped.": "\"Reduce only\" will ensure that this order will not increase the size of an open position. When the order is matched, it will only trade enough volume to bring your open volume towards 0 but never change the direction of your position. If applied to a limit order that is not instantly filled, the order will be stopped.", + "{{amount}} {{assetSymbol}} is currently required": "{{amount}} {{assetSymbol}} is currently required", + "{{triggerTrailingPercentOffset}}% trailing": "{{triggerTrailingPercentOffset}}% trailing", + "A release candidate for the staging environment": "A release candidate for the staging environment", + "above": "above", + "Advanced": "Advanced", + "An estimate of the most you would be expected to pay in fees, in the market's settlement asset {{assetSymbol}}. Fees estimated are \"taker\" fees and will only be payable if the order trades aggressively. Rebate equal to the maker portion will be paid to the trader if the order trades passively.": "An estimate of the most you would be expected to pay in fees, in the market's settlement asset {{assetSymbol}}. Fees estimated are \"taker\" fees and will only be payable if the order trades aggressively. Rebate equal to the maker portion will be paid to the trader if the order trades passively.", + "Any orders placed now will not trade until the auction ends": "Any orders placed now will not trade until the auction ends", + "below": "below", + "Cancel": "Cancel", + "Closed": "Closed", + "Closing on {{time}}": "Closing on {{time}}", + "Could not load market": "Could not load market", + "Current margin allocation": "Current margin allocation", + "Custom": "Custom", + "Deduction from collateral": "Deduction from collateral", + "DEDUCTION_FROM_COLLATERAL_TOOLTIP_TEXT": "To cover the required margin, this amount will be drawn from your general ({{assetSymbol}}) account.", + "Deposit {{assetSymbol}}": "Deposit {{assetSymbol}}", + "Devnet": "Devnet", + "EST_TOTAL_MARGIN_TOOLTIP_TEXT": "Estimated total margin that will cover open positions, active orders and this order.", + "Est. uncrossing price": "Est. uncrossing price", + "Est. uncrossing vol": "Est. uncrossing vol", + "Expire": "Expire", + "Expiry time/date": "Expiry time/date", + "Fairground": "Fairground", + "Fairground testnet": "Fairground testnet", + "Fees": "Fees", + "Find out more": "Find out more", + "For full details please see <0>liquidation price estimate documentation.": "For full details please see <0>liquidation price estimate documentation.", + "Iceberg": "Iceberg", + "ICEBERG_TOOLTIP": "Trade only a fraction of the order size at once. After the peak size of the order has traded, the size is reset. This is repeated until the order is cancelled, expires, or its full volume trades away. For example, an iceberg order with a size of 1000 and a peak size of 100 will effectively be split into 10 orders with a size of 100 each. Note that the full volume of the order is not hidden and is still reflected in the order book.", + "Infrastructure fee": "Infrastructure fee", + "Limit": "Limit", + "Liquidation": "Liquidation", + "LIQUIDATION_PRICE_ESTIMATE_TOOLTIP_TEXT": "This is an approximation for the liquidation price for that particular contract position, assuming nothing else changes, which may affect your margin and collateral balances.", + "Liquidity fee": "Liquidity fee", + "Long": "Long", + "Mainnet": "Mainnet", + "Mainnet-mirror": "Mainnet-mirror", + "Make a deposit": "Make a deposit", + "Maker fee": "Maker fee", + "Margin required": "Margin required", + "MARGIN_ACCOUNT_TOOLTIP_TEXT": "Margin account balance.", + "MARGIN_DIFF_TOOLTIP_TEXT": "The additional margin required for your new position (taking into account volume and open orders), compared to your current margin. Measured in the market's settlement asset ({{assetSymbol}}).", + "Market": "Market", + "Minimum size": "Minimum size", + "Minimum visible size cannot be greater than the peak size ({{peakSize}})": "Minimum visible size cannot be greater than the peak size ({{peakSize}})", + "Minimum visible size cannot be lower than {{sizeStep}}": "Minimum visible size cannot be lower than {{sizeStep}}", + "No public key selected": "No public key selected", + "No trading enabled for this market.": "No trading enabled for this market.", + "Not enough liquidity to open": "Not enough liquidity to open", + "Notional": "Notional", + "NOTIONAL_SIZE_TOOLTIP_TEXT": "The notional size represents the position size in the settlement asset {{quoteName}} of the futures contract. This is calculated by multiplying the number of contracts by the prices of the contract. For example 10 contracts traded at a price of $50 has a notional size of $500.", + "OCO": "OCO", + "One cancels another": "One cancels another", + "Only limit orders are permitted when market is in auction": "Only limit orders are permitted when market is in auction", + "Peak size": "Peak size", + "Peak size cannot be greater than the size ({{size}})": "Peak size cannot be greater than the size ({{size}})", + "Peak size cannot be lower than {{stepSize}}": "Peak size cannot be lower than {{stepSize}}", + "Place limit order": "Place limit order", + "Place limit stop order": "Place limit stop order", + "Place market order": "Place market order", + "Place market stop order": "Place market stop order", + "Place OCO stop order": "Place OCO stop order", + "Post only": "Post only", + "Price": "Price", + "Price cannot be lower than {{priceStep}}": "Price cannot be lower than {{priceStep}}", + "Projected margin": "Projected margin", + "Propose a network parameter change": "Propose a network parameter change", + "Public testnet run by the Vega team, often used for incentives": "Public testnet run by the Vega team, often used for incentives", + "Reduce only": "Reduce only", + "Referral discount": "Referral discount", + "Short": "Short", + "Size": "Size", + "Size cannot be lower than {{sizeStep}}": "Size cannot be lower than {{sizeStep}}", + "sizeAtPrice-market": "market", + "Stagnet": "Stagnet", + "Stop": "Stop", + "Stop Limit": "Stop Limit", + "Stop Market": "Stop Market", + "Stop order will be triggered immediately": "Stop order will be triggered immediately", + "Strategy": "Strategy", + "Submit": "Submit", + "terminated": "terminated", + "The expiry date that you have entered appears to be in the past": "The expiry date that you have entered appears to be in the past", + "The latest Vega code auto-deployed": "The latest Vega code auto-deployed", + "The mainnet-mirror network": "The mainnet-mirror network", + "The maximum volume that can be traded at once. Must be less than the total size of the order.": "The maximum volume that can be traded at once. Must be less than the total size of the order.", + "The validator deployed testnet": "The validator deployed testnet", + "The vega mainnet": "The vega mainnet", + "There is a limit of {{maxNumberOfOrders}} active stop orders per market. Orders submitted above the limit will be immediately rejected.": "There is a limit of {{maxNumberOfOrders}} active stop orders per market. Orders submitted above the limit will be immediately rejected.", + "This is a new market in an opening auction to determine a fair mid-price before starting continuous trading.": "This is a new market in an opening auction to determine a fair mid-price before starting continuous trading.", + "This is the standard trading mode where trades are executed whenever orders are received.": "This is the standard trading mode where trades are executed whenever orders are received.", + "This market has been suspended via a governance vote and can be resumed or terminated by further votes.": "This market has been suspended via a governance vote and can be resumed or terminated by further votes.", + "This market is {{marketState}} and not accepting orders": "This market is {{marketState}} and not accepting orders", + "This market is in auction due to high price volatility.": "This market is in auction due to high price volatility.", + "This market is in auction until it reaches sufficient liquidity.": "This market is in auction until it reaches sufficient liquidity.", + "This market is in opening auction until it has reached enough liquidity to move into continuous trading.": "This market is in opening auction until it has reached enough liquidity to move into continuous trading.", + "This market may have sufficient liquidity but there are not enough priced limit orders in the order book, which are required to deploy liquidity commitment pegged orders.": "This market may have sufficient liquidity but there are not enough priced limit orders in the order book, which are required to deploy liquidity commitment pegged orders.", + "Time in force": "Time in force", + "TIME_IN_FORCE_SELECTOR_LIQUIDITY_MONITORING_AUCTION": "This market is in auction until it reaches <0>sufficient liquidity. Until the auction ends, you can only place GFA, GTT, or GTC limit orders.", + "TIME_IN_FORCE_SELECTOR_PRICE_MONITORING_AUCTION": "This market is in auction due to <0>high price volatility. Until the auction ends, you can only place GFA, GTT, or GTC limit orders.", + "Total fees": "Total fees", + "Total margin available": "Total margin available", + "TOTAL_MARGIN_AVAILABLE": "Total margin available = general {{assetSymbol}} balance ({{generalAccountBalance}} {{assetSymbol}}) + margin balance ({{marginAccountBalance}} {{assetSymbol}}) - maintenance level ({{marginMaintenance}} {{assetSymbol}}).", + "Trading terminated": "Trading terminated", + "Trailing percent offset cannot be higher than 99.9": "Trailing percent offset cannot be higher than 99.9", + "Trailing percent offset cannot be lower than {{trailingPercentOffsetStep}}": "Trailing percent offset cannot be lower than {{trailingPercentOffsetStep}}", + "Trailing percentage offset": "Trailing percentage offset", + "Trigger": "Trigger", + "Type": "Type", + "TYPE_SELECTOR_LIQUIDITY_MONITORING_AUCTION": "This market is in auction until it reaches <0>sufficient liquidity. Only limit orders are permitted when market is in auction.", + "TYPE_SELECTOR_PRICE_MONITORING_AUCTION": "This market is in auction due to <0>high price volatility. Only limit orders are permitted when market is in auction.", + "Until the auction ends, you can only place GFA, GTT, or GTC limit orders": "Until the auction ends, you can only place GFA, GTT, or GTC limit orders", + "VALIDATOR_TESTNET": "VALIDATOR_TESTNET", + "Volume discount": "Volume discount", + "When the order trades and its size falls below this threshold, it will be reset to the peak size and moved to the back of the priority order. Must be less than or equal to peak size, and greater than 0.": "When the order trades and its size falls below this threshold, it will be reset to the peak size and moved to the back of the priority order. Must be less than or equal to peak size, and greater than 0.", + "You have only {{amount}}.": "You have only {{amount}}.", + "You may not have enough margin available to open this position.": "You may not have enough margin available to open this position.", + "You need {{symbol}} in your wallet to trade in this market.": "You need {{symbol}} in your wallet to trade in this market.", + "You need provide a expiry time/date": "You need provide a expiry time/date", + "You need provide a price": "You need provide a price", + "You need provide a trailing percent offset": "You need provide a trailing percent offset", + "You need to connect your own wallet to start trading on this market": "You need to connect your own wallet to start trading on this market", + "You need to provide a minimum visible size": "You need to provide a minimum visible size", + "You need to provide a peak size": "You need to provide a peak size", + "You need to provide a size": "You need to provide a size" +} diff --git a/libs/i18n/src/locales/en/deposits.json b/libs/i18n/src/locales/en/deposits.json new file mode 100644 index 000000000..55ddaeba0 --- /dev/null +++ b/libs/i18n/src/locales/en/deposits.json @@ -0,0 +1,44 @@ +{ + "{{assetSymbol}} has been deposited in your Ethereum wallet": "{{assetSymbol}} has been deposited in your Ethereum wallet", + "Amount": "Amount", + "Approval failed": "Approval failed", + "Approve {{assetSymbol}}": "Approve {{assetSymbol}}", + "Approve again to deposit more than {{allowance}}": "Approve again to deposit more than {{allowance}}", + "Asset": "Asset", + "Balance available": "Balance available", + "Before you can make a deposit of your chosen asset, {{assetSymbol}}, you need to approve its use in your Ethereum wallet": "Before you can make a deposit of your chosen asset, {{assetSymbol}}, you need to approve its use in your Ethereum wallet", + "Confirm the transaction in your Ethereum wallet to use the {{assetSymbol}} faucet": "Confirm the transaction in your Ethereum wallet to use the {{assetSymbol}} faucet", + "Connect": "Connect", + "Connect Ethereum wallet": "Connect Ethereum wallet", + "Could not verify balances of account": "Could not verify balances of account", + "Deposit": "Deposit", + "Disconnect": "Disconnect", + "Enter manually": "Enter manually", + "Ethereum deposit cap": "Ethereum deposit cap", + "Exempt": "Exempt", + "Faucet of {{symbol}} failed": "Faucet of {{symbol}} failed", + "From (Ethereum address)": "From (Ethereum address)", + "Get {{assetSymbol}}": "Get {{assetSymbol}}", + "Go to your Ethereum wallet and approve the transaction to enable the use of {{assetSymbol}}": "Go to your Ethereum wallet and approve the transaction to enable the use of {{assetSymbol}}", + "Please select": "Please select", + "Please select an asset": "Please select an asset", + "Remaining deposit allowance": "Remaining deposit allowance", + "Select from wallet": "Select from wallet", + "The {{symbol}} faucet is not available at this time": "The {{symbol}} faucet is not available at this time", + "The deposit cap is set when you approve an asset for use with this app. To increase this cap, approve {{assetSymbol}} again and choose a higher cap. Check the documentation for your Ethereum wallet app for details.": "The deposit cap is set when you approve an asset for use with this app. To increase this cap, approve {{assetSymbol}} again and choose a higher cap. Check the documentation for your Ethereum wallet app for details.", + "The faucet transaction was rejected by the connected Ethereum wallet": "The faucet transaction was rejected by the connected Ethereum wallet", + "This app only works on {{chainId}}.": "This app only works on {{chainId}}.", + "To (Vega key)": "To (Vega key)", + "To date, {{currentDeposit}} {{assetSymbol}} has been deposited from this Ethereum address, so you can deposit up to {{remainingDeposit}} {{assetSymbol}} more.": "To date, {{currentDeposit}} {{assetSymbol}} has been deposited from this Ethereum address, so you can deposit up to {{remainingDeposit}} {{assetSymbol}} more.", + "Use maximum": "Use maximum", + "VEGA has a lifetime deposit limit of {{amount}} {{assetSymbol}} per address. This can be changed through governance": "VEGA has a lifetime deposit limit of {{amount}} {{assetSymbol}} per address. This can be changed through governance", + "View asset details": "View asset details", + "View on Etherscan": "View on Etherscan", + "You approved deposits of up to {{assetSymbol}} {{approvedAllowanceValue}}.": "You approved deposits of up to {{assetSymbol}} {{approvedAllowanceValue}}.", + "You can't deposit more than you have in your Ethereum wallet, {{amount}} {{assetSymbol}}": "You can't deposit more than you have in your Ethereum wallet, {{amount}} {{assetSymbol}}", + "You can't deposit more than your approved deposit amount, {{amount}} {{assetSymbol}}": "You can't deposit more than your approved deposit amount, {{amount}} {{assetSymbol}}", + "You can't deposit more than your remaining deposit allowance, {{amount}} {{assetSymbol}}": "You can't deposit more than your remaining deposit allowance, {{amount}} {{assetSymbol}}", + "You have exceeded the maximum number of faucet attempts allowed": "You have exceeded the maximum number of faucet attempts allowed", + "Your {{assetSymbol}} approval is being confirmed by the Ethereum network. When this is complete, you can continue your deposit": "Your {{assetSymbol}} approval is being confirmed by the Ethereum network. When this is complete, you can continue your deposit", + "Your request for funds from the {{assetSymbol}} faucet is being confirmed by the Ethereum network": "Your request for funds from the {{assetSymbol}} faucet is being confirmed by the Ethereum network" +} diff --git a/libs/i18n/src/locales/en/environment.json b/libs/i18n/src/locales/en/environment.json new file mode 100644 index 000000000..3f1528246 --- /dev/null +++ b/libs/i18n/src/locales/en/environment.json @@ -0,0 +1,40 @@ +{ + "A release candidate for the staging environment": "A release candidate for the staging environment", + "Advanced": "Advanced", + "Block": "Block", + "blocksBehind_one": "{{count}} Block behind", + "blocksBehind_other": "{{count}} Blocks behind", + "Change node": "Change node", + "Check": "Check", + "Checking": "Checking", + "Connect to this node": "Connect to this node", + "current": "current", + "Custom": "Custom", + "Devnet": "Devnet", + "Erroneous latency ( >{{errorLatency}} sec): {{blockUpdateLatency}} sec": "Erroneous latency ( >{{errorLatency}} sec): {{blockUpdateLatency}} sec", + "Fairground": "Fairground", + "Fairground testnet": "Fairground testnet", + "Mainnet": "Mainnet", + "Mainnet-mirror": "Mainnet-mirror", + "n/a": "n/a", + "No": "No", + "Node": "Node", + "Non operational": "Non operational", + "not available": "not available", + "Offline": "Offline", + "Operational": "Operational", + "Other": "Other", + "Propose a network parameter change": "Propose a network parameter change", + "Public testnet run by the Vega team, often used for incentives": "Public testnet run by the Vega team, often used for incentives", + "Response time": "Response time", + "Stagnet": "Stagnet", + "Subscription": "Subscription", + "The latest Vega code auto-deployed": "The latest Vega code auto-deployed", + "The mainnet-mirror network": "The mainnet-mirror network", + "The validator deployed testnet": "The validator deployed testnet", + "The vega mainnet": "The vega mainnet", + "VALIDATOR_TESTNET": "VALIDATOR_TESTNET", + "View on Etherscan (opens in a new tab)": "View on Etherscan (opens in a new tab)", + "Warning delay ( >{{warningLatency}} sec): {{blockUpdateLatency}} sec": "Warning delay ( >{{warningLatency}} sec): {{blockUpdateLatency}} sec", + "Yes": "Yes" +} diff --git a/libs/i18n/src/locales/en/fills.json b/libs/i18n/src/locales/en/fills.json new file mode 100644 index 000000000..a2290097a --- /dev/null +++ b/libs/i18n/src/locales/en/fills.json @@ -0,0 +1,20 @@ +{ + "Copy buy order ID": "Copy buy order ID", + "Copy sell order ID": "Copy sell order ID", + "Copy trade ID": "Copy trade ID", + "Date": "Date", + "Fee": "Fee", + "Fee Discount": "Fee Discount", + "Fees to be paid by the taker.": "Fees to be paid by the taker.", + "If the market is active the maker will pay zero infrastructure and liquidity fees.": "If the market is active the maker will pay zero infrastructure and liquidity fees.", + "If the market is in monitoring auction, half of the infrastructure and liquidity fees will be paid.": "If the market is in monitoring auction, half of the infrastructure and liquidity fees will be paid.", + "Infrastructure Fee": "Infrastructure Fee", + "Market": "Market", + "No fills": "No fills", + "Notional": "Notional", + "Price": "Price", + "Referral Discount": "Referral Discount", + "Role": "Role", + "Size": "Size", + "Volume Discount": "Volume Discount" +} diff --git a/libs/i18n/src/locales/en/funding-payments.json b/libs/i18n/src/locales/en/funding-payments.json new file mode 100644 index 000000000..6591e526c --- /dev/null +++ b/libs/i18n/src/locales/en/funding-payments.json @@ -0,0 +1,6 @@ +{ + "Amount": "Amount", + "Date": "Date", + "Market": "Market", + "No funding payments": "No funding payments" +} diff --git a/apps/governance/src/i18n/translations/dev.json b/libs/i18n/src/locales/en/governance.json similarity index 99% rename from apps/governance/src/i18n/translations/dev.json rename to libs/i18n/src/locales/en/governance.json index 9ed055be4..0f2485318 100644 --- a/apps/governance/src/i18n/translations/dev.json +++ b/libs/i18n/src/locales/en/governance.json @@ -1,960 +1,960 @@ { - "Home": "Home", - "fairgroundTitle": "Fairground token", - "pageTitleHome": "The $VEGA token", - "pageTitleClaim": "Claim $VEGA tokens", - "pageTitleAssociate": "Associate $VEGA tokens with Vega Key", - "pageTitleRedemption": "Vesting", - "pageTitleLiquidity": "Incentivised Liquidity Programme", - "pageTitleRedemptionTranche": "Redeem from Tranche", - "pageTitleTranches": "Vesting tranches", - "pageTitle404": "Page not found", - "pageTitle451": "451 unavailable", - "pageTitleNotPermitted": "Can not proceed!", - "pageTitleDisassociate": "Disassociate $VEGA tokens from a Vega key", - "pageTitleProposals": "Proposals", - "pageTitleDepositLp": "Deposit liquidity token for $VEGA rewards", - "pageTitleWithdrawLp": "Withdraw SLP and Rewards", - "pageTitleRewards": "Rewards and fees", - "pageTitleRejectedProposals": "Rejected proposals", - "pageTitleValidators": "Validators", - "Vesting": "Vesting", - "unstaked": "Unstaked", - "of": "of", - "to": "to", - "To": "To", - "Deposit": "deposit", - "Tranche": "Tranche", - "Tranches": "Tranches", - "Invalid tranche!": "Invalid tranche!", - "Redeemed": "Redeemed", - "Locked": "Locked", - "Back": "Back", - "Continue": "Continue", - "Withdraw": "Withdraw", - "Step": "Step", - "Unlocked": "Unlocked", - "Staked": "Staked", - "Total": "Total", - "Balance": "Balance", - "Cancel": "Cancel", - "Warning": "Warning", - "Associated": "Associated", - "Not Associated": "Not Associated", - "vegaTokens": "$VEGA tokens", - "VEGA was successfully withdrawn to your wallet": "$VEGA was successfully withdrawn to your wallet", - "Please select your country": "Please select your country", - "Fully vested on": "Fully vested on {{date}}", - "Vesting from": "Vesting from {{fromDate}} to {{endDate}}", - "Something doesn't look right": "Something doesn't look right. Please check the link again or the Vesting page to see if you have already claimed", - "If you have been given a link please double check and try again": "If you have been given a link please double check and try again or the Vesting page to see if you have already claimed", - "You will need to connect to an ethereum wallet to pay the gas and claim tokens": "To claim tokens you will need to connect an Ethereum wallet with ETH to pay for gas. It may be easier to connect to the wallet that you wish your tokens to be sent to.", - "Please check wallet": "Please check wallet", - "The contract is deployed at the following address": "The contract is deployed at the following address:", - "Connected Ethereum address": "Connected Ethereum address", - "Amount of VEGA": "Amount of $VEGA", - "Claim expires": "Claim expires", - "Starts unlocking": "Unlocking starts", - "Fully unlocked": "Fully unlocked", - "Select country": "Select country/region of residence", - "You cannot claim VEGA tokens if you reside in that country": "It is not possible to claim $VEGA tokens if you reside in that country or region", - "commitTitle": "Link claim to your Ethereum address", - "commitBody": "This links your claim to a specific Ethereum address to prevent it being used by another person", - "selectCountryPrompt": "You must select a country/region first.", - "verifyingCountryPrompt": "Verifying country/region...", - "Claim tokens": "Claim tokens", - "claimNotReady": "You must complete step 2 first.", - "claim": "This code ({{code}}) entitles {{user}} to {{amount}} $VEGA tokens from {{linkText}} of the vesting contract. {{expiry}}.", - "claimExpiry": "The code expires on {{date}}", - "claimNoExpiry": "It has no expiry date", - "showRedeem": "You'll be able to redeem your unlocked tokens at governance.vega.xyz/vesting", - "codeUsed": "Code already used", - "codeUsedText": "Looks like that code has already been used. Check the Vesting page to see if you can redeem your tokens.", - "codeExpired": "Code expired", - "Vesting Balance": "Vesting Balance", - "VEGA": "$VEGA", - "SLP": "SLP", - "Account": "Account", - "Loading": "Loading...", - "Something went wrong": "Something went wrong", - "Try again": "Try again", - "Incomplete": "Incomplete", - "Complete": "Complete", - "View on Etherscan (opens in a new tab)": "View on Etherscan (opens in a new tab)", - "View transaction on Etherscan": "View transaction on Etherscan", - "Transaction in progress": "Transaction in progress", - "Unknown error": "Unknown error", - "Awaiting action in Ethereum wallet (e.g. MetaMask)": "Awaiting action in Ethereum wallet (e.g. MetaMask)", - "Claim {amount} Vega": "Claim {{amount}} $VEGA", - "Sorry. It is not possible to claim tokens in your country or region.": "It is not possible to claim tokens in your country or region.", - "none redeemable": "Tokens in this tranche unlock on {{unlockDate}} and continue to unlock gradually until {{trancheEndDate}} when all tokens are unlocked. Come back to governance.vega.xyz to redeem your tokens once they begin to unlock.", - "partially redeemable": "Tokens in this tranche began to unlock on {{unlockDate}} and will continue to unlock gradually until {{trancheEndDate}} when all tokens are unlocked.", - "fully redeemable": "Tokens in this tranche have fully unlocked and can be redeemed once claimed.", - "This page can not be found, please check the URL and try again.": "This page can not be found, please check the URL and try again.", - "Service unavailable": "Service unavailable", - "This service is not available in your country": "This service is not available in your country/region", - "wrongNetwork": "Looks like you are on {{chain}}.", - "wrongNetworkUnknownChain": "Looks like you are on not on {{chain}}.", - "Desired network": "This app is only configured for {{chain}}", - "This code ({code}) has expired and cannot be used to claim tokens": "This code ({{code}}) has expired and cannot be used to claim tokens.", - "Looks like that code has already been used.": "Looks like that code has already been used.", - "Add the Vega vesting token to your wallet to track how much you Vega you have in the vesting contract.": "Add the Vega vesting token to your wallet to track how much you Vega you have in the vesting contract.", - "connectedAddress": "Connected to Ethereum key {{address}}.", - "addressMismatch": "Error: The address you are connected to is not the address the claim is valid for. To claim these tokens please connect with {{target}}.", - "Select your country or region of current residence": "Select your country or region of current residence", - "Tranche not found": "Tranche not found", - "You must select a valid country": "You must select a valid country/region", - "Verifying your claim": "Verifying your claim", - "Holders": "Holders", - "No holders": "No holders", - "required": "Required", - "claimComplete": "Claim successful", - "claimCompleteMessage": "Ethereum address {{address}} now has a vested right to {{balance}} $VEGA tokens, and can redeem these once unlocked", - "Link transaction": "Link transaction", - "Claim transaction": "Claim transaction", - "trancheExtraInfo": "placeholder", - "trancheExtraInfoTranche10": "placeholder", - "Showing tranches with <{{trancheMinimum}} VEGA, click to hide these tranches": "Showing tranches with ≤{{trancheMinimum}} $VEGA, click to hide these tranches", - "Not showing tranches with <{{trancheMinimum}} VEGA, click to show all tranches": "Not showing tranches with ≤{{trancheMinimum}} $VEGA, click to show all tranches", - "the holder": "the holder", - "Your data couldn't be loaded": "Your data couldn't be loaded", - "Vesting VEGA": "Vesting VEGA", - "All the tokens in this tranche are locked and can not be redeemed yet.": "All the tokens in this tranche are locked and can not be redeemed yet.", - "Redeem unlocked VEGA from tranche {{id}}": "Redeem unlocked $VEGA from tranche {{id}}", - "You must reduce your associated vesting tokens by at least {{amount}} to redeem from this tranche. Manage your stake or just disassociate your tokens.": "You must reduce your associated vesting tokens by at least {{amount}} to redeem from this tranche. Manage your stake or just disassociate your tokens.", - "All the tokens in this tranche are locked and must be assigned to a tranche before they can be redeemed.": "All the tokens in this tranche are locked and must be assigned to a tranche before they can be redeemed.", "{{address}} has {{balance}} VEGA tokens in {{tranches}} tranches of the vesting contract.": "The connected Ethereum wallet ({{address}}) has {{balance}} $VEGA tokens in {{tranches}} tranche(s) of the vesting contract.", - "Stake your Locked VEGA tokens!": "You can stake your $VEGA tokens even while locked.", - "Find out more about Staking.": "Use your $VEGA tokens to nominate a validator, earn rewards and participate in governance of the Vega network.", - "noVestingTokens": "You do not have any vesting $VEGA tokens. Switch to another Ethereum address to check what can be redeemed, or view all tranches", - "ethereumKey": "Ethereum key", - "checkingForProvider": "Checking for provider", - "In wallet": "In wallet", - "Not staked": "Not staked", - "viewKeys": "View keys", - "vegaKey": "Vega key", - "noService": "Looks like the Vega wallet service isn't running. Please start it and refresh the page", - "disconnect": "Disconnect", - "Checking Vega wallet status": "Checking Vega Wallet status", - "hostedSwitchLabel": "Use hosted wallet", - "walletServiceLabel": "Wallet service URL", - "walletLabel": "Wallet name", - "passphraseLabel": "Passphrase", - "vegaWalletConnect": "Connect", - "vegaWalletConnecting": "Connecting...", - "No token": "No token", - "Wallet service unavailable": "Wallet service not running at that url", - "Session expired": "Session expired", - "Invalid credentials": "Wallet or passphrase incorrect", - "Invalid wallet URL": "Invalid wallet URL", - "noKeys": "No keys", - "Stake VEGA tokens": "Stake $VEGA tokens", - "Tranche breakdown": "Tranche breakdown", - "Across all tranches": "Across all tranches", - "Token Vesting": "Vesting", - "Rewards": "Rewards", - "Governance": "Governance", - "Staking": "Staking", - "The vesting contract holds VEGA tokens until they have become unlocked.": "The vesting contract holds $VEGA tokens until they have become unlocked.", - "Once unlocked they can be redeemed from the contract so that you can transfer them between wallets.": "Once unlocked they can be redeemed from the contract so that you can transfer them between wallets.", - "Tokens are held in different Tranches. Each tranche has its own schedule for how the tokens are unlocked.": "Tokens are held in different Tranches. Each tranche has its own schedule for how the tokens are unlocked.", - "proposals": "Proposals", - "proposal": "Proposal", - "submittingProposal": "Submitting proposal", - "submit": "Submit", - "submitProposal": "Submit proposal", - "connectWalletToSubmitProposal": "Connect your wallet to submit a proposal", - "proposedEnactment": "Proposed enactment", - "Enacted": "Enacted", - "enactedOn": "Enacted on", - "enactedOn{{date}}": "Enacted on {{enactmentDate}}", - "status": "Status", - "state": "State", - "shouldPass": "Should pass", - "Participation": "Participation", - "Majority": "Majority", - "not reached": "not reached", - "openProposals": "Open proposals", - "closedProposals": "Closed proposals", - "noOpenProposals": "There are no open or yet to enact proposals", - "noClosedProposals": "There are no enacted or rejected proposals", - "noRejectedProposals": "No rejected proposals", - "Proposal rejected": "Proposal rejected", - "participationNotMet": "Participation not met", - "majorityNotMet": "Majority not met", - "noProposals": "There are no active network change proposals", - "updateNetworkParam": "Update Network Parameter", - "proposedOn": "Proposed on", - "proposedBy": "Proposed by", - "toEnactOn": "Enacts on", - "enactsOn{{date}}": "Enacts on {{enactmentDate}}", - "closesOn": "Closes on", - "closedOn": "Closed on", - "errorDetails": "Error details", - "proposedNewValue": "Proposed new value:", - "proposalChange": "Change {{key}} to {{value}}", - "STATE_DECLINED": "Declined", - "STATE_FAILED": "Failed", - "STATE_REJECTED": "Rejected", - "STATE_ENACTED": "Enacted", - "STATE_PASSED": "Passed", - "STATE_OPEN": "Open", - "STATE_WAITING_FOR_NODE_VOTE": "Waiting for node vote", - "UpdateNetworkParameter": "Network parameter", - "NewFreeform": "Freeform", - "setToPass": "Set to pass", - "setToFail": "Set to fail", - "tokenVotes": "Token votes", - "liquidityVotes": "Liquidity votes", - "castYourVote": "Cast your vote", - "yourVote": "Your vote", - "for": "For", - "against": "Against", - "majorityRequired": "Majority Required", - "participation": "Participation", - "majorityThreshold": "majority threshold", - "participationThreshold": "participation threshold", - "met": "met", - "notMet": "not met", - "governanceRequired": "Required", - "daysLeft": "{{daysLeft}} left to vote.", - "toVote": "to vote", - "voteFor": "Vote for", - "voteAgainst": "Vote against", - "tokenVote": "Token vote", - "tokenVotesFor": "Token votes for", - "tokenVotesAgainst": "Token votes against", - "totalTokensVoted": "Total tokens voted", - "liquidityProviderVote": "Liquidity provider vote", - "liquidityProviderVotesFor": "LP votes for", - "liquidityProviderVotesAgainst": "LP votes against", - "totalLiquidityProviderTokensVoted": "Total LP tokens voted", - "votingThresholdInfo": "If the token vote passes the participation threshold it will be the deciding vote. If not, the outcome will be determined by liquidity providers on this market.", - "noGovernanceTokens": "You need some VEGA tokens to participate in governance", - "youVoted": "You voted", - "voted": "Voted", - "changeVote": "Change vote", - "txRequested": "Confirm transaction in wallet", - "votePending": "Casting vote", - "voteError": "Something went wrong, and your vote was not seen by the network", - "back": "back", - "byTokenVote": "by token vote", - "byLiquidityVote": "by liquidity vote", - "byLPVote": "by LP vote", - "youDidNotVote": "Voting has ended. You did not vote", - "voteState_Yes": "For", - "voteState_No": "Against", - "voteState_NotCast": "Not cast", - "voteState_Enacted": "Enacted", - "voteState_Passed": "Passed", - "voteState_WaitingForNodeVote": "Waiting for node vote", - "voteState_Open": "Open", - "voteState_Declined": "Declined", - "voteState_Failed": "Failed", - "voteState_Rejected": "Rejected", - "Token address": "Token address", - "Vesting contract": "Vesting contract", - "Total supply": "Total supply", - "Circulating supply": "Circulating supply", - "vegaAssociatedWithKey": "{{symbol}} associated with a Vega key", - "There are {{nodeCount}} nodes with a shared stake of {{sharedStake}} VEGA tokens": "There are {{nodeCount}} nodes with a shared stake of {{sharedStake}} $VEGA tokens", - "Epoch": "Epoch", - "Started": "Started", - "Node invalid": "Node invalid", - "Next epoch in {{endText}}": "Next epoch in {{endText}}", - "Awaiting next epoch": "Waiting for next epoch to start...", - "Manage your stake": "Manage your stake", - "Add Stake": "Add Stake", - "Remove Stake": "Remove Stake", - "Total stake": "Total stake", - "Your stake": "Your stake", - "Your Stake On Node (This Epoch)": "Your Stake On Node (This Epoch)", - "Your Stake On Node (Next Epoch)": "Your Stake On Node (Next Epoch)", - "validatorTitle": "VALIDATOR: {{nodeName}}", - "validatorTitleFallback": "[no name]", - "VEGA ADDRESS / PUBLIC KEY": "VEGA ADDRESS / PUBLIC KEY", + "{{amount}} VEGA tokens have been returned to Ethereum wallet": "{{amount}} $VEGA tokens have been returned to Ethereum wallet", + "{{amount}} VEGA tokens have been returned to Vesting contract": "{{amount}} $VEGA tokens have been returned to Vesting contract", + "67% voting power required": "67% voting power required", "ABOUT THIS VALIDATOR": "ABOUT THIS VALIDATOR", - "ETHEREUM ADDRESS": "ETHEREUM ADDRESS", - "IP ADDRESS": "SERVER LOCATION", - "TOTAL STAKE": "TOTAL STAKE", - "STAKE SHARE": "STAKE SHARE", - "PENDING STAKE": "PENDING STAKE", - "STAKED BY OPERATOR": "STAKED BY OPERATOR", - "STAKED BY DELEGATES": "STAKED BY DELEGATES", - "OWN STAKE (THIS EPOCH)": "OWN STAKE (THIS EPOCH)", - "NOMINATED (THIS EPOCH)": "NOMINATED (THIS EPOCH)", - "Use maximum": "Use maximum", - "How much would you like to associate?": "How much would you like to associate?", - "VEGA Tokens": "$VEGA Tokens", - "SLP Tokens": "SLP Tokens", - "Connected Vega key": "Connected Vega key", - "What Vega key is going to control your stake?": "What Vega key is going to control your stake?", - "Where would you like to stake from?": "Where would you like to associate from?", - "associateNoVega": "Your connected Ethereum address does not have any $VEGA to associate", + "AboutThisValidatorDescription": "External URL provided by the validator linking to information about themselves", + "Account": "Account", + "ACCOUNT_TYPE_BOND": "Bond account", + "ACCOUNT_TYPE_EXTERNAL": "External account", + "ACCOUNT_TYPE_FEES_INFRASTRUCTURE": "Infrastructure fees account", + "ACCOUNT_TYPE_FEES_LIQUIDITY": "Liquidity fees account", + "ACCOUNT_TYPE_FEES_MAKER": "Maker fees account", + "ACCOUNT_TYPE_GENERAL": "General account", + "ACCOUNT_TYPE_GLOBAL_INSURANCE": "Global insurance account", + "ACCOUNT_TYPE_GLOBAL_REWARD": "Global reward account", + "ACCOUNT_TYPE_HOLDING": "Holding account", + "ACCOUNT_TYPE_INSURANCE": "Insurance account", + "ACCOUNT_TYPE_LP_LIQUIDITY_FEES": "Liquidity provider fees account", + "ACCOUNT_TYPE_MARGIN": "Margin account ", + "ACCOUNT_TYPE_NETWORK_TREASURY": "Network treasury account", + "ACCOUNT_TYPE_PENDING_FEE_REFERRAL_REWARD": "Pending fee referral reward account", + "ACCOUNT_TYPE_PENDING_TRANSFERS": "Pending transfers account", + "ACCOUNT_TYPE_REWARD_AVERAGE_POSITION": "Average position reward account", + "ACCOUNT_TYPE_REWARD_LP_RECEIVED_FEES": "Liquidity provider received fees reward account", + "ACCOUNT_TYPE_REWARD_MAKER_PAID_FEES": "Maker paid fees reward account", + "ACCOUNT_TYPE_REWARD_MAKER_RECEIVED_FEES": "Maker received fees reward account", + "ACCOUNT_TYPE_REWARD_MARKET_PROPOSERS": "Market proposers reward account", + "ACCOUNT_TYPE_REWARD_RELATIVE_RETURN": "Relative return reward account", + "ACCOUNT_TYPE_REWARD_RETURN_VOLATILITY": "Return volatility reward account", + "ACCOUNT_TYPE_REWARD_VALIDATOR_RANKING": "Validator ranking reward account", + "ACCOUNT_TYPE_SETTLEMENT": "Settlement account", + "ACCOUNT_TYPE_VESTED_REWARDS": "Vested rewards account", + "ACCOUNT_TYPE_VESTING_REWARDS": "Vesting rewards account", + "Across all tranches": "Across all tranches", + "activeNodes": "active nodes", + "Add Stake": "Add Stake", + "Add the Vega vesting token to your wallet to track how much you Vega you have in the vesting contract.": "Add the Vega vesting token to your wallet to track how much you Vega you have in the vesting contract.", + "addressMismatch": "Error: The address you are connected to is not the address the claim is valid for. To claim these tokens please connect with {{target}}.", + "addTokenToWallet": "Show this token in your Ethereum wallet", + "against": "Against", + "All the tokens in this tranche are locked and can not be redeemed yet.": "All the tokens in this tranche are locked and can not be redeemed yet.", + "All the tokens in this tranche are locked and must be assigned to a tranche before they can be redeemed.": "All the tokens in this tranche are locked and must be assigned to a tranche before they can be redeemed.", + "All VEGA tokens in the connected wallet is already associated with a Vega wallet/key": "All $VEGA tokens in the connected wallet are already associated with a Vega Wallet/key", + "All VEGA tokens vesting in the connected wallet have already been associated.": "All $VEGA tokens vesting in the connected wallet have already been associated.", + "AllProposals": "All proposals", + "AllValidators": "All validators", + "alreadyRedeemed": "Already redeemed", + "Amount of VEGA": "Amount of $VEGA", + "Anonymous": "Anonymous", + "Any Tokens that have been nominated to a node will sacrifice any Rewards they are due for the current epoch. If you do not wish to sacrifices fees you should remove stake from a node at the end of an epoch before disassocation.": "If you disassociate tokens that have been nominated to a node, you will sacrifice any rewards they are due for the current epoch. If you do not wish to sacrifice rewards, remove your stake from a node at the end of an epoch before disassociating.", + "approval (% validator voting power)": "approval (% validator voting power)", + "approvalStatus": "Approval status", + "Approve VEGA tokens for staking on Vega": "Approve $VEGA tokens for staking on Vega", + "approvers": "Approvers", + "as soon as possible": "now", + "Asset change": "Asset change", + "AssetID": "Asset ID", + "assets": "Assets", + "assetSpecification": "Asset specification", + "associate": "Associate", + "Associate VEGA tokens": "Associate $VEGA tokens", + "Associate VEGA Tokens with key": "Associate $VEGA Tokens with key", + "associateButton": "Associate $VEGA tokens with wallet", + "Associated": "Associated", + "associated": "Associated", + "associatedVega": "Associated", + "associatedWithVegaKeys": "Associated with Vega keys", "associateInfo1": "To participate in governance or to nominate a Validator you'll need to associate $VEGA tokens with a Vega wallet/key.", "associateInfo2": "If you already have $VEGA tokens nominated to validators, your newly associated tokens will automatically be nominated to the same validators, in the same proportion.", - "Associate VEGA Tokens with key": "Associate $VEGA Tokens with key", - "Wallet": "Wallet", - "Associating Tokens": "Associating with Vega key", - "associationPendingWaitingForVega": "Waiting for Vega to credit key...", - "Done": "Done", - "Associating {{amount}} VEGA tokens with Vega key {{vegaKey}}": "Associating {{amount}} $VEGA tokens with Vega key {{vegaKey}}", - "pendingAssociationText": "The Vega network requires a number of confirmations on Ethereum before crediting your Vega key with your tokens. You can see the number of confirmations that are required in the network parameters. This page will update once complete or you can come back and check your Vega wallet to see if it is ready to use.", - "You have no VEGA tokens in your connected wallet. You will need to buy some VEGA tokens from an exchange in order to stake using this method.": "You have no $VEGA tokens in your connected wallet. You will need to buy some $VEGA tokens from an exchange in order to stake using this method.", - "All VEGA tokens in the connected wallet is already associated with a Vega wallet/key": "All $VEGA tokens in the connected wallet are already associated with a Vega Wallet/key", - "VEGA tokens are approved for staking": "$VEGA tokens are approved for staking", - "Approve VEGA tokens for staking on Vega": "Approve $VEGA tokens for staking on Vega", - "You have no VEGA tokens currently vesting.": "You have no $VEGA tokens currently vesting.", - "All VEGA tokens vesting in the connected wallet have already been associated.": "All $VEGA tokens vesting in the connected wallet have already been associated.", - "Any Tokens that have been nominated to a node will sacrifice any Rewards they are due for the current epoch. If you do not wish to sacrifices fees you should remove stake from a node at the end of an epoch before disassocation.": "If you disassociate tokens that have been nominated to a node, you will sacrifice any rewards they are due for the current epoch. If you do not wish to sacrifice rewards, remove your stake from a node at the end of an epoch before disassociating.", - "Use this form to disassociate VEGA tokens with a Vega key. This returns them to either the Ethereum wallet that used the Staking bridge or the vesting contract.": "Use this form to disassociate $VEGA tokens from a Vega key. This returns them to the Ethereum wallet that connected to either the staking bridge or the vesting contract.", - "What Vega wallet are you removing Tokens from?": "What Vega Wallet are you removing tokens from?", - "What tokens would you like to return?": "What tokens would you like to return?", - "You have no VEGA tokens currently staked through your connected Vega wallet.": "You have no $VEGA tokens currently staked through your connected Vega Wallet.", - "You have no VEGA tokens currently staked through your connected Eth wallet.": "You have no $VEGA tokens currently staked through your connected Ethereum wallet.", - "Dissociating Tokens": "Disassociating Tokens", - "Dissociating {{amount}} VEGA tokens from Vega key {{vegaKey}}": "Disassociating {{amount}} $VEGA tokens from Vega key {{vegaKey}}", - "backToStaking": "Back to Staking", - "{{amount}} VEGA tokens have been returned to Vesting contract": "{{amount}} $VEGA tokens have been returned to Vesting contract", - "{{amount}} VEGA tokens have been returned to Ethereum wallet": "{{amount}} $VEGA tokens have been returned to Ethereum wallet", - "Disassociate VEGA Tokens from key": "Disassociate $VEGA Tokens from key", - "Read about Vesting on Vega": "Read about Vesting on Vega", - "Governance is coming soon": "Governance is coming soon", - "Staking is coming soon": "Staking is coming soon", - "VESTING VEGA TOKENS": "in vesting contract", - "stakingIntro": "Earn a share of trading fees and treasury rewards for each full epoch staked.", - "stakingConfirm": "Open your wallet app to confirm", - "associateButton": "Associate $VEGA tokens with wallet", - "nodeQueryFailed": "Could not get data for validator {{node}}", - "stakeAddPendingTitle": "Adding {{amount}} $VEGA to validator {{node}}", - "stakeRemovePendingTitle": "Removing {{amount}} $VEGA from validator {{node}}", - "timeForConfirmation": "Waiting for confirmation that your change in nomination has been received", - "stakeAddSuccessTitle": "At the beginning of the next epoch your $VEGA will be nominated to the validator", - "stakeRemoveSuccessTitle": "{{amount}} $VEGA has been removed from validator {{node}}", - "stakeRemoveSuccessMessage": "It will be applied in the next epoch", - "stakeRemoveNowSuccessMessage": "It will be applied immediately", - "stakeFailed": "Failed to delegate to validator {{node}}", - "Remove {{amount}} VEGA tokens": "Remove {{amount}} $VEGA tokens", - "at the end of epoch": "at the end of epoch", - "undelegateSubmitButton": "{{amount}} {{when}}", - "Removing stake mid epoch will forsake any staking rewards from that epoch": "Removing stake mid epoch will forsake any staking rewards from that epoch", - "minimumNomination": "Your nomination must be greater than or equal to {{minTokens}} $VEGA", - "lpTokensInvalidToken": "Address {{address}} is not a valid SLP token address for $VEGA", - "lpTxSuccessButton": "Review liquidity stake", - "depositLpTokensHeading": "How much would you like to deposit?", - "depositLpSubmitButton": "Deposit SLP", - "depositLpApproveButton": "Approve SLP tokens for deposit", - "depositLpInsufficientBalance": "You do not have tokens to deposit.", - "depositLpAlreadyStaked": "You have already staked your SLP tokens, go to withdraw in order withdraw these before you can add more.", - "depositLpCalloutTitle": "You can only make one deposit at a time", - "depositLpCalloutBody": "If you want to add more SLP tokens later you will need to unstake first or use a different Ethereum key.", - "depositLpSuccessCalloutTitle": "You SLP tokens have been deposited and will start earning rewards from the next epoch", - "depositLpSuccessCalloutBody": "You will be rewarded for each full epoch your SLP tokens are staked", - "withdrawLpWithdrawAllButton": "Unstake SLP and Withdraw $VEGA rewards", - "withdrawLpNoneDeposited": "You have no SLP tokens deposited or rewards accumulated", - "withdrawAllLpSuccessCalloutTitle": "Your SLP tokens and rewards have been sent to your Ethereum address", - "Dissociate VEGA tokens": "Disassociate $VEGA tokens", - "DisassociateVegaTokensFromWallet": "Disassociate $VEGA tokens from your Vega wallet", - "Early Investors": "Early Investors", - "Team": "Team", - "Community": "Community", - "Public Sale": "Public Sale", - "Check to see if you can redeem unlocked VEGA tokens": "Check to see if you can redeem unlocked $VEGA tokens", - "To use your tokens on the Vega network they need to be associated with a Vega wallet/key.": "To use your tokens on the Vega network they need to be associated with a Vega Wallet/key.", - "This can happen both while held in the vesting contract as well as when redeemed.": "This can happen both while held in the vesting contract as well as when redeemed.", - "Get a Vega wallet": "Get a Vega Wallet", - "Associate VEGA tokens": "Associate $VEGA tokens", - "VEGA token holders can vote on proposed changes to the network and create proposals.": "$VEGA token holders can vote on proposed changes to the network and create proposals.", - "VEGA token holders can nominate a validator node and receive staking rewards.": "$VEGA token holders can nominate a validator node and receive staking rewards.", - "Use your Vega tokens": "Use your Vega tokens", - "Check your vesting VEGA tokens": "Check your vesting $VEGA tokens", - "Tokens from this Tranche have been redeemed": "Tokens from this Tranche have been redeemed", - "You have redeemed {{redeemedAmount}} VEGA tokens from this tranche. They are now free to transfer from your Ethereum wallet.": "You have redeemed {{redeemedAmount}} $VEGA tokens from this tranche. They are now free to transfer from your Ethereum wallet.", - "The VEGA token address is {{address}}, make sure you add this to your wallet to see your tokens": "The $VEGA token address is {{address}}, make sure you add this to your wallet to see your tokens", - "Go to staking or governance to see how you can use your unlocked tokens": "Go to staking or governance to see how you can use your unlocked tokens", - "liquidityNav": "DEX Liquidity", - "liquidityIntro": "You can read about our incentive program in this blog post.", - "liquidityStep1Title": "Provide liquidity on one of the markets below and get your SLP tokens.", - "liquidityStep1Body": "You will need to add the SushiSwap market/token address to your wallet to see your SLP tokens.", - "liquidityStep2Title": "Stake these SLP tokens into the appropriate contract below.", - "liquidityStep2Body": "You can't increase your stake without un-staking first so consider how much you stake and when.", - "liquidityStep3Title": "Wait for a full epoch, get a share of the incentive for each full epoch you stake.", - "liquidityStep3Body": "The reward amount is divided by the amount of SLP tokens staked in that epoch. The APY on each pool is indicative based on the current state, this will change over time and is not guaranteed. You will not be entitled to rewards from the epoch that you un-staked in.", - "liquidityStep4Title": "Un-stake or withdraw to receive your rewards.", - "liquidityStep4Body": "Upon un-staking, your Ethereum key will be credited with its share of $VEGA tokens for each full epoch that it was staked and all SLP tokens staked. Withdrawing your rewards will credit your earned VEGA to your wallet while leaving you SLP staked to earn further rewards.", - "liquidityTokensWalletTitle": "SLP Tokens in connected wallet", - "liquidityTokensWalletIntro": "The following tokens can be staked to earn $VEGA", - "liquidityTokensContractTitle": "SLP Tokens earning rewards", - "liquidityTotalAvailableRewards": "Total available rewards", - "liquidityRewardsTitle": "Active liquidity rewards", - "liquidityOnsenIntro": "Earn rewards for providing liquidity on the", - "liquidityOnsenLinkText": "SushiSwap Onsen Menu", - "liquidityOnsenButtonText": "View the SushiSwap Onsen Menu", - "liquidityOnsenHowItWorks": "How it works", - "liquidityOnsenFAQ": "FAQ", - "liquidityRewardsTitlePrevious": "Previous liquidity rewards", - "liquidityTokenSushiAddress": "SLP pool/token address", - "liquidityTokenContractAddress": "Liquidity token contract address", - "rewardPerEpoch": "Reward per epoch (split between reward pool)", - "rewardTokenContractAddress": "Reward token contract address ($VEGA)", - "slpTokenContractAddress": "SLP token contract address", - "lpTokensInRewardPool": "Tokens in reward pool", - "lpTokensEstimateAPY": "Estimated APY", - "liquidityTokenWithdrawBalance": "Withdrawal balance", - "liquidityTokenWithdrawRewards": "Withdrawal rewards", - "usersLpTokens": "Your SLP tokens in connected wallet", - "usersStakedLPTokens": "Your SLP tokens in reward pool", - "usersPendingStakeLPTokens": "Your SLP tokens in reward pool (next epoch)", - "usersShareOfPool": "Your share of pool", - "usersAccumulatedRewards": "Your accumulated rewards", - "withdrawFromRewardPoolButton": "Withdraw rewards and unstake", - "liquidityTotalAvailableRewardsBalance": "Balance", - "liquidityStakedToken": "SLP Token", - "liquidityStakedIntro": "Withdrawing your SLP tokens from the contract will also claim the reward balance", - "liquidityStakedBalance": "SLP token balance", - "liquidityStakedRewards": "Earned rewards", - "liquidityStakedWithdraw": "Withdraw", - "liquidityTokenTitle": "SLP Token", - "liquidityTokenBalance": "Balance", - "liquidityTokenDeposit": "Deposit", - "liquidityTokenApprove": "Approve", - "liquidityComingSoon": "Liquidity rewards coming soon", - "lpEndedParagraph": "You can only withdraw your rewards and unstake. Upon unstaking, your Ethereum key will be credited with all SLP tokens staked and its share of $VEGA tokens for each full epoch that it was staked.", - "lpEndedTitle": "This liquidity incentive ended on 03 December 2021 14:52 UTC", - "lpDiscordPrompt": "Watch our Discord for future ways to earn $VEGA!", - "Keep track of locked tokens in your wallet with the VEGA (VESTING) token.": "Keep track of locked tokens in your wallet with the $VEGA (VESTING) token.", - "The token address is {{address}}. Hit the add token button in your ERC20 wallet and enter this address.": "The token address is {{address}}. Hit the add token button in your ERC20 wallet and enter this address.", - "mainnetDisableHome": "You will be able to use your $VEGA tokens on the Vega network to nominate Validator nodes and participate in governance.", - "vegaInWallet": "{{symbol}} in wallet", - "Vesting associated": "Vesting associated", - "Wallet associated": "Wallet associated", - "alreadyRedeemed": "Already redeemed", - "stakeNodeNone": "You need to associate some $VEGA before you can stake", - "stakeNodeWrongVegaKey": "Your Ethereum wallet indicates you have associated tokens for staking. However, there are none available to stake. You may be connected to the wrong Vega key, or Vega is still confirming your associations", - "redeemComingSoon": "Redeem is coming soon", - "associatedVega": "Associated", - "blockCountdown": "Waiting for {{amount}} more confirmations...", - "stakingNodeNotFound": "Could not find a node with ID {{node}}", - "copyToClipboard": "Copy to clipboard", - "copied!": "Copied!", - "viewAllTranches": "View all tranches", - "id": "ID", - "noVersionFound": "Version could not be found, most likely your wallet version is <0.9.2 which is not supported.", - "unsupportedVersion": "Looks like you're running an outdated version of GoWallet. You're running {{version}} but {{requiredVersion}} is required.", - "stakedValidators": "Staked Validators", - "governance": "Governance", - "staking": "Staking", - "assets": "Assets", - "collateral": "Collateral", - "associate": "Associate", - "disassociate": "Disassociate", - "associatedWithVegaKeys": "Associated with Vega keys", - "thisEpoch": "This Epoch", - "nextEpoch": "Next epoch", - "toSeeYourRewardsConnectYourWallet": "TO SEE YOUR REWARDS, CONNECT YOUR WALLET", - "rewardsIntro": "Earn rewards and infrastructure fees for trading and maintaining the network.", - "rewardsCallout": "Rewards are credited {{duration}} after the epoch ends.", - "rewardsCalloutDetail": "This delay is set by a network parameter", - "noRewards": "The Vega key has not been credited any rewards since the previous network checkpoint.", - "seeHowRewardsAreCalculated": "See how rewards are calculated", - "rewardType": "Reward type", - "rewardsAndFeesReceived": "Rewards and fees received", - "ThisDoesNotIncludeFeesReceivedForMakersOrLiquidityProviders": "This does not include fees received for makers or liquidity providers", - "totalDistributed": "Total distributed", - "earnedByMe": "Earned by me", - "noRewardsHaveBeenDistributedYet": "NO REWARDS HAVE BEEN DISTRIBUTED YET", - "rewardsColAssetHeader": "ASSET", - "rewardsColStakingHeader": "STAKING", - "rewardsColStakingTooltip": "Staking rewards supplement infrastructure fees in the early stages of the network, rewarding validators and those who stake them for maintaining the network", - "rewardsColInfraHeader": "INFRA FEES", - "rewardsColInfraTooltip": "Infrastructure fees are incurred across the network during trading. They are distributed to validators according to their share of total stake on the network, and passed onto those who stake them, proportionate to their own stake after validator commission is taken", - "rewardsColPriceTakingHeader": "PRICE TAKING", - "rewardsColPriceTakingTooltip": "Price taking rewards are based on the proportion of the total maker fees you paid while trading, on markets where there is a funded reward", - "rewardsColPriceMakingHeader": "PRICE MAKING", - "rewardsColPriceMakingTooltip": "Price making rewards are based on the proportion of the total maker fees you received while trading, on markets where there is a funded reward", - "rewardsColLiquidityProvisionHeader": "LIQUIDITY PROVISION", - "rewardsColLiquidityProvisionTooltip": "Liquidity provision rewards are distributed based on how much you have earned in liquidity fees, funded by a liquidity reward pool for that market", - "rewardsColMarketCreationHeader": "MARKET CREATION", - "rewardsColMarketCreationTooltip": "Market creation rewards are paid out to the creator of any market that exceeds a set threshold of cumulative volume in a given epoch, currently {{marketCreationQuantumMultiple}}", - "rewardsColTotalHeader": "TOTAL", - "ofTotalDistributed": "of total distributed", - "checkBackSoon": "Check back soon", - "yourStake": "Your stake", - "reward": "Reward", - "shareOfReward": "Share of reward", - "received": "Payout time", - "withdrawPreparedWarningHeading": "Only start a withdrawal when you are ready to pay the gas to release on Ethereum", - "withdrawPreparedWarningText1": "If you proceed beyond this stage, but do not complete the withdrawal on Ethereum, it will not be possible to cancel or alter your withdrawal request.", - "withdrawPreparedWarningText2": "To ensure your assets are not lost, you must pay gas on Ethereum to complete the final step of the withdrawal process. Gas costs per withdrawal have been between $100 and $200.", - "withdrawalsPreparedWarningHeading": "Complete these withdrawals before the next checkpoint restore", - "withdrawalsPreparedWarningText": "Prepared withdrawals are not stored between network resets meaning you will not have the information required to complete a withdrawal.", - "withdrawPageHeading": "Withdraw", - "withdrawPageText": "Use this form to withdraw/release assets from your Vega wallet to their native chain.", - "withdrawPageInfoCalloutTitle": "How ERC20 withdrawals work on Vega", - "withdrawPageInfoCalloutText": "To withdraw from Vega, the network needs to agree that a party can withdraw funds (to ensure they are available). Once that happens, it returns a signature that is used in an Ethereum transaction to send the tokens to the given Ethereum address.", - "pendingWithdrawalsCalloutTitle": "You have incomplete withdrawals", - "pendingWithdrawalsCalloutText": "You have withdrawals that have been released from the Vega network but not yet completed on Ethereum.", - "pendingWithdrawalsCalloutButton": "View incomplete withdrawals", - "withdrawFormAssetLabel": "What would you like to withdraw?", - "withdrawFormNoAsset": "You don't have any assets to withdraw", - "withdrawFormAmountLabel": "How much would you like to withdraw?", - "withdrawFormSubmitButtonIdle": "Withdraw {{amount}} {{symbol}} tokens", - "withdrawFormSubmitButtonPending": "Preparing", - "withdrawalsTitle": "Withdrawals", - "withdrawalsSubtitle": "Connect your Vega wallet to complete a withdrawal. These withdrawals will be completed with an Ethereum transaction.", - "withdrawalsText": "These withdrawals need to be completed with an Ethereum transaction.", - "withdrawalsNone": "You don't have any pending withdrawals.", - "withdrawalsCompleteButton": "Finish withdrawal", - "withdrawalTransaction": "Transaction ({{foreignChain}})", - "signature": "Signature", - "created": "Created", - "toEthereum": "To (Ethereum)", - "from": "From", - "txButtonComplete": "Complete", - "txButtonActionRequired": "Action required in Ethereum wallet", - "txButtonAwaiting": "Awaiting Ethereum transaction", - "txButtonFailure": "Ethereum transaction failed", - "transaction": "Transaction", - "associated": "Associated", - "notAssociated": "Not Associated", - "title": "Governance", - "Use the Ethereum wallet you want to send your tokens to. You'll also need enough Ethereum to pay gas.": "Connect to the Ethereum wallet that holds your $VEGA tokens to see what can be redeemed from vesting tranches. To redeem tokens you will need some ETH to pay gas fees.\n", - "Connect to see your stake": "Connect to see your stake", - "Staked on Vega validator": "Associated to Vega key", - "You can associate tokens while they are held in the vesting contract, when they unlock you will need to disassociate them before they can be redeemed.": "You can associate tokens while they are held in the vesting contract, when they unlock you will need to disassociate them before they can be redeemed.", - "Nominate Stake to Validator Node": "Select a validator to nominate", - "successfullAssociationMessage": "Vega key {{vegaKey}} can now participate in governance and nominate a validator with your associated $VEGA.", - "stakingStep2Text": "Your tokens need to be associated with a Vega Wallet so that you can control your stake", - "stakingStep3": "Step 3. Select the validator you'd like to nominate", - "stakeAddSuccessMessage": "You can cancel your nomination at any time", - "How much to Add in next epoch?": "How much do you want to add in next epoch?", - "How much to Remove?": "How much do you want to remove?", - "as soon as possible": "now", - "Want to remove your stake before the epoch ends?": "Do you want to remove your stake when the epoch ends?", - "Want to remove your stake at the end of the epoch?": "Do you want to remove your stake now?", - "Switch to form for immediate removal": "Switch to remove now", - "Switch to form for removal at end of epoch": "Switch to remove at end of epoch", - "Nominate a validator": "Nominate validator", - "View Governance proposals": "View proposals", - "seeRejectedProposals": "See rejected proposals", - "vegaWallet": "Vega Wallet", - "rewardsComingSoon": "Rewards is coming soon", - "associationChoice": "You have $VEGA tokens held by the vesting contract. Would you like to associate those or associate $VEGA directly from your wallet?", - "footerLinksText": "Known issues and feedback on the Feedback board and Github", - "connectEthWallet": "Connect Ethereum wallet", - "connectEthWalletToAssociate": "Connect Ethereum wallet to associate $VEGA", - "connectVegaWallet": "Connect Vega wallet", - "connectVegaWalletToUseAssociated": "Connect Vega wallet to use associated $VEGA", - "getWallet": "Don't have a Vega wallet yet?", - "getWalletLink": "Get a Vega wallet", - "useConnectedWallet": "Use connected wallet", - "enterAddress": "Enter address manually", - "invalidAddress": "Looks like that address isn't a valid Ethereum address, please check and try again", - "Signature": "Signature", - "voteFailedReason": "Vote closed. Failed due to: ", - "Passed": "Passed", - "votePassed": "Vote passed.", - "WaitingForNodeVote": "Waiting for nodes to validate asset. ", - "transactionHashPrompt": "Transaction hash will appear here once the transaction is approved in your Ethereum wallet", - "newWalletVersionAvailable": "A new Vega wallet is available 🎉. ", - "downloadNewWallet": "Download {{newVersionAvailable}}", - "errorLoadingTranches": "Error loading tranches. Please try again later.", - "pendingNomination": "Pending Nomination", - "pendingNominationNextEpoch": "Pending nomination for next epoch: {{pendingAmount}} $VEGA", - "cancelPendingEpochNomination": "Cancel pending epoch nomination", - "removingPendingStake": "Removing pending stake of {{pendingAmount}} $VEGA", - "failedToRemovePendingStake": "Failed to remove pending stake of {{pendingAmount}} $VEGA", - "pleaseTryAgain": "Please try again later.", - "injected.name": "Injected", - "injected.text": "Connect with the provider in your browser", - "walletConnect.name": "Mobile", - "walletConnect.text": "Scan QR code with your mobile wallet", - "resourceNotFound": "Resource Not Found", - "Or": "Or", - "addTokenToWallet": "Show this token in your Ethereum wallet", - "date": "Date", - "noEthereumProviderError": "No Ethereum browser extension detected, install MetaMask on desktop or visit from a dApp browser on mobile", - "unsupportedChainIdError": "You're connected to an unsupported network", - "userRejectionError": "Please authorise this website to access your Ethereum account", - "unknownEthereumConnectionError": "An unknown error occurred. Check the console in your browser's web developer tools for more details", - "validatorTableIntro": "View the validator profile pitches and discussion", - "onTheForum": "on the forum", - "readMoreStaking": "Read more about staking on Vega", - "readMoreGovernance": "Read more about Vega governance", - "readMoreValidators": "Read more about validators", - "networkDown": "This site is not currently connecting to the network please try again later.", - "ethTransactionModalTitle": "Ethereum Transactions", - "confirmed": "Confirmed", - "pending": "Pending", - "confirmationsRemaining": "{{confirmations}} of {{required}} blocks to go", - "pendingTransactions": "Pending transactions", - "noTransactions": "No transactions", - "networkRestoring": "The network is less than {{bootstrapBlockCount}} blocks old, it could be in the process of restoring from a checkpoint", - "type": "Type", - "rejectionReason": "Rejection reason", - "reference": "Reference", - "voteBreakdown": "Vote breakdown", - "expectedToPass": "Expected to pass", - "majorityMet": "Token majority met", - "majorityLPMet": "Liquidity majority met", - "participationMet": "Token participation met", - "participationLPMet": "Liquidity participation met", - "tokenForProposal": "Tokens for proposal", - "tokenLPForProposal": "Liquidity shares for proposal", - "tokensAgainstProposal": "Tokens against proposal", - "participationRequired": "Participation required", - "numberOfVotingParties": "Number of voting parties", - "totalTokensVotes": "Total tokens voted", - "totalTokenVotedPercentage": "Total tokens voted percentage", - "numberOfForVotes": "Number of votes for", - "numberOfAgainstVotes": "Number of votes against", - "yesPercentage": "Yes percentage", - "noPercentage": "No percentage", - "proposalJson": "Full proposal JSON", - "proposalDetails": "Proposal details", - "marketSpecification": "Market specification", - "viewMarketJson": "View market JSON", - "marketId": "Market ID", - "marketName": "Market name", - "marketCode": "Market code", - "proposalDescription": "Description", - "currentlySetTo": "Currently expected to ", - "currently": "currently", - "finalOutcomeMayDiffer": "Final outcome may differ", - "votingPower": "Voting power", - "normalisedVotingPower": "Normalised voting power", - "unnormalisedVotingPower": "Unnormalised voting power", - "noValidators": "No validators", - "validator": "Validator", - "stake": "Stake", - "myStake": "My stake", - "stakeShare": "Stake share", - "stakedByOperator": "Staked by operator", - "stakedByDelegates": "Staked by delegates", - "stakedByMe": "Staked by me", - "totalStake": "Total stake", - "pendingStake": "Pending stake", - "myPendingStake": "My pending stake", - "totalPenalties": "Total penalties", - "noPenaltyDataFromLastEpoch": "No penalty data from last epoch", - "stakeNeededForPromotion": "Stake needed for promotion", - "Nodes": "Nodes", - "status-tendermint": "Consensus", - "status-ersatz": "Standby", - "status-pending": "Candidate", - "ersatzDescription1": "To be promoted, a standby validator must have more than the lowest consensus stake, plus a bonus given to existing validators, and only one standby validator can be promoted per epoch. Currently this requires a minimum of", - "ersatzDescription2": "stake assuming no performance penalty incurred.", - "pendingDescription1": "Anyone can", - "pendingDescriptionLinkText": "set up and run a node on Vega", - "pendingDescription2": ". A node can move from being a candidate into standby based on how much nomination it attracts, assuming it has proven reliability by sending heartbeats to the network.", - "n/a": "N/A", - "pass": "pass", - "fail": "fail", - "New asset": "New asset", - "Asset change": "Asset change", - "New market": "New market", - "Market change": "Market change", - "Network parameter": "Network parameter", - "Change": "Change", - "Unknown proposal": "Unknown proposal", - "ERC20ContractAddress": "ERC20 contract address", - "MaxFaucetAmountMint": "Max faucet amount mint", - "Code": "Code", - "settled future": "settled future", - "Symbol": "Symbol", - "Max faucet amount mint": "Max faucet amount mint", - "left to vote": "left to vote", - "View": "View", - "CloseTimeTooSoon": "Close time too soon", - "CloseTimeTooLate": "Close time too late", - "EnactTimeTooSoon": "Enact time too soon", - "EnactTimeTooLate": "Enact time too late", - "InsufficientTokens": "Insufficient tokens", - "InvalidInstrumentSecurity": "Invalid instrument security", - "NoProduct": "No product", - "UnsupportedProduct": "Unsupported product", - "InvalidFutureMaturityTimestamp": "Invalid future maturity timestamp", - "ProductMaturityIsPassed": "Product maturity is passed", - "NoTradingMode": "No trading mode", - "UnsupportedTradingMode": "Unsupported trading mode", - "NodeValidationFailed": "Node validation failed", - "MissingBuiltinAssetField": "Missing builtin asset field", - "MissingERC20ContractAddress": "Missing ERC20 contract address", - "InvalidAsset": "Invalid asset", - "IncompatibleTimestamps": "Incompatible timestamps", - "NoRiskParameters": "No risk parameters", - "NetworkParameterInvalidKey": "Network parameter invalid key", - "NetworkParameterInvalidValue": "Network parameter invalid value", - "NetworkParameterValidationFailed": "Network parameter validation failed", - "OpeningAuctionDurationTooSmall": "Opening auction duration too small", - "OpeningAuctionDurationTooLarge": "Opening auction duration too large", - "MarketMissingLiquidityCommitment": "Market missing liquidity commitment", - "CouldNotInstantiateMarket": "Could not instantiate market", - "InvalidFutureProduct": "Invalid future product", - "MissingCommitmentAmount": "Missing commitment amount", - "InvalidFeeAmount": "Invalid fee amount", - "InvalidShape": "Invalid shape", - "InvalidRiskParameter": "Invalid risk parameter", - "MajorityThresholdNotReached": "Majority threshold not reached", - "ParticipationThresholdNotReached": "Participation threshold not reached", - "InvalidAssetDetails": "Invalid asset details", - "FilterProposals": "Filter proposals", - "FilterProposalsDescription": "Filter by proposal ID or proposer ID", - "Freeform proposal": "Freeform proposal", - "NewProposal": "New proposal", - "CreateProposalAndDownloadJSONToShare": "Create proposal and download JSON to share", - "SubmitAnAgreedProposalFromTheForum": "Submit an agreed proposal from the forum", - "ProposalTypeQuestion": "What type of proposal would you like to make?", - "NetworkParameterProposal": "Update network parameter proposal", - "parameter": "parameter", - "NewMarketProposal": "New market proposal", - "UpdateMarketProposal": "Update market proposal", - "UpdateMarketStateProposal": "Update market state proposal", - "UpdateReferralProgramProposal": "Update referral program proposal", - "UpdateVolumeDiscountProgramProposal": "Update volume discount program proposal", - "MarketChange": "Market change", - "MarketStateChange": "Market state change", - "MarketDetails": "Market details", - "NewAssetProposal": "New asset proposal", - "UpdateAssetProposal": "Update asset proposal", - "NewFreeformProposal": "New freeform proposal", - "NewRawProposal": "New proposal", - "NewTransferProposal": "New transfer proposal", - "CancelTransferProposal": "Cancel transfer proposal", - "MARKET_STATE_UPDATE_TYPE_RESUME": "Resume market", - "MARKET_STATE_UPDATE_TYPE_SUSPEND": "Suspend market", - "MARKET_STATE_UPDATE_TYPE_TERMINATE": "Terminate market", - "MinProposalRequirements": "You must have at least {{value}} VEGA associated to make a proposal", - "MinProposalVoteRequirements": "You must have at least {{value}} VEGA associated to vote on this proposal", - "totalSupply": "Total Supply", - "viaWallet": "via wallet", - "viaContract": "via vesting", - "ProposalDocsPrefix": "For guidance on how to make proposals, see", - "NetworkParameter": "Network parameter", - "NewMarket": "New market", - "NewMarketPerpetualProduct": "New market - perpetual", - "NewMarketFutureProduct": "New market - future", - "NewMarketSpotProduct": "New market - spot", - "UpdateMarket": "Update market", - "UpdateMarketState": "Update market state", - "UpdateReferralProgram": "Update referral program", - "UpdateVolumeDiscountProgram": "Update volume discount program", - "NewAsset": "New asset", - "UpdateAsset": "Update asset", - "NewTransfer": "New transfer", - "CancelTransfer": "Cancel transfer", - "AssetID": "Asset ID", - "Freeform": "Freeform", - "RawProposal": "Let me choose (raw proposal)", - "SubmitAgreedRawProposal": "Submit agreed raw proposal", - "UseMin": "Use minimum", - "UseMax": "Use maximum", - "Proposal": "Proposal", - "ProposalRationale": "Proposal rationale", - "ProposalTitle": "Title", - "ProposalTitleText": "Tell people what you are proposing and why (100 characters or less)", - "ProposalsGuide": "proposals guide", - "ProposalDescription": "Description", - "ProposalDescriptionText": "Full justification for what you are proposing (20,000 characters or less). Markdown is recommended. When linking to external resources please use IPFS", - "ProposalTerms": "Proposal terms (JSON format)", - "ProposalTermsText": "For more information visit", - "ProposalReference": "Reference", - "ProposalVoteTitle": "Vote deadline", - "ProposalVoteAndEnactmentTitle": "Vote deadline and enactment", - "ProposalVoteDeadline": "Time till voting closes", - "ProposalEnactmentDeadline": "Time till enactment (must be equal to or after vote close)", - "ProposalValidationDeadline": "Time till ERC-20 asset validation. Maximum value is affected by the vote deadline.", - "ThisWillSetVotingDeadlineTo": "This will set the voting deadline to", - "ThisWillSetEnactmentDeadlineTo": "This will set the enactment date to", - "ThisWillSetValidationDeadlineTo": "This will set the validation deadline to", - "Hours": "hours", - "ThisWillAdd2MinutesToAllowTimeToConfirmInWallet": "Note: 2 minutes of extra time are added when you choose the minimum value. This gives you time to confirm the proposal in your wallet.", - "ProposalWillFailIfEnactmentIsEarlierThanVotingDeadline": "The proposal will fail if enactment is earlier than the voting deadline", - "ProposalWillFailIfEnactmentIsBelowTheMinimumDeadline": "The proposal will fail if enactment deadline is below the minimum", - "ProposalWillFailIfVotingIsBelowTheMinimumDeadline": "The proposal will fail if voting deadline is below the minimum", - "ProposalWillFailIfEnactmentIsAboveTheMaximumDeadline": "The proposal will fail if enactment deadline is above the maximum", - "ProposalWillFailIfVotingIsAboveTheMaximumDeadline": "The proposal will fail if voting deadline is above the maximum", - "SelectAMarketToChange": "Select a market to change", - "MarketName": "Market name", - "MarketCode": "Market code", - "MarketId": "Market ID", - "ProposeNewMarketTerms": "terms.changes.newMarket (JSON format)", - "ProposeUpdateMarketTerms": "terms.updateMarket.changes (JSON format)", - "SelectAParameterToChange": "Select a parameter to change", - "SelectParameter": "Select parameter", - "SelectMarket": "Select market", - "CurrentValue": "Current value", - "NewProposedValue": "New proposed value", - "MoreProposalsInfo": "To see Explorer data on proposals visit", - "MoreNetParamsInfo": "To see Explorer data on network params visit", - "MoreMarketsInfo": "To see Explorer data on existing markets visit", - "MoreAssetsInfo": "To see Explorer data on existing assets visit", - "ProposalNotFound": "Proposal not found", - "ProposalNotFoundDetails": "The proposal you are looking for is not here, it may have been enacted before the last chain restore. You could check the Vega forums/discord instead for information about it.", - "FreeformProposal": "Freeform proposal", - "Id": "ID", - "unknownReason": "unknown reason", - "votingEnded": "Voting has ended.", - "STATUS": "STATUS", - "ProposalMinimumAmounts": "Different proposal types can have different minimum token requirements. You must have the greater of the proposal minimum or spam protection minimum from the table below", - "SpamProtectionMin": "Spam protection minimum", - "ListAsset": "List Asset", - "ListAssetDescription": "This asset needs to be listed on the collateral bridge before it can be used.", - "ListAssetAction": "List asset", - "Proposals": "Proposals", - "Validators": "Validators", - "Redeem": "Redeem", - "validatorFormIntro": "To learn more about validators and how scores are calculated,", - "readMoreValidatorForm": "read about staking on Vega", - "StakeDescription": "The total amount $VEGA staked to this validator including self-stake and all delegation.", - "StakeShareDescription": "The stake a validator represents as a share of total stake across the network.", - "TotalPenaltiesDescription": "Total of penalties taking into account performance (considering proportion of blocks proposed against the number of blocks the validator was expected to propose) and any overstaking.", - "PendingStakeDescription": "The amount of stake that will be added or removed from the validator from the next epoch.", - "StakeNeededForPromotionStandbyDescription": "{{prefix}} additional stake needed for promotion to consensus, assuming constant performance in line with previous epoch.", - "StakeNeededForPromotionCandidateDescription": "{{prefix}} additional stake needed for promotion to standby, assuming constant performance in line with previous epoch.", - "StakedByOperatorDescription": "The stake provided as self-stake by the node operator, must be at least the minimum stake as defined by network parameter", - "AboutThisValidatorDescription": "External URL provided by the validator linking to information about themselves", - "ValidatorStatusDescription": "Consensus, Standby or Pending (Candidate), depending on how much stake the validator has attracted", - "StakedByDelegatesDescription": "The stake delegated to the node by other users", - "OverstakedPenaltyDescription": "A penalty applied for having more stake than the optimal stake for the network. Designed to avoid concentration of voting power with a small number of validators", - "PerformancePenaltyDescription": "Performance score is a measure of how often a validator proposed blocks in the last epoch relative to how many they should be expected to propose based on their voting power. Performance penalty is applied for having a performance score of less than 1", - "UnnormalisedVotingPowerDescription": "The voting power of the validator based on their final validator score after all penalties have been applied", - "NormalisedVotingPowerDescription": "The voting power of the validator, adjusted to ensure all validator scores sum to 1, used for distribution of rewards", - "NonConsensusVotingPowerDescription": "The voting power of the validator. Only consensus validators have voting power", - "Score": "Score", - "performancePenalty": "Performance penalty", - "overstaked": "Overstaked", - "overstakedPenalty": "Overstaked penalty", - "multisigPenalty": "Multisig penalty", - "homeProposalsIntro": "Decisions on the Vega network are on-chain, with tokenholders creating proposals that other tokenholders vote to approve or reject. Network upgrades are proposed and approved by validators.", - "homeProposalsButtonText": "See all proposals", - "homeValidatorsIntro": "Vega runs on a delegated proof of stake blockchain, where validators earn fees for validating block transactions. Tokenholders can nominate validators by staking tokens to them.", - "homeValidatorsButtonText": "Browse, and stake", - "homeRewardsIntro": "Track rewards you've earned for trading, liquidity provision, market creation, and staking.", - "homeRewardsButtonText": "See rewards", - "homeVegaTokenIntro": "VEGA Token is a governance asset used to make and vote on proposals, and nominate validators.", - "homeVegaTokenButtonText": "Manage tokens", - "downloadProposalJson": "Download proposal as JSON", - "networkUpgrade": "Network Upgrade", - "PROTOCOL_UPGRADE_PROPOSAL_STATUS_APPROVED": "Approved by validators", - "PROTOCOL_UPGRADE_PROPOSAL_STATUS_PENDING": "Waiting for validator votes", - "PROTOCOL_UPGRADE_PROPOSAL_STATUS_REJECTED": "Declined by validators", - "PROTOCOL_UPGRADE_PROPOSAL_STATUS_UNSPECIFIED": "Unspecified", - "vegaRelease{release}": "Vega Release {{release}}", - "upgradeBlockHeight": "Upgrade block height", - "vegaReleaseTag": "Vega release tag", - "approvalStatus": "Approval status", - "approvers": "Approvers", - "approval (% validator voting power)": "approval (% validator voting power)", - "67% voting power required": "67% voting power required", - "Token": "Token", + "associateNoVega": "Your connected Ethereum address does not have any $VEGA to associate", "associateVegaNow": "Associate $VEGA now", - "disconnectedNotice": "You have been disconnected. Connect your ETH wallet to the {{correctNetwork}} network to use this app.", - "connectAVegaWalletToVote": "Connect a Vega wallet with $VEGA tokens to vote on a proposal.", - "findOutMoreAboutHowToVote": "Find out more about how to vote on Vega", - "ImproveVegaGovernance": "Improve Vega governance", - "TelemetryModalIntro": "Help us identify bugs and improve Vega Governance by sharing anonymous usage data.", - "Anonymous": "Anonymous", - "YourIdentityAnonymous": "Your identity is always anonymous on Vega", - "Optional": "Optional", - "OptOutOfTelemetry": "You can opt out any time via settings", - "NoThanks": "No thanks", - "ShareData": "Share data", - "ContinueSharingData": "Continue sharing data", - "NodeUnsuitable": "Node: {{url}} is unsuitable", - "Disclaimer": "Disclaimer", - "disclaimer1": "The Vega Governance App allows the Vega network to arrive at on-chain decisions, where tokenholders can create proposals that other tokenholders can vote to approve or reject. Vega supports on-chain proposals for creating markets and assets, and changing network parameters, markets and assets. Vega also supports freeform proposals for community suggestions that will not be enacted on-chain.", - "disclaimer2": "The Vega Governance App is free, public and open source software. Software upgrades may contain bugs or security vulnerabilities that might result in loss of functionality.", - "disclaimer3": "The Vega Governance App uses data obtained from nodes on the Vega Blockchain. The developers of the Vega Governance App do not operate or run the Vega Blockchain or any other blockchain.", - "disclaimer4": "The Vega Governance App is provided “as is”. The developers of the Vega Governance App make no representations or warranties of any kind, whether express or implied, statutory or otherwise regarding the Vega Governance App. They disclaim all warranties of merchantability, quality, fitness for purpose. They disclaim all warranties that the Vega Governance App is free of harmful components or errors.", - "disclaimer5": "No developer of the Vega Governance App accepts any responsibility for, or liability to users in connection with their use of the Vega Governance App.", - "multisigContractLink": "Ethereum Multisig Contract", - "multisigContractIncorrect": "is incorrectly configured. Validator and delegator rewards will be penalised until this is resolved.", - "learnMore": "Learn more", - "AllValidators": "All validators", - "AllProposals": "All proposals", - "RejectedProposals": "Rejected proposals", - "networkGovernance": "Network governance", - "networkUpgrades": "Network upgrades", - "assetSpecification": "Asset specification", - "viewDetails": "View details", - "vegaGovernance": "Vega Governance", - "latestProposals": "Latest proposals", - "vegaToken": "VEGA Token", - "majorityVotedForProposal": "majority voted for this proposal", - "majorityNotVotedForProposal": "majority not voted for this proposal", - "requiredMajorityVotedForProposal": "Required majority voted for this proposal", - "requiredMajorityNotVotedForProposal": "Required majority not voted for this proposal", - "minParticipationReached": "Min. participation reached", - "minParticipationNotReached": "Min. participation not reached", - "consensusNodes": "consensus nodes", - "activeNodes": "active nodes", - "Estimated time to upgrade": "Estimated time to upgrade", - "Upgraded at": "Upgraded at", - "dataIsIdentical": "Data is identical", - "updatesToMarket": "Updates to market", - "viewAsParty": "View as party", - "HowToPropose": "How to make a proposal", - "HowToProposeRawStep1": "1. Sense check your proposal with the community on the forum:", - "HowToProposeRawStep2": "2. Use the appropriate proposal template in the docs:", - "HowToProposeRawStep3": "3. Submit on-chain below", - "proposalTransferDetails": "New governance transfer details", - "proposalCancelTransferDetails": "Cancel governance transfer details", - "BenefitTiers": "Benefit tiers", + "Associating {{amount}} VEGA tokens with Vega key {{vegaKey}}": "Associating {{amount}} $VEGA tokens with Vega key {{vegaKey}}", + "Associating Tokens": "Associating with Vega key", + "associationChoice": "You have $VEGA tokens held by the vesting contract. Would you like to associate those or associate $VEGA directly from your wallet?", + "associationPendingWaitingForVega": "Waiting for Vega to credit key...", + "at the end of epoch": "at the end of epoch", + "Awaiting action in Ethereum wallet (e.g. MetaMask)": "Awaiting action in Ethereum wallet (e.g. MetaMask)", + "Awaiting next epoch": "Waiting for next epoch to start...", + "Back": "Back", + "back": "back", + "backToStaking": "Back to Staking", + "Balance": "Balance", + "BenefitTierMinimumActivityStreak": "Minimum activity streak", + "BenefitTierMinimumActivityStreakDescription": "The minimum number of times the party needs to have completed the activity", "BenefitTierMinimumEpochs": "Minimum epochs", "BenefitTierMinimumEpochsDescription": "The minimum number of epochs the party needs to be in the referral set to be eligible for the benefit", + "BenefitTierMinimumQuantumBalance": "Minimum quantum balance", + "BenefitTierMinimumQuantumBalanceDescription": "The minimum amount of the vesting token to qualify", "BenefitTierMinimumRunningNotionalTakerVolume": "Minimum running notional taker volume", "BenefitTierMinimumRunningNotionalTakerVolumeDescription": "The minimum running notional for the given benefit tier", "BenefitTierReferralDiscountFactor": "Referral discount factor", "BenefitTierReferralDiscountFactorDescription": "The proportion of the referee's taker fees to be discounted", "BenefitTierReferralRewardFactor": "Referral reward factor", "BenefitTierReferralRewardFactorDescription": "The proportion of the referee's taker fees to be rewarded to the referrer", - "BenefitTierMinimumActivityStreak": "Minimum activity streak", - "BenefitTierMinimumActivityStreakDescription": "The minimum number of times the party needs to have completed the activity", - "BenefitTierMinimumQuantumBalance": "Minimum quantum balance", - "BenefitTierMinimumQuantumBalanceDescription": "The minimum amount of the vesting token to qualify", - "BenefitTierVestingMultiplier": "Vesting multiplier", - "BenefitTierVestingMultiplierDescription": "Vesting multiplier for the tier", "BenefitTierRewardMultiplier": "Reward multiplier", "BenefitTierRewardMultiplierDescription": "The multiplier", - "StakingTiers": "Staking tiers", + "BenefitTiers": "Benefit tiers", + "BenefitTierVestingMultiplier": "Vesting multiplier", + "BenefitTierVestingMultiplierDescription": "Vesting multiplier for the tier", + "BenefitTierVolumeDiscountFactor": "Volume discount factor", + "BenefitTierVolumeDiscountFactorDescription": "Discount given to those in this benefit tier", + "blockCountdown": "Waiting for {{amount}} more confirmations...", + "byLiquidityVote": "by liquidity vote", + "byLPVote": "by LP vote", + "byTokenVote": "by token vote", + "Cancel": "Cancel", + "cancelPendingEpochNomination": "Cancel pending epoch nomination", + "CancelTransfer": "Cancel transfer", + "CancelTransferProposal": "Cancel transfer proposal", + "castYourVote": "Cast your vote", + "Change": "Change", + "changeVote": "Change vote", + "Check to see if you can redeem unlocked VEGA tokens": "Check to see if you can redeem unlocked $VEGA tokens", + "Check your vesting VEGA tokens": "Check your vesting $VEGA tokens", + "checkBackSoon": "Check back soon", + "Checking Vega wallet status": "Checking Vega Wallet status", + "checkingForProvider": "Checking for provider", + "Circulating supply": "Circulating supply", + "claim": "This code ({{code}}) entitles {{user}} to {{amount}} $VEGA tokens from {{linkText}} of the vesting contract. {{expiry}}.", + "Claim {amount} Vega": "Claim {{amount}} $VEGA", + "Claim expires": "Claim expires", + "Claim tokens": "Claim tokens", + "Claim transaction": "Claim transaction", + "claimComplete": "Claim successful", + "claimCompleteMessage": "Ethereum address {{address}} now has a vested right to {{balance}} $VEGA tokens, and can redeem these once unlocked", + "claimExpiry": "The code expires on {{date}}", + "claimNoExpiry": "It has no expiry date", + "claimNotReady": "You must complete step 2 first.", + "closedOn": "Closed on", + "closedProposals": "Closed proposals", + "closesOn": "Closes on", + "CloseTimeTooLate": "Close time too late", + "CloseTimeTooSoon": "Close time too soon", + "Code": "Code", + "codeExpired": "Code expired", + "codeUsed": "Code already used", + "codeUsedText": "Looks like that code has already been used. Check the Vesting page to see if you can redeem your tokens.", + "collateral": "Collateral", + "commitBody": "This links your claim to a specific Ethereum address to prevent it being used by another person", + "commitTitle": "Link claim to your Ethereum address", + "Community": "Community", + "Complete": "Complete", + "confirmationsRemaining": "{{confirmations}} of {{required}} blocks to go", + "confirmed": "Confirmed", + "Connect to see your stake": "Connect to see your stake", + "connectAVegaWalletToVote": "Connect a Vega wallet with $VEGA tokens to vote on a proposal.", + "Connected Ethereum address": "Connected Ethereum address", + "Connected Vega key": "Connected Vega key", + "connectedAddress": "Connected to Ethereum key {{address}}.", + "connectEthWallet": "Connect Ethereum wallet", + "connectEthWalletToAssociate": "Connect Ethereum wallet to associate $VEGA", + "connectVegaWallet": "Connect Vega wallet", + "connectVegaWalletToUseAssociated": "Connect Vega wallet to use associated $VEGA", + "connectWalletToSubmitProposal": "Connect your wallet to submit a proposal", + "consensusNodes": "consensus nodes", + "Continue": "Continue", + "ContinueSharingData": "Continue sharing data", + "copied!": "Copied!", + "copyToClipboard": "Copy to clipboard", + "CouldNotInstantiateMarket": "Could not instantiate market", + "created": "Created", + "CreateProposalAndDownloadJSONToShare": "Create proposal and download JSON to share", + "currently": "currently", + "currentlySetTo": "Currently expected to ", + "CurrentValue": "Current value", + "dataIsIdentical": "Data is identical", + "date": "Date", + "daysLeft": "{{daysLeft}} left to vote.", + "Deposit": "deposit", + "depositLpAlreadyStaked": "You have already staked your SLP tokens, go to withdraw in order withdraw these before you can add more.", + "depositLpApproveButton": "Approve SLP tokens for deposit", + "depositLpCalloutBody": "If you want to add more SLP tokens later you will need to unstake first or use a different Ethereum key.", + "depositLpCalloutTitle": "You can only make one deposit at a time", + "depositLpInsufficientBalance": "You do not have tokens to deposit.", + "depositLpSubmitButton": "Deposit SLP", + "depositLpSuccessCalloutBody": "You will be rewarded for each full epoch your SLP tokens are staked", + "depositLpSuccessCalloutTitle": "You SLP tokens have been deposited and will start earning rewards from the next epoch", + "depositLpTokensHeading": "How much would you like to deposit?", + "Desired network": "This app is only configured for {{chain}}", + "disassociate": "Disassociate", + "Disassociate VEGA Tokens from key": "Disassociate $VEGA Tokens from key", + "DisassociateVegaTokensFromWallet": "Disassociate $VEGA tokens from your Vega wallet", + "Disclaimer": "Disclaimer", + "disclaimer1": "The Vega Governance App allows the Vega network to arrive at on-chain decisions, where tokenholders can create proposals that other tokenholders can vote to approve or reject. Vega supports on-chain proposals for creating markets and assets, and changing network parameters, markets and assets. Vega also supports freeform proposals for community suggestions that will not be enacted on-chain.", + "disclaimer2": "The Vega Governance App is free, public and open source software. Software upgrades may contain bugs or security vulnerabilities that might result in loss of functionality.", + "disclaimer3": "The Vega Governance App uses data obtained from nodes on the Vega Blockchain. The developers of the Vega Governance App do not operate or run the Vega Blockchain or any other blockchain.", + "disclaimer4": "The Vega Governance App is provided “as is”. The developers of the Vega Governance App make no representations or warranties of any kind, whether express or implied, statutory or otherwise regarding the Vega Governance App. They disclaim all warranties of merchantability, quality, fitness for purpose. They disclaim all warranties that the Vega Governance App is free of harmful components or errors.", + "disclaimer5": "No developer of the Vega Governance App accepts any responsibility for, or liability to users in connection with their use of the Vega Governance App.", + "disconnect": "Disconnect", + "disconnectedNotice": "You have been disconnected. Connect your ETH wallet to the {{correctNetwork}} network to use this app.", + "Dissociate VEGA tokens": "Disassociate $VEGA tokens", + "Dissociating {{amount}} VEGA tokens from Vega key {{vegaKey}}": "Disassociating {{amount}} $VEGA tokens from Vega key {{vegaKey}}", + "Dissociating Tokens": "Disassociating Tokens", + "Done": "Done", + "downloadNewWallet": "Download {{newVersionAvailable}}", + "downloadProposalJson": "Download proposal as JSON", + "Early Investors": "Early Investors", + "earnedByMe": "Earned by me", + "Enacted": "Enacted", + "enactedOn": "Enacted on", + "enactedOn{{date}}": "Enacted on {{enactmentDate}}", + "enactsOn{{date}}": "Enacts on {{enactmentDate}}", + "EnactTimeTooLate": "Enact time too late", + "EnactTimeTooSoon": "Enact time too soon", + "EndOfProgramTimestamp": "End of program", + "EndOfProgramTimestampDescription": "Time after which when the current epoch ends, the programs will end and benefits will be disabled.", + "enterAddress": "Enter address manually", + "Epoch": "Epoch", + "ERC20ContractAddress": "ERC20 contract address", + "errorDetails": "Error details", + "errorLoadingTranches": "Error loading tranches. Please try again later.", + "ersatzDescription1": "To be promoted, a standby validator must have more than the lowest consensus stake, plus a bonus given to existing validators, and only one standby validator can be promoted per epoch. Currently this requires a minimum of", + "ersatzDescription2": "stake assuming no performance penalty incurred.", + "Estimated time to upgrade": "Estimated time to upgrade", + "ETHEREUM ADDRESS": "ETHEREUM ADDRESS", + "ethereumKey": "Ethereum key", + "ethTransactionModalTitle": "Ethereum Transactions", + "expectedToPass": "Expected to pass", + "fail": "fail", + "failedToRemovePendingStake": "Failed to remove pending stake of {{pendingAmount}} $VEGA", + "fairgroundTitle": "Fairground token", + "FilterProposals": "Filter proposals", + "FilterProposalsDescription": "Filter by proposal ID or proposer ID", + "finalOutcomeMayDiffer": "Final outcome may differ", + "Find out more about Staking.": "Use your $VEGA tokens to nominate a validator, earn rewards and participate in governance of the Vega network.", + "findOutMoreAboutHowToVote": "Find out more about how to vote on Vega", + "footerLinksText": "Known issues and feedback on the Feedback board and Github", + "for": "For", + "Freeform": "Freeform", + "Freeform proposal": "Freeform proposal", + "FreeformProposal": "Freeform proposal", + "from": "From", + "fully redeemable": "Tokens in this tranche have fully unlocked and can be redeemed once claimed.", + "Fully unlocked": "Fully unlocked", + "Fully vested on": "Fully vested on {{date}}", + "Get a Vega wallet": "Get a Vega Wallet", + "getWallet": "Don't have a Vega wallet yet?", + "getWalletLink": "Get a Vega wallet", + "Go to staking or governance to see how you can use your unlocked tokens": "Go to staking or governance to see how you can use your unlocked tokens", + "Governance": "Governance", + "governance": "Governance", + "Governance is coming soon": "Governance is coming soon", + "governanceRequired": "Required", + "Holders": "Holders", + "Home": "Home", + "homeProposalsButtonText": "See all proposals", + "homeProposalsIntro": "Decisions on the Vega network are on-chain, with tokenholders creating proposals that other tokenholders vote to approve or reject. Network upgrades are proposed and approved by validators.", + "homeRewardsButtonText": "See rewards", + "homeRewardsIntro": "Track rewards you've earned for trading, liquidity provision, market creation, and staking.", + "homeValidatorsButtonText": "Browse, and stake", + "homeValidatorsIntro": "Vega runs on a delegated proof of stake blockchain, where validators earn fees for validating block transactions. Tokenholders can nominate validators by staking tokens to them.", + "homeVegaTokenButtonText": "Manage tokens", + "homeVegaTokenIntro": "VEGA Token is a governance asset used to make and vote on proposals, and nominate validators.", + "hostedSwitchLabel": "Use hosted wallet", + "Hours": "hours", + "How much to Add in next epoch?": "How much do you want to add in next epoch?", + "How much to Remove?": "How much do you want to remove?", + "How much would you like to associate?": "How much would you like to associate?", + "HowToPropose": "How to make a proposal", + "HowToProposeRawStep1": "1. Sense check your proposal with the community on the forum:", + "HowToProposeRawStep2": "2. Use the appropriate proposal template in the docs:", + "HowToProposeRawStep3": "3. Submit on-chain below", + "Id": "ID", + "id": "ID", + "If you have been given a link please double check and try again": "If you have been given a link please double check and try again or the Vesting page to see if you have already claimed", + "ImproveVegaGovernance": "Improve Vega governance", + "In wallet": "In wallet", + "IncompatibleTimestamps": "Incompatible timestamps", + "Incomplete": "Incomplete", + "injected.name": "Injected", + "injected.text": "Connect with the provider in your browser", + "InsufficientTokens": "Insufficient tokens", + "Invalid credentials": "Wallet or passphrase incorrect", + "Invalid tranche!": "Invalid tranche!", + "Invalid wallet URL": "Invalid wallet URL", + "invalidAddress": "Looks like that address isn't a valid Ethereum address, please check and try again", + "InvalidAsset": "Invalid asset", + "InvalidAssetDetails": "Invalid asset details", + "InvalidFeeAmount": "Invalid fee amount", + "InvalidFutureMaturityTimestamp": "Invalid future maturity timestamp", + "InvalidFutureProduct": "Invalid future product", + "InvalidInstrumentSecurity": "Invalid instrument security", + "InvalidRiskParameter": "Invalid risk parameter", + "InvalidShape": "Invalid shape", + "IP ADDRESS": "SERVER LOCATION", + "Keep track of locked tokens in your wallet with the VEGA (VESTING) token.": "Keep track of locked tokens in your wallet with the $VEGA (VESTING) token.", + "latestProposals": "Latest proposals", + "learnMore": "Learn more", + "left to vote": "left to vote", + "Link transaction": "Link transaction", + "liquidityComingSoon": "Liquidity rewards coming soon", + "liquidityIntro": "You can read about our incentive program in this blog post.", + "liquidityNav": "DEX Liquidity", + "liquidityOnsenButtonText": "View the SushiSwap Onsen Menu", + "liquidityOnsenFAQ": "FAQ", + "liquidityOnsenHowItWorks": "How it works", + "liquidityOnsenIntro": "Earn rewards for providing liquidity on the", + "liquidityOnsenLinkText": "SushiSwap Onsen Menu", + "liquidityProviderVote": "Liquidity provider vote", + "liquidityProviderVotesAgainst": "LP votes against", + "liquidityProviderVotesFor": "LP votes for", + "liquidityRewardsTitle": "Active liquidity rewards", + "liquidityRewardsTitlePrevious": "Previous liquidity rewards", + "liquidityStakedBalance": "SLP token balance", + "liquidityStakedIntro": "Withdrawing your SLP tokens from the contract will also claim the reward balance", + "liquidityStakedRewards": "Earned rewards", + "liquidityStakedToken": "SLP Token", + "liquidityStakedWithdraw": "Withdraw", + "liquidityStep1Body": "You will need to add the SushiSwap market/token address to your wallet to see your SLP tokens.", + "liquidityStep1Title": "Provide liquidity on one of the markets below and get your SLP tokens.", + "liquidityStep2Body": "You can't increase your stake without un-staking first so consider how much you stake and when.", + "liquidityStep2Title": "Stake these SLP tokens into the appropriate contract below.", + "liquidityStep3Body": "The reward amount is divided by the amount of SLP tokens staked in that epoch. The APY on each pool is indicative based on the current state, this will change over time and is not guaranteed. You will not be entitled to rewards from the epoch that you un-staked in.", + "liquidityStep3Title": "Wait for a full epoch, get a share of the incentive for each full epoch you stake.", + "liquidityStep4Body": "Upon un-staking, your Ethereum key will be credited with its share of $VEGA tokens for each full epoch that it was staked and all SLP tokens staked. Withdrawing your rewards will credit your earned VEGA to your wallet while leaving you SLP staked to earn further rewards.", + "liquidityStep4Title": "Un-stake or withdraw to receive your rewards.", + "liquidityTokenApprove": "Approve", + "liquidityTokenBalance": "Balance", + "liquidityTokenContractAddress": "Liquidity token contract address", + "liquidityTokenDeposit": "Deposit", + "liquidityTokensContractTitle": "SLP Tokens earning rewards", + "liquidityTokenSushiAddress": "SLP pool/token address", + "liquidityTokensWalletIntro": "The following tokens can be staked to earn $VEGA", + "liquidityTokensWalletTitle": "SLP Tokens in connected wallet", + "liquidityTokenTitle": "SLP Token", + "liquidityTokenWithdrawBalance": "Withdrawal balance", + "liquidityTokenWithdrawRewards": "Withdrawal rewards", + "liquidityTotalAvailableRewards": "Total available rewards", + "liquidityTotalAvailableRewardsBalance": "Balance", + "liquidityVotes": "Liquidity votes", + "ListAsset": "List Asset", + "ListAssetAction": "List asset", + "ListAssetDescription": "This asset needs to be listed on the collateral bridge before it can be used.", + "Loading": "Loading...", + "Locked": "Locked", + "Looks like that code has already been used.": "Looks like that code has already been used.", + "lpDiscordPrompt": "Watch our Discord for future ways to earn $VEGA!", + "lpEndedParagraph": "You can only withdraw your rewards and unstake. Upon unstaking, your Ethereum key will be credited with all SLP tokens staked and its share of $VEGA tokens for each full epoch that it was staked.", + "lpEndedTitle": "This liquidity incentive ended on 03 December 2021 14:52 UTC", + "lpTokensEstimateAPY": "Estimated APY", + "lpTokensInRewardPool": "Tokens in reward pool", + "lpTokensInvalidToken": "Address {{address}} is not a valid SLP token address for $VEGA", + "lpTxSuccessButton": "Review liquidity stake", + "mainnetDisableHome": "You will be able to use your $VEGA tokens on the Vega network to nominate Validator nodes and participate in governance.", + "Majority": "Majority", + "majorityLPMet": "Liquidity majority met", + "majorityMet": "Token majority met", + "majorityNotMet": "Majority not met", + "majorityNotVotedForProposal": "majority not voted for this proposal", + "majorityRequired": "Majority Required", + "majorityThreshold": "majority threshold", + "MajorityThresholdNotReached": "Majority threshold not reached", + "majorityVotedForProposal": "majority voted for this proposal", + "Manage your stake": "Manage your stake", + "Market change": "Market change", + "MARKET_STATE_UPDATE_TYPE_RESUME": "Resume market", + "MARKET_STATE_UPDATE_TYPE_SUSPEND": "Suspend market", + "MARKET_STATE_UPDATE_TYPE_TERMINATE": "Terminate market", + "MarketChange": "Market change", + "MarketCode": "Market code", + "marketCode": "Market code", + "MarketDetails": "Market details", + "MarketId": "Market ID", + "marketId": "Market ID", + "MarketMissingLiquidityCommitment": "Market missing liquidity commitment", + "MarketName": "Market name", + "marketName": "Market name", + "marketSpecification": "Market specification", + "MarketStateChange": "Market state change", + "Max faucet amount mint": "Max faucet amount mint", + "MaxFaucetAmountMint": "Max faucet amount mint", + "met": "met", + "minimumNomination": "Your nomination must be greater than or equal to {{minTokens}} $VEGA", + "minParticipationNotReached": "Min. participation not reached", + "minParticipationReached": "Min. participation reached", + "MinProposalRequirements": "You must have at least {{value}} VEGA associated to make a proposal", + "MinProposalVoteRequirements": "You must have at least {{value}} VEGA associated to vote on this proposal", + "MissingBuiltinAssetField": "Missing builtin asset field", + "MissingCommitmentAmount": "Missing commitment amount", + "MissingERC20ContractAddress": "Missing ERC20 contract address", + "MoreAssetsInfo": "To see Explorer data on existing assets visit", + "MoreMarketsInfo": "To see Explorer data on existing markets visit", + "MoreNetParamsInfo": "To see Explorer data on network params visit", + "MoreProposalsInfo": "To see Explorer data on proposals visit", + "multisigContractIncorrect": "is incorrectly configured. Validator and delegator rewards will be penalised until this is resolved.", + "multisigContractLink": "Ethereum Multisig Contract", + "multisigPenalty": "Multisig penalty", + "myPendingStake": "My pending stake", + "myStake": "My stake", + "n/a": "N/A", + "Network parameter": "Network parameter", + "networkDown": "This site is not currently connecting to the network please try again later.", + "networkGovernance": "Network governance", + "NetworkParameter": "Network parameter", + "NetworkParameterInvalidKey": "Network parameter invalid key", + "NetworkParameterInvalidValue": "Network parameter invalid value", + "NetworkParameterProposal": "Update network parameter proposal", + "NetworkParameterValidationFailed": "Network parameter validation failed", + "networkRestoring": "The network is less than {{bootstrapBlockCount}} blocks old, it could be in the process of restoring from a checkpoint", + "networkUpgrade": "Network Upgrade", + "networkUpgrades": "Network upgrades", + "New asset": "New asset", + "New market": "New market", + "NewAsset": "New asset", + "NewAssetProposal": "New asset proposal", + "NewFreeform": "Freeform", + "NewFreeformProposal": "New freeform proposal", + "NewMarket": "New market", + "NewMarketFutureProduct": "New market - future", + "NewMarketPerpetualProduct": "New market - perpetual", + "NewMarketProposal": "New market proposal", + "NewMarketSpotProduct": "New market - spot", + "NewProposal": "New proposal", + "NewProposedValue": "New proposed value", + "NewRawProposal": "New proposal", + "NewTransfer": "New transfer", + "NewTransferProposal": "New transfer proposal", + "newWalletVersionAvailable": "A new Vega wallet is available 🎉. ", + "Next epoch in {{endText}}": "Next epoch in {{endText}}", + "nextEpoch": "Next epoch", + "No holders": "No holders", + "No token": "No token", + "noClosedProposals": "There are no enacted or rejected proposals", + "Node invalid": "Node invalid", + "nodeQueryFailed": "Could not get data for validator {{node}}", + "Nodes": "Nodes", + "NodeUnsuitable": "Node: {{url}} is unsuitable", + "NodeValidationFailed": "Node validation failed", + "noEthereumProviderError": "No Ethereum browser extension detected, install MetaMask on desktop or visit from a dApp browser on mobile", + "noGovernanceTokens": "You need some VEGA tokens to participate in governance", + "noKeys": "No keys", + "Nominate a validator": "Nominate validator", + "Nominate Stake to Validator Node": "Select a validator to nominate", + "NOMINATED (THIS EPOCH)": "NOMINATED (THIS EPOCH)", + "NonConsensusVotingPowerDescription": "The voting power of the validator. Only consensus validators have voting power", + "none redeemable": "Tokens in this tranche unlock on {{unlockDate}} and continue to unlock gradually until {{trancheEndDate}} when all tokens are unlocked. Come back to governance.vega.xyz to redeem your tokens once they begin to unlock.", + "noOpenProposals": "There are no open or yet to enact proposals", + "noPenaltyDataFromLastEpoch": "No penalty data from last epoch", + "noPercentage": "No percentage", + "NoProduct": "No product", + "noProposals": "There are no active network change proposals", + "noRejectedProposals": "No rejected proposals", + "noRewards": "The Vega key has not been credited any rewards since the previous network checkpoint.", + "noRewardsHaveBeenDistributedYet": "NO REWARDS HAVE BEEN DISTRIBUTED YET", + "NoRiskParameters": "No risk parameters", + "normalisedVotingPower": "Normalised voting power", + "NormalisedVotingPowerDescription": "The voting power of the validator, adjusted to ensure all validator scores sum to 1, used for distribution of rewards", + "noService": "Looks like the Vega wallet service isn't running. Please start it and refresh the page", + "Not Associated": "Not Associated", + "not reached": "not reached", + "Not showing tranches with <{{trancheMinimum}} VEGA, click to show all tranches": "Not showing tranches with ≤{{trancheMinimum}} $VEGA, click to show all tranches", + "Not staked": "Not staked", + "notAssociated": "Not Associated", + "NoThanks": "No thanks", + "notMet": "not met", + "NoTradingMode": "No trading mode", + "noTransactions": "No transactions", + "noValidators": "No validators", + "noVersionFound": "Version could not be found, most likely your wallet version is <0.9.2 which is not supported.", + "noVestingTokens": "You do not have any vesting $VEGA tokens. Switch to another Ethereum address to check what can be redeemed, or view all tranches", + "numberOfAgainstVotes": "Number of votes against", + "numberOfForVotes": "Number of votes for", + "numberOfVotingParties": "Number of voting parties", + "of": "of", + "ofTotalDistributed": "of total distributed", + "Once unlocked they can be redeemed from the contract so that you can transfer them between wallets.": "Once unlocked they can be redeemed from the contract so that you can transfer them between wallets.", + "onTheForum": "on the forum", + "OpeningAuctionDurationTooLarge": "Opening auction duration too large", + "OpeningAuctionDurationTooSmall": "Opening auction duration too small", + "openProposals": "Open proposals", + "Optional": "Optional", + "OptOutOfTelemetry": "You can opt out any time via settings", + "Or": "Or", + "overstaked": "Overstaked", + "overstakedPenalty": "Overstaked penalty", + "OverstakedPenaltyDescription": "A penalty applied for having more stake than the optimal stake for the network. Designed to avoid concentration of voting power with a small number of validators", + "OWN STAKE (THIS EPOCH)": "OWN STAKE (THIS EPOCH)", + "pageTitle404": "Page not found", + "pageTitle451": "451 unavailable", + "pageTitleAssociate": "Associate $VEGA tokens with Vega Key", + "pageTitleClaim": "Claim $VEGA tokens", + "pageTitleDepositLp": "Deposit liquidity token for $VEGA rewards", + "pageTitleDisassociate": "Disassociate $VEGA tokens from a Vega key", + "pageTitleHome": "The $VEGA token", + "pageTitleLiquidity": "Incentivised Liquidity Programme", + "pageTitleNotPermitted": "Can not proceed!", + "pageTitleProposals": "Proposals", + "pageTitleRedemption": "Vesting", + "pageTitleRedemptionTranche": "Redeem from Tranche", + "pageTitleRejectedProposals": "Rejected proposals", + "pageTitleRewards": "Rewards and fees", + "pageTitleTranches": "Vesting tranches", + "pageTitleValidators": "Validators", + "pageTitleWithdrawLp": "Withdraw SLP and Rewards", + "parameter": "parameter", + "partially redeemable": "Tokens in this tranche began to unlock on {{unlockDate}} and will continue to unlock gradually until {{trancheEndDate}} when all tokens are unlocked.", + "Participation": "Participation", + "participation": "Participation", + "participationLPMet": "Liquidity participation met", + "participationMet": "Token participation met", + "participationNotMet": "Participation not met", + "participationRequired": "Participation required", + "participationThreshold": "participation threshold", + "ParticipationThresholdNotReached": "Participation threshold not reached", + "pass": "pass", + "Passed": "Passed", + "passphraseLabel": "Passphrase", + "pending": "Pending", + "PENDING STAKE": "PENDING STAKE", + "pendingAssociationText": "The Vega network requires a number of confirmations on Ethereum before crediting your Vega key with your tokens. You can see the number of confirmations that are required in the network parameters. This page will update once complete or you can come back and check your Vega wallet to see if it is ready to use.", + "pendingDescription1": "Anyone can", + "pendingDescription2": ". A node can move from being a candidate into standby based on how much nomination it attracts, assuming it has proven reliability by sending heartbeats to the network.", + "pendingDescriptionLinkText": "set up and run a node on Vega", + "pendingNomination": "Pending Nomination", + "pendingNominationNextEpoch": "Pending nomination for next epoch: {{pendingAmount}} $VEGA", + "pendingStake": "Pending stake", + "PendingStakeDescription": "The amount of stake that will be added or removed from the validator from the next epoch.", + "pendingTransactions": "Pending transactions", + "pendingWithdrawalsCalloutButton": "View incomplete withdrawals", + "pendingWithdrawalsCalloutText": "You have withdrawals that have been released from the Vega network but not yet completed on Ethereum.", + "pendingWithdrawalsCalloutTitle": "You have incomplete withdrawals", + "performancePenalty": "Performance penalty", + "PerformancePenaltyDescription": "Performance score is a measure of how often a validator proposed blocks in the last epoch relative to how many they should be expected to propose based on their voting power. Performance penalty is applied for having a performance score of less than 1", + "Please check wallet": "Please check wallet", + "Please select your country": "Please select your country", + "pleaseTryAgain": "Please try again later.", + "ProductMaturityIsPassed": "Product maturity is passed", + "Proposal": "Proposal", + "proposal": "Proposal", + "Proposal rejected": "Proposal rejected", + "proposalCancelTransferDetails": "Cancel governance transfer details", + "proposalChange": "Change {{key}} to {{value}}", + "ProposalDescription": "Description", + "proposalDescription": "Description", + "ProposalDescriptionText": "Full justification for what you are proposing (20,000 characters or less). Markdown is recommended. When linking to external resources please use IPFS", + "proposalDetails": "Proposal details", + "ProposalDocsPrefix": "For guidance on how to make proposals, see", + "ProposalEnactmentDeadline": "Time till enactment (must be equal to or after vote close)", + "proposalJson": "Full proposal JSON", + "ProposalMinimumAmounts": "Different proposal types can have different minimum token requirements. You must have the greater of the proposal minimum or spam protection minimum from the table below", + "ProposalNotFound": "Proposal not found", + "ProposalNotFoundDetails": "The proposal you are looking for is not here, it may have been enacted before the last chain restore. You could check the Vega forums/discord instead for information about it.", + "ProposalRationale": "Proposal rationale", + "ProposalReference": "Reference", + "Proposals": "Proposals", + "proposals": "Proposals", + "ProposalsGuide": "proposals guide", + "ProposalTerms": "Proposal terms (JSON format)", + "ProposalTermsText": "For more information visit", + "ProposalTitle": "Title", + "ProposalTitleText": "Tell people what you are proposing and why (100 characters or less)", + "proposalTransferDetails": "New governance transfer details", + "ProposalTypeQuestion": "What type of proposal would you like to make?", + "ProposalValidationDeadline": "Time till ERC-20 asset validation. Maximum value is affected by the vote deadline.", + "ProposalVoteAndEnactmentTitle": "Vote deadline and enactment", + "ProposalVoteDeadline": "Time till voting closes", + "ProposalVoteTitle": "Vote deadline", + "ProposalWillFailIfEnactmentIsAboveTheMaximumDeadline": "The proposal will fail if enactment deadline is above the maximum", + "ProposalWillFailIfEnactmentIsBelowTheMinimumDeadline": "The proposal will fail if enactment deadline is below the minimum", + "ProposalWillFailIfEnactmentIsEarlierThanVotingDeadline": "The proposal will fail if enactment is earlier than the voting deadline", + "ProposalWillFailIfVotingIsAboveTheMaximumDeadline": "The proposal will fail if voting deadline is above the maximum", + "ProposalWillFailIfVotingIsBelowTheMinimumDeadline": "The proposal will fail if voting deadline is below the minimum", + "proposedBy": "Proposed by", + "proposedEnactment": "Proposed enactment", + "proposedNewValue": "Proposed new value:", + "proposedOn": "Proposed on", + "ProposeNewMarketTerms": "terms.changes.newMarket (JSON format)", + "ProposeUpdateMarketTerms": "terms.updateMarket.changes (JSON format)", + "PROTOCOL_UPGRADE_PROPOSAL_STATUS_APPROVED": "Approved by validators", + "PROTOCOL_UPGRADE_PROPOSAL_STATUS_PENDING": "Waiting for validator votes", + "PROTOCOL_UPGRADE_PROPOSAL_STATUS_REJECTED": "Declined by validators", + "PROTOCOL_UPGRADE_PROPOSAL_STATUS_UNSPECIFIED": "Unspecified", + "Public Sale": "Public Sale", + "RawProposal": "Let me choose (raw proposal)", + "Read about Vesting on Vega": "Read about Vesting on Vega", + "readMoreGovernance": "Read more about Vega governance", + "readMoreStaking": "Read more about staking on Vega", + "readMoreValidatorForm": "read about staking on Vega", + "readMoreValidators": "Read more about validators", + "received": "Payout time", + "Redeem": "Redeem", + "Redeem unlocked VEGA from tranche {{id}}": "Redeem unlocked $VEGA from tranche {{id}}", + "redeemComingSoon": "Redeem is coming soon", + "Redeemed": "Redeemed", + "RedeemRewardsTooltip": "Click to redeem vested rewards in Console", + "reference": "Reference", + "RejectedProposals": "Rejected proposals", + "rejectionReason": "Rejection reason", + "Remove {{amount}} VEGA tokens": "Remove {{amount}} $VEGA tokens", + "Remove Stake": "Remove Stake", + "Removing stake mid epoch will forsake any staking rewards from that epoch": "Removing stake mid epoch will forsake any staking rewards from that epoch", + "removingPendingStake": "Removing pending stake of {{pendingAmount}} $VEGA", + "required": "Required", + "requiredMajorityNotVotedForProposal": "Required majority not voted for this proposal", + "requiredMajorityVotedForProposal": "Required majority voted for this proposal", + "resourceNotFound": "Resource Not Found", + "reward": "Reward", + "rewardPerEpoch": "Reward per epoch (split between reward pool)", + "Rewards": "Rewards", + "rewardsAndFeesReceived": "Rewards and fees received", + "rewardsCallout": "Rewards are credited {{duration}} after the epoch ends.", + "rewardsCalloutDetail": "This delay is set by a network parameter", + "rewardsColAssetHeader": "ASSET", + "rewardsColInfraHeader": "INFRA FEES", + "rewardsColInfraTooltip": "Infrastructure fees are incurred across the network during trading. They are distributed to validators according to their share of total stake on the network, and passed onto those who stake them, proportionate to their own stake after validator commission is taken", + "rewardsColLiquidityProvisionHeader": "LIQUIDITY PROVISION", + "rewardsColLiquidityProvisionTooltip": "Liquidity provision rewards are distributed based on how much you have earned in liquidity fees, funded by a liquidity reward pool for that market", + "rewardsColMarketCreationHeader": "MARKET CREATION", + "rewardsColMarketCreationTooltip": "Market creation rewards are paid out to the creator of any market that exceeds a set threshold of cumulative volume in a given epoch, currently {{marketCreationQuantumMultiple}}", + "rewardsColPriceMakingHeader": "PRICE MAKING", + "rewardsColPriceMakingTooltip": "Price making rewards are based on the proportion of the total maker fees you received while trading, on markets where there is a funded reward", + "rewardsColPriceTakingHeader": "PRICE TAKING", + "rewardsColPriceTakingTooltip": "Price taking rewards are based on the proportion of the total maker fees you paid while trading, on markets where there is a funded reward", + "rewardsColStakingHeader": "STAKING", + "rewardsColStakingTooltip": "Staking rewards supplement infrastructure fees in the early stages of the network, rewarding validators and those who stake them for maintaining the network", + "rewardsColTotalHeader": "TOTAL", + "rewardsComingSoon": "Rewards is coming soon", + "rewardsIntro": "Earn rewards and infrastructure fees for trading and maintaining the network.", + "rewardTokenContractAddress": "Reward token contract address ($VEGA)", + "rewardType": "Reward type", + "Score": "Score", + "seeHowRewardsAreCalculated": "See how rewards are calculated", + "seeRejectedProposals": "See rejected proposals", + "Select country": "Select country/region of residence", + "Select your country or region of current residence": "Select your country or region of current residence", + "SelectAMarketToChange": "Select a market to change", + "SelectAParameterToChange": "Select a parameter to change", + "selectCountryPrompt": "You must select a country/region first.", + "SelectMarket": "Select market", + "SelectParameter": "Select parameter", + "Service unavailable": "Service unavailable", + "Session expired": "Session expired", + "settled future": "settled future", + "setToFail": "Set to fail", + "setToPass": "Set to pass", + "ShareData": "Share data", + "shareOfReward": "Share of reward", + "shouldPass": "Should pass", + "Showing tranches with <{{trancheMinimum}} VEGA, click to hide these tranches": "Showing tranches with ≤{{trancheMinimum}} $VEGA, click to hide these tranches", + "showRedeem": "You'll be able to redeem your unlocked tokens at governance.vega.xyz/vesting", + "Signature": "Signature", + "signature": "Signature", + "SLP": "SLP", + "SLP Tokens": "SLP Tokens", + "slpTokenContractAddress": "SLP token contract address", + "Something doesn't look right": "Something doesn't look right. Please check the link again or the Vesting page to see if you have already claimed", + "Something went wrong": "Something went wrong", + "Sorry. It is not possible to claim tokens in your country or region.": "It is not possible to claim tokens in your country or region.", + "SpamProtectionMin": "Spam protection minimum", + "stake": "Stake", + "STAKE SHARE": "STAKE SHARE", + "Stake VEGA tokens": "Stake $VEGA tokens", + "Stake your Locked VEGA tokens!": "You can stake your $VEGA tokens even while locked.", + "stakeAddPendingTitle": "Adding {{amount}} $VEGA to validator {{node}}", + "stakeAddSuccessMessage": "You can cancel your nomination at any time", + "stakeAddSuccessTitle": "At the beginning of the next epoch your $VEGA will be nominated to the validator", + "Staked": "Staked", + "STAKED BY DELEGATES": "STAKED BY DELEGATES", + "STAKED BY OPERATOR": "STAKED BY OPERATOR", + "Staked on Vega validator": "Associated to Vega key", + "stakedByDelegates": "Staked by delegates", + "StakedByDelegatesDescription": "The stake delegated to the node by other users", + "stakedByMe": "Staked by me", + "stakedByOperator": "Staked by operator", + "StakedByOperatorDescription": "The stake provided as self-stake by the node operator, must be at least the minimum stake as defined by network parameter", + "StakeDescription": "The total amount $VEGA staked to this validator including self-stake and all delegation.", + "stakedValidators": "Staked Validators", + "stakeFailed": "Failed to delegate to validator {{node}}", + "stakeNeededForPromotion": "Stake needed for promotion", + "StakeNeededForPromotionCandidateDescription": "{{prefix}} additional stake needed for promotion to standby, assuming constant performance in line with previous epoch.", + "StakeNeededForPromotionStandbyDescription": "{{prefix}} additional stake needed for promotion to consensus, assuming constant performance in line with previous epoch.", + "stakeNodeNone": "You need to associate some $VEGA before you can stake", + "stakeNodeWrongVegaKey": "Your Ethereum wallet indicates you have associated tokens for staking. However, there are none available to stake. You may be connected to the wrong Vega key, or Vega is still confirming your associations", + "stakeRemoveNowSuccessMessage": "It will be applied immediately", + "stakeRemovePendingTitle": "Removing {{amount}} $VEGA from validator {{node}}", + "stakeRemoveSuccessMessage": "It will be applied in the next epoch", + "stakeRemoveSuccessTitle": "{{amount}} $VEGA has been removed from validator {{node}}", + "stakeShare": "Stake share", + "StakeShareDescription": "The stake a validator represents as a share of total stake across the network.", + "Staking": "Staking", + "staking": "Staking", + "Staking is coming soon": "Staking is coming soon", + "stakingConfirm": "Open your wallet app to confirm", + "stakingIntro": "Earn a share of trading fees and treasury rewards for each full epoch staked.", + "stakingNodeNotFound": "Could not find a node with ID {{node}}", + "stakingStep2Text": "Your tokens need to be associated with a Vega Wallet so that you can control your stake", + "stakingStep3": "Step 3. Select the validator you'd like to nominate", "StakingTierMinimumStakedTokens": "Minimum staked tokens", "StakingTierMinimumStakedTokensDescription": "Required number of governance tokens ($VEGA) a referrer must have staked to receive the multiplier", "StakingTierReferralRewardMultiplier": "Referral reward multiplier", "StakingTierReferralRewardMultiplierDescription": "Multiplier applied to the referral reward factor when calculating referral rewards due to the referrer", + "StakingTiers": "Staking tiers", + "Started": "Started", + "Starts unlocking": "Unlocking starts", + "state": "State", + "STATE_DECLINED": "Declined", + "STATE_ENACTED": "Enacted", + "STATE_FAILED": "Failed", + "STATE_OPEN": "Open", + "STATE_PASSED": "Passed", + "STATE_REJECTED": "Rejected", + "STATE_WAITING_FOR_NODE_VOTE": "Waiting for node vote", + "STATUS": "STATUS", + "status": "Status", + "status-ersatz": "Standby", + "status-pending": "Candidate", + "status-tendermint": "Consensus", + "Step": "Step", + "submit": "Submit", + "SubmitAgreedRawProposal": "Submit agreed raw proposal", + "SubmitAnAgreedProposalFromTheForum": "Submit an agreed proposal from the forum", + "submitProposal": "Submit proposal", + "submittingProposal": "Submitting proposal", + "successfullAssociationMessage": "Vega key {{vegaKey}} can now participate in governance and nominate a validator with your associated $VEGA.", + "Switch to form for immediate removal": "Switch to remove now", + "Switch to form for removal at end of epoch": "Switch to remove at end of epoch", + "Symbol": "Symbol", + "Team": "Team", + "TelemetryModalIntro": "Help us identify bugs and improve Vega Governance by sharing anonymous usage data.", + "The contract is deployed at the following address": "The contract is deployed at the following address:", + "the holder": "the holder", + "The token address is {{address}}. Hit the add token button in your ERC20 wallet and enter this address.": "The token address is {{address}}. Hit the add token button in your ERC20 wallet and enter this address.", + "The VEGA token address is {{address}}, make sure you add this to your wallet to see your tokens": "The $VEGA token address is {{address}}, make sure you add this to your wallet to see your tokens", + "The vesting contract holds VEGA tokens until they have become unlocked.": "The vesting contract holds $VEGA tokens until they have become unlocked.", + "There are {{nodeCount}} nodes with a shared stake of {{sharedStake}} VEGA tokens": "There are {{nodeCount}} nodes with a shared stake of {{sharedStake}} $VEGA tokens", + "This can happen both while held in the vesting contract as well as when redeemed.": "This can happen both while held in the vesting contract as well as when redeemed.", + "This code ({code}) has expired and cannot be used to claim tokens": "This code ({{code}}) has expired and cannot be used to claim tokens.", + "This page can not be found, please check the URL and try again.": "This page can not be found, please check the URL and try again.", + "This service is not available in your country": "This service is not available in your country/region", + "ThisDoesNotIncludeFeesReceivedForMakersOrLiquidityProviders": "This does not include fees received for makers or liquidity providers", + "thisEpoch": "This Epoch", + "ThisWillAdd2MinutesToAllowTimeToConfirmInWallet": "Note: 2 minutes of extra time are added when you choose the minimum value. This gives you time to confirm the proposal in your wallet.", + "ThisWillSetEnactmentDeadlineTo": "This will set the enactment date to", + "ThisWillSetValidationDeadlineTo": "This will set the validation deadline to", + "ThisWillSetVotingDeadlineTo": "This will set the voting deadline to", + "timeForConfirmation": "Waiting for confirmation that your change in nomination has been received", + "title": "Governance", + "To": "To", + "to": "to", + "To use your tokens on the Vega network they need to be associated with a Vega wallet/key.": "To use your tokens on the Vega network they need to be associated with a Vega Wallet/key.", + "toEnactOn": "Enacts on", + "toEthereum": "To (Ethereum)", + "Token": "Token", + "Token address": "Token address", + "Token Vesting": "Vesting", + "tokenForProposal": "Tokens for proposal", + "tokenLPForProposal": "Liquidity shares for proposal", + "Tokens are held in different Tranches. Each tranche has its own schedule for how the tokens are unlocked.": "Tokens are held in different Tranches. Each tranche has its own schedule for how the tokens are unlocked.", + "Tokens from this Tranche have been redeemed": "Tokens from this Tranche have been redeemed", + "tokensAgainstProposal": "Tokens against proposal", + "tokenVote": "Token vote", + "tokenVotes": "Token votes", + "tokenVotesAgainst": "Token votes against", + "tokenVotesFor": "Token votes for", + "toSeeYourRewardsConnectYourWallet": "TO SEE YOUR REWARDS, CONNECT YOUR WALLET", + "Total": "Total", + "TOTAL STAKE": "TOTAL STAKE", + "Total stake": "Total stake", + "Total supply": "Total supply", + "totalDistributed": "Total distributed", + "totalLiquidityProviderTokensVoted": "Total LP tokens voted", + "totalPenalties": "Total penalties", + "TotalPenaltiesDescription": "Total of penalties taking into account performance (considering proportion of blocks proposed against the number of blocks the validator was expected to propose) and any overstaking.", + "totalStake": "Total stake", + "totalSupply": "Total Supply", + "totalTokensVoted": "Total tokens voted", + "totalTokensVotes": "Total tokens voted", + "totalTokenVotedPercentage": "Total tokens voted percentage", + "toVote": "to vote", + "Tranche": "Tranche", + "Tranche breakdown": "Tranche breakdown", + "Tranche not found": "Tranche not found", + "trancheExtraInfo": "placeholder", + "trancheExtraInfoTranche10": "placeholder", + "Tranches": "Tranches", + "transaction": "Transaction", + "Transaction in progress": "Transaction in progress", + "transactionHashPrompt": "Transaction hash will appear here once the transaction is approved in your Ethereum wallet", + "Try again": "Try again", + "txButtonActionRequired": "Action required in Ethereum wallet", + "txButtonAwaiting": "Awaiting Ethereum transaction", + "txButtonComplete": "Complete", + "txButtonFailure": "Ethereum transaction failed", + "txRequested": "Confirm transaction in wallet", + "type": "Type", + "undelegateSubmitButton": "{{amount}} {{when}}", + "Unknown error": "Unknown error", + "Unknown proposal": "Unknown proposal", + "unknownEthereumConnectionError": "An unknown error occurred. Check the console in your browser's web developer tools for more details", + "unknownReason": "unknown reason", + "Unlocked": "Unlocked", + "unnormalisedVotingPower": "Unnormalised voting power", + "UnnormalisedVotingPowerDescription": "The voting power of the validator based on their final validator score after all penalties have been applied", + "unstaked": "Unstaked", + "unsupportedChainIdError": "You're connected to an unsupported network", + "UnsupportedProduct": "Unsupported product", + "UnsupportedTradingMode": "Unsupported trading mode", + "unsupportedVersion": "Looks like you're running an outdated version of GoWallet. You're running {{version}} but {{requiredVersion}} is required.", + "UpdateAsset": "Update asset", + "UpdateAssetProposal": "Update asset proposal", + "UpdateMarket": "Update market", + "UpdateMarketProposal": "Update market proposal", + "UpdateMarketState": "Update market state", + "UpdateMarketStateProposal": "Update market state proposal", + "updateNetworkParam": "Update Network Parameter", + "UpdateNetworkParameter": "Network parameter", + "UpdateReferralProgram": "Update referral program", + "UpdateReferralProgramProposal": "Update referral program proposal", + "updatesToMarket": "Updates to market", + "UpdateVolumeDiscountProgram": "Update volume discount program", + "UpdateVolumeDiscountProgramProposal": "Update volume discount program proposal", + "upgradeBlockHeight": "Upgrade block height", + "Upgraded at": "Upgraded at", + "Use maximum": "Use maximum", + "Use the Ethereum wallet you want to send your tokens to. You'll also need enough Ethereum to pay gas.": "Connect to the Ethereum wallet that holds your $VEGA tokens to see what can be redeemed from vesting tranches. To redeem tokens you will need some ETH to pay gas fees.\n", + "Use this form to disassociate VEGA tokens with a Vega key. This returns them to either the Ethereum wallet that used the Staking bridge or the vesting contract.": "Use this form to disassociate $VEGA tokens from a Vega key. This returns them to the Ethereum wallet that connected to either the staking bridge or the vesting contract.", + "Use your Vega tokens": "Use your Vega tokens", + "useConnectedWallet": "Use connected wallet", + "UseMax": "Use maximum", + "UseMin": "Use minimum", + "userRejectionError": "Please authorise this website to access your Ethereum account", + "usersAccumulatedRewards": "Your accumulated rewards", + "usersLpTokens": "Your SLP tokens in connected wallet", + "usersPendingStakeLPTokens": "Your SLP tokens in reward pool (next epoch)", + "usersShareOfPool": "Your share of pool", + "usersStakedLPTokens": "Your SLP tokens in reward pool", + "validator": "Validator", + "validatorFormIntro": "To learn more about validators and how scores are calculated,", + "Validators": "Validators", + "ValidatorStatusDescription": "Consensus, Standby or Pending (Candidate), depending on how much stake the validator has attracted", + "validatorTableIntro": "View the validator profile pitches and discussion", + "validatorTitle": "VALIDATOR: {{nodeName}}", + "validatorTitleFallback": "[no name]", + "VEGA": "$VEGA", + "VEGA ADDRESS / PUBLIC KEY": "VEGA ADDRESS / PUBLIC KEY", + "VEGA token holders can nominate a validator node and receive staking rewards.": "$VEGA token holders can nominate a validator node and receive staking rewards.", + "VEGA token holders can vote on proposed changes to the network and create proposals.": "$VEGA token holders can vote on proposed changes to the network and create proposals.", + "VEGA Tokens": "$VEGA Tokens", + "VEGA tokens are approved for staking": "$VEGA tokens are approved for staking", + "VEGA was successfully withdrawn to your wallet": "$VEGA was successfully withdrawn to your wallet", + "vegaAssociatedWithKey": "{{symbol}} associated with a Vega key", + "vegaGovernance": "Vega Governance", + "vegaInWallet": "{{symbol}} in wallet", + "vegaKey": "Vega key", + "vegaRelease{release}": "Vega Release {{release}}", + "vegaReleaseTag": "Vega release tag", + "vegaToken": "VEGA Token", + "vegaTokens": "$VEGA tokens", + "vegaWallet": "Vega Wallet", + "vegaWalletConnect": "Connect", + "vegaWalletConnecting": "Connecting...", + "Verifying your claim": "Verifying your claim", + "verifyingCountryPrompt": "Verifying country/region...", + "VestedRewardsTooltip": "Vested rewards can be redeemed using Console", + "Vesting": "Vesting", + "Vesting associated": "Vesting associated", + "Vesting Balance": "Vesting Balance", + "Vesting contract": "Vesting contract", + "Vesting from": "Vesting from {{fromDate}} to {{endDate}}", + "Vesting VEGA": "Vesting VEGA", + "VESTING VEGA TOKENS": "in vesting contract", + "VestingRewardsTooltip": "Vesting rewards will be moved to vested account at a rate of {{baseRate}} per epoch.", + "viaContract": "via vesting", + "viaWallet": "via wallet", + "View": "View", + "View Governance proposals": "View proposals", + "View on Etherscan (opens in a new tab)": "View on Etherscan (opens in a new tab)", + "View transaction on Etherscan": "View transaction on Etherscan", + "viewAllTranches": "View all tranches", + "viewAsParty": "View as party", + "viewDetails": "View details", + "viewKeys": "View keys", + "viewMarketJson": "View market JSON", + "voteAgainst": "Vote against", + "voteBreakdown": "Vote breakdown", + "voted": "Voted", + "voteError": "Something went wrong, and your vote was not seen by the network", + "voteFailedReason": "Vote closed. Failed due to: ", + "voteFor": "Vote for", + "votePassed": "Vote passed.", + "votePending": "Casting vote", + "voteState_Declined": "Declined", + "voteState_Enacted": "Enacted", + "voteState_Failed": "Failed", + "voteState_No": "Against", + "voteState_NotCast": "Not cast", + "voteState_Open": "Open", + "voteState_Passed": "Passed", + "voteState_Rejected": "Rejected", + "voteState_WaitingForNodeVote": "Waiting for node vote", + "voteState_Yes": "For", + "votingEnded": "Voting has ended.", + "votingPower": "Voting power", + "votingThresholdInfo": "If the token vote passes the participation threshold it will be the deciding vote. If not, the outcome will be determined by liquidity providers on this market.", + "WaitingForNodeVote": "Waiting for nodes to validate asset. ", + "Wallet": "Wallet", + "Wallet associated": "Wallet associated", + "Wallet service unavailable": "Wallet service not running at that url", + "walletConnect.name": "Mobile", + "walletConnect.text": "Scan QR code with your mobile wallet", + "walletLabel": "Wallet name", + "walletServiceLabel": "Wallet service URL", + "Want to remove your stake at the end of the epoch?": "Do you want to remove your stake now?", + "Want to remove your stake before the epoch ends?": "Do you want to remove your stake when the epoch ends?", + "Warning": "Warning", + "What tokens would you like to return?": "What tokens would you like to return?", + "What Vega key is going to control your stake?": "What Vega key is going to control your stake?", + "What Vega wallet are you removing Tokens from?": "What Vega Wallet are you removing tokens from?", + "Where would you like to stake from?": "Where would you like to associate from?", "WindowLength": "Window length", "WindowLengthDescription": "Number of epochs over which to evaluate a referral set's running volume", - "EndOfProgramTimestamp": "End of program", - "EndOfProgramTimestampDescription": "Time after which when the current epoch ends, the programs will end and benefits will be disabled.", - "BenefitTierVolumeDiscountFactor": "Volume discount factor", - "BenefitTierVolumeDiscountFactorDescription": "Discount given to those in this benefit tier", - "ACCOUNT_TYPE_INSURANCE": "Insurance account", - "ACCOUNT_TYPE_GLOBAL_INSURANCE": "Global insurance account", - "ACCOUNT_TYPE_SETTLEMENT": "Settlement account", - "ACCOUNT_TYPE_MARGIN": "Margin account ", - "ACCOUNT_TYPE_GENERAL": "General account", - "ACCOUNT_TYPE_FEES_INFRASTRUCTURE": "Infrastructure fees account", - "ACCOUNT_TYPE_FEES_LIQUIDITY": "Liquidity fees account", - "ACCOUNT_TYPE_FEES_MAKER": "Maker fees account", - "ACCOUNT_TYPE_BOND": "Bond account", - "ACCOUNT_TYPE_EXTERNAL": "External account", - "ACCOUNT_TYPE_GLOBAL_REWARD": "Global reward account", - "ACCOUNT_TYPE_PENDING_TRANSFERS": "Pending transfers account", - "ACCOUNT_TYPE_REWARD_MAKER_PAID_FEES": "Maker paid fees reward account", - "ACCOUNT_TYPE_REWARD_MAKER_RECEIVED_FEES": "Maker received fees reward account", - "ACCOUNT_TYPE_REWARD_LP_RECEIVED_FEES": "Liquidity provider received fees reward account", - "ACCOUNT_TYPE_REWARD_MARKET_PROPOSERS": "Market proposers reward account", - "ACCOUNT_TYPE_HOLDING": "Holding account", - "ACCOUNT_TYPE_LP_LIQUIDITY_FEES": "Liquidity provider fees account", - "ACCOUNT_TYPE_NETWORK_TREASURY": "Network treasury account", - "ACCOUNT_TYPE_VESTING_REWARDS": "Vesting rewards account", - "ACCOUNT_TYPE_VESTED_REWARDS": "Vested rewards account", - "ACCOUNT_TYPE_REWARD_AVERAGE_POSITION": "Average position reward account", - "ACCOUNT_TYPE_REWARD_RELATIVE_RETURN": "Relative return reward account", - "ACCOUNT_TYPE_REWARD_RETURN_VOLATILITY": "Return volatility reward account", - "ACCOUNT_TYPE_REWARD_VALIDATOR_RANKING": "Validator ranking reward account", - "ACCOUNT_TYPE_PENDING_FEE_REFERRAL_REWARD": "Pending fee referral reward account", - "VestingRewardsTooltip": "Vesting rewards will be moved to vested account at a rate of {{baseRate}} per epoch.", - "VestedRewardsTooltip": "Vested rewards can be redeemed using Console", - "RedeemRewardsTooltip": "Click to redeem vested rewards in Console" + "Withdraw": "Withdraw", + "withdrawAllLpSuccessCalloutTitle": "Your SLP tokens and rewards have been sent to your Ethereum address", + "withdrawalsCompleteButton": "Finish withdrawal", + "withdrawalsNone": "You don't have any pending withdrawals.", + "withdrawalsPreparedWarningHeading": "Complete these withdrawals before the next checkpoint restore", + "withdrawalsPreparedWarningText": "Prepared withdrawals are not stored between network resets meaning you will not have the information required to complete a withdrawal.", + "withdrawalsSubtitle": "Connect your Vega wallet to complete a withdrawal. These withdrawals will be completed with an Ethereum transaction.", + "withdrawalsText": "These withdrawals need to be completed with an Ethereum transaction.", + "withdrawalsTitle": "Withdrawals", + "withdrawalTransaction": "Transaction ({{foreignChain}})", + "withdrawFormAmountLabel": "How much would you like to withdraw?", + "withdrawFormAssetLabel": "What would you like to withdraw?", + "withdrawFormNoAsset": "You don't have any assets to withdraw", + "withdrawFormSubmitButtonIdle": "Withdraw {{amount}} {{symbol}} tokens", + "withdrawFormSubmitButtonPending": "Preparing", + "withdrawFromRewardPoolButton": "Withdraw rewards and unstake", + "withdrawLpNoneDeposited": "You have no SLP tokens deposited or rewards accumulated", + "withdrawLpWithdrawAllButton": "Unstake SLP and Withdraw $VEGA rewards", + "withdrawPageHeading": "Withdraw", + "withdrawPageInfoCalloutText": "To withdraw from Vega, the network needs to agree that a party can withdraw funds (to ensure they are available). Once that happens, it returns a signature that is used in an Ethereum transaction to send the tokens to the given Ethereum address.", + "withdrawPageInfoCalloutTitle": "How ERC20 withdrawals work on Vega", + "withdrawPageText": "Use this form to withdraw/release assets from your Vega wallet to their native chain.", + "withdrawPreparedWarningHeading": "Only start a withdrawal when you are ready to pay the gas to release on Ethereum", + "withdrawPreparedWarningText1": "If you proceed beyond this stage, but do not complete the withdrawal on Ethereum, it will not be possible to cancel or alter your withdrawal request.", + "withdrawPreparedWarningText2": "To ensure your assets are not lost, you must pay gas on Ethereum to complete the final step of the withdrawal process. Gas costs per withdrawal have been between $100 and $200.", + "wrongNetwork": "Looks like you are on {{chain}}.", + "wrongNetworkUnknownChain": "Looks like you are on not on {{chain}}.", + "yesPercentage": "Yes percentage", + "You can associate tokens while they are held in the vesting contract, when they unlock you will need to disassociate them before they can be redeemed.": "You can associate tokens while they are held in the vesting contract, when they unlock you will need to disassociate them before they can be redeemed.", + "You cannot claim VEGA tokens if you reside in that country": "It is not possible to claim $VEGA tokens if you reside in that country or region", + "You have no VEGA tokens currently staked through your connected Eth wallet.": "You have no $VEGA tokens currently staked through your connected Ethereum wallet.", + "You have no VEGA tokens currently staked through your connected Vega wallet.": "You have no $VEGA tokens currently staked through your connected Vega Wallet.", + "You have no VEGA tokens currently vesting.": "You have no $VEGA tokens currently vesting.", + "You have no VEGA tokens in your connected wallet. You will need to buy some VEGA tokens from an exchange in order to stake using this method.": "You have no $VEGA tokens in your connected wallet. You will need to buy some $VEGA tokens from an exchange in order to stake using this method.", + "You have redeemed {{redeemedAmount}} VEGA tokens from this tranche. They are now free to transfer from your Ethereum wallet.": "You have redeemed {{redeemedAmount}} $VEGA tokens from this tranche. They are now free to transfer from your Ethereum wallet.", + "You must reduce your associated vesting tokens by at least {{amount}} to redeem from this tranche. Manage your stake or just disassociate your tokens.": "You must reduce your associated vesting tokens by at least {{amount}} to redeem from this tranche. Manage your stake or just disassociate your tokens.", + "You must select a valid country": "You must select a valid country/region", + "You will need to connect to an ethereum wallet to pay the gas and claim tokens": "To claim tokens you will need to connect an Ethereum wallet with ETH to pay for gas. It may be easier to connect to the wallet that you wish your tokens to be sent to.", + "youDidNotVote": "Voting has ended. You did not vote", + "Your data couldn't be loaded": "Your data couldn't be loaded", + "Your stake": "Your stake", + "Your Stake On Node (Next Epoch)": "Your Stake On Node (Next Epoch)", + "Your Stake On Node (This Epoch)": "Your Stake On Node (This Epoch)", + "YourIdentityAnonymous": "Your identity is always anonymous on Vega", + "yourStake": "Your stake", + "yourVote": "Your vote", + "youVoted": "You voted" } diff --git a/libs/i18n/src/locales/en/trading.json b/libs/i18n/src/locales/en/trading.json new file mode 100644 index 000000000..25ac898de --- /dev/null +++ b/libs/i18n/src/locales/en/trading.json @@ -0,0 +1,3 @@ +{ + "k": " " +} diff --git a/libs/i18n/tsconfig.lib.json b/libs/i18n/tsconfig.lib.json index 623dd477a..e65c1a059 100644 --- a/libs/i18n/tsconfig.lib.json +++ b/libs/i18n/tsconfig.lib.json @@ -1,6 +1,8 @@ { "extends": "./tsconfig.json", "compilerOptions": { + "esModuleInterop": true, + "resolveJsonModule": true, "outDir": "../../dist/out-tsc", "declaration": true, "types": [] diff --git a/libs/orders/__mocks__/react-i18next.ts b/libs/orders/__mocks__/react-i18next.ts new file mode 100644 index 000000000..7c2343f52 --- /dev/null +++ b/libs/orders/__mocks__/react-i18next.ts @@ -0,0 +1,14 @@ +export const useTranslation = () => ({ + t: (label: string, replacements?: Record) => { + let translatedLabel = label; + if (typeof replacements === 'object' && replacements !== null) { + Object.keys(replacements).forEach((key) => { + translatedLabel = translatedLabel.replace( + `{{${key}}}`, + replacements[key] + ); + }); + } + return translatedLabel; + }, +}); diff --git a/libs/ui-toolkit/src/components/tooltip/tooltip.tsx b/libs/ui-toolkit/src/components/tooltip/tooltip.tsx index 43dbbbf9f..21909cb99 100644 --- a/libs/ui-toolkit/src/components/tooltip/tooltip.tsx +++ b/libs/ui-toolkit/src/components/tooltip/tooltip.tsx @@ -68,6 +68,17 @@ export const Tooltip = ({ children ); +export const TextChildrenTooltip = ({ + children, + ...props +}: Omit & { + children: string | string[]; +}) => ( + + {children} + +); + export const TooltipCellComponent = (props: ITooltipParams) => { return (
diff --git a/package.json b/package.json index 74bec62a1..237b09a51 100644 --- a/package.json +++ b/package.json @@ -69,6 +69,8 @@ "graphql-ws": "^5.6.3", "i18next": "^20.3.5", "i18next-browser-languagedetector": "^6.1.2", + "i18next-http-backend": "^2.3.1", + "i18next-locize-backend": "^6.4.1", "immer": "^9.0.12", "iso8601-duration": "^2.1.1", "js-sha3": "^0.8.0", @@ -121,6 +123,7 @@ "@graphql-inspector/validate-command": "^3.3.0", "@nrwl/js": "17.1.2", "@nx/cypress": "17.1.2", + "@nx/eslint": "17.1.2", "@nx/eslint-plugin": "17.1.2", "@nx/jest": "17.1.2", "@nx/js": "17.1.2", @@ -226,8 +229,7 @@ "typescript": "5.2.2", "url-loader": "^4.1.1", "webpack": "5.89.0", - "webpack-merge": "^5.8.0", - "@nx/eslint": "17.1.2" + "webpack-merge": "^5.8.0" }, "lint-staged": { "*": "yarn nx format:write --uncommitted", diff --git a/yarn.lock b/yarn.lock index f83145a48..2af8beb19 100644 --- a/yarn.lock +++ b/yarn.lock @@ -10587,6 +10587,20 @@ create-require@^1.1.0: resolved "https://registry.yarnpkg.com/create-require/-/create-require-1.1.1.tgz#c1d7e8f1e5f6cfc9ff65f9cd352d37348756c333" integrity sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ== +cross-fetch@4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/cross-fetch/-/cross-fetch-4.0.0.tgz#f037aef1580bb3a1a35164ea2a848ba81b445983" + integrity sha512-e4a5N8lVvuLgAWgnCrLr2PP0YyDOTHa9H/Rj54dirp61qXnNq46m82bRhNqIA5VccJtWBvPTFRV3TtvHUKPB1g== + dependencies: + node-fetch "^2.6.12" + +cross-fetch@4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/cross-fetch/-/cross-fetch-4.0.0.tgz#f037aef1580bb3a1a35164ea2a848ba81b445983" + integrity sha512-e4a5N8lVvuLgAWgnCrLr2PP0YyDOTHa9H/Rj54dirp61qXnNq46m82bRhNqIA5VccJtWBvPTFRV3TtvHUKPB1g== + dependencies: + node-fetch "^2.6.12" + cross-fetch@^3.1.4, cross-fetch@^3.1.5: version "3.1.8" resolved "https://registry.yarnpkg.com/cross-fetch/-/cross-fetch-3.1.8.tgz#0327eba65fd68a7d119f8fb2bf9334a1a7956f82" @@ -14193,6 +14207,20 @@ i18next-browser-languagedetector@^6.1.2: dependencies: "@babel/runtime" "^7.19.0" +i18next-http-backend@^2.3.1: + version "2.3.1" + resolved "https://registry.yarnpkg.com/i18next-http-backend/-/i18next-http-backend-2.3.1.tgz#9ea06cd96772527f5bf171f4948af5f34be5fe05" + integrity sha512-jnagFs5cnq4ryb+g92Hex4tB5kj3tWmiRWx8gHMCcE/PEgV1fjH5rC7xyJmPSgyb9r2xgcP8rvZxPKgsmvMqTw== + dependencies: + cross-fetch "4.0.0" + +i18next-locize-backend@^6.4.1: + version "6.4.1" + resolved "https://registry.yarnpkg.com/i18next-locize-backend/-/i18next-locize-backend-6.4.1.tgz#eca46e6afeeb8a484efba15575022dae492b6508" + integrity sha512-D8XxklzzsftydwEKxEa5y9Hz5TMxY5Z68ciwMyIhB/g/vAGW4x8ZW5u27guCppWH+pAzdIYkT8E47lfjcBak6w== + dependencies: + cross-fetch "4.0.0" + i18next@^20.3.5: version "20.6.1" resolved "https://registry.yarnpkg.com/i18next/-/i18next-20.6.1.tgz#535e5f6e5baeb685c7d25df70db63bf3cc0aa345" @@ -17160,7 +17188,14 @@ node-fetch@2.6.7: dependencies: whatwg-url "^5.0.0" -node-fetch@^2.0.0, node-fetch@^2.6.1, node-fetch@^2.6.12, node-fetch@^2.6.7: +node-fetch@^2.0.0: + version "2.6.11" + resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.11.tgz#cde7fc71deef3131ef80a738919f999e6edfff25" + integrity sha512-4I6pdBY1EthSqDmJkiNk3JIT8cswwR9nfeW/cPdUagJYEQG7R95WRH74wpz7ma8Gh/9dI9FP+OU+0E4FvtA55w== + dependencies: + whatwg-url "^5.0.0" + +node-fetch@^2.6.11, node-fetch@^2.6.12: version "2.7.0" resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.7.0.tgz#d0f0fa6e3e2dc1d27efcd8ad99d550bda94d187d" integrity sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==