From a9ca2152763563fc1f9c48b40b33c98d45d126b8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20G=C5=82ownia?= Date: Mon, 20 Nov 2023 06:49:39 +0100 Subject: [PATCH] feat(proposals): use i18next (#5284) Co-authored-by: Matthew Russell --- .../proposal-form-transaction-dialog.tsx | 5 +- libs/i18n/src/index.ts | 2 + libs/i18n/src/locales/en/proposals.json | 46 +++++++++++++++++++ .../asset-proposal-notification.tsx | 3 +- .../market-proposal-notification.tsx | 5 +- .../components/proposal-actions-dropdown.tsx | 3 +- .../proposals-list/proposals-list.tsx | 3 +- .../proposals-list/use-column-defs.tsx | 6 ++- .../components/protocol-upgrade-countdown.tsx | 30 ++++++------ ...tocol-upgrade-in-progress-notification.tsx | 7 ++- ...protocol-upgrade-proposal-notification.tsx | 22 ++++++--- .../vega-transaction-dialog.tsx | 10 ++-- .../proposals-hooks/use-proposal-toasts.tsx | 36 ++++++++++----- libs/proposals/src/setup-tests.ts | 13 ++++++ libs/proposals/src/use-t.ts | 3 ++ .../src/utils/proposal-dialog-helpers.tsx | 5 +- 16 files changed, 149 insertions(+), 50 deletions(-) create mode 100644 libs/i18n/src/locales/en/proposals.json create mode 100644 libs/proposals/src/use-t.ts diff --git a/apps/governance/src/routes/proposals/components/propose/proposal-form-transaction-dialog.tsx b/apps/governance/src/routes/proposals/components/propose/proposal-form-transaction-dialog.tsx index e9bbd0db8..bdf68eb6e 100644 --- a/apps/governance/src/routes/proposals/components/propose/proposal-form-transaction-dialog.tsx +++ b/apps/governance/src/routes/proposals/components/propose/proposal-form-transaction-dialog.tsx @@ -1,7 +1,7 @@ import { getProposalDialogIcon, getProposalDialogIntent, - getProposalDialogTitle, + useGetProposalDialogTitle, } from '@vegaprotocol/proposals'; import type { ProposalEventFieldsFragment } from '@vegaprotocol/proposals'; import type { DialogProps } from '@vegaprotocol/proposals'; @@ -15,6 +15,7 @@ export const ProposalFormTransactionDialog = ({ finalizedProposal, TransactionDialog, }: ProposalFormTransactionDialogProps) => { + const title = useGetProposalDialogTitle(finalizedProposal?.state); // Render a custom complete UI if the proposal was rejected otherwise // pass undefined so that the default vega transaction dialog UI gets used const completeContent = finalizedProposal?.rejectionReason ? ( @@ -24,7 +25,7 @@ export const ProposalFormTransactionDialog = ({ return (
{{count}} blocks": "<0>{{count}} blocks", + "Awaiting network confirmation": "Awaiting network confirmation", + "blocks": "blocks", + "Changes have been proposed for this asset.": "Changes have been proposed for this asset.", + "Changes have been proposed for this market.": "Changes have been proposed for this market.", + "Closing date": "Closing date", + "Confirm transaction in wallet": "Confirm transaction in wallet", + "Enactment date: {{date}}": "Enactment date: {{date}}", + "Enactment date": "Enactment date", + "estimated time to protocol upgrade": "estimated time to protocol upgrade", + "estimating...": "estimating...", + "Market": "Market", + "Network upgrade in {{countdown}}": "Network upgrade in {{countdown}}", + "No proposed markets": "No proposed markets", + "Parent market": "Parent market", + "Please open your wallet application and confirm or reject the transaction": "Please open your wallet application and confirm or reject the transaction", + "Please wait for your transaction to be confirmed": "Please wait for your transaction to be confirmed", + "Proposal declined": "Proposal declined", + "Proposal enacted": "Proposal enacted", + "Proposal failed": "Proposal failed", + "Proposal passed": "Proposal passed", + "Proposal rejected": "Proposal rejected", + "Proposal submitted": "Proposal submitted", + "Proposal waiting for node vote": "Proposal waiting for node vote", + "Rejection reason: {{reason}}": "Rejection reason: {{reason}}", + "Settlement asset": "Settlement asset", + "State": "State", + "Submission failed": "Submission failed", + "The network is being upgraded to {{vegaReleaseTag}}": "The network is being upgraded to {{vegaReleaseTag}}", + "The network will upgrade to {{vegaReleaseTag}} in {{countdown}}": "The network will upgrade to {{vegaReleaseTag}} in {{countdown}}", + "Trading activity will be interrupted, manage your risk appropriately.": "Trading activity will be interrupted, manage your risk appropriately.", + "Trading and other network activity has stopped until the upgrade is complete.": "Trading and other network activity has stopped until the upgrade is complete.", + "Transaction complete": "Transaction complete", + "Transaction failed": "Transaction failed", + "Unknown proposal {{proposalState}}": "Unknown proposal {{proposalState}}", + "Update <0>{{key}} to {{value}}": "Update <0>{{key}} to {{value}}", + "View details": "View details", + "View in block explorer": "View in block explorer", + "View proposal details": "View proposal details", + "View proposal": "View proposal", + "Voting": "Voting", + "Your transaction has been confirmed": "Your transaction has been confirmed" +} diff --git a/libs/proposals/src/components/asset-proposal-notification.tsx b/libs/proposals/src/components/asset-proposal-notification.tsx index 9c2a71937..7c5d9dd9a 100644 --- a/libs/proposals/src/components/asset-proposal-notification.tsx +++ b/libs/proposals/src/components/asset-proposal-notification.tsx @@ -1,8 +1,8 @@ import { DApp, TOKEN_PROPOSAL, useLinks } from '@vegaprotocol/environment'; -import { t } from '@vegaprotocol/i18n'; import * as Schema from '@vegaprotocol/types'; import { ExternalLink, Intent, Notification } from '@vegaprotocol/ui-toolkit'; import { useUpdateProposal } from '../lib'; +import { useT } from '../use-t'; type AssetProposalNotificationProps = { assetId?: string; @@ -10,6 +10,7 @@ type AssetProposalNotificationProps = { export const AssetProposalNotification = ({ assetId, }: AssetProposalNotificationProps) => { + const t = useT(); const tokenLink = useLinks(DApp.Governance); const { data: proposal } = useUpdateProposal({ id: assetId, diff --git a/libs/proposals/src/components/market-proposal-notification.tsx b/libs/proposals/src/components/market-proposal-notification.tsx index 07f82804d..a09e7fede 100644 --- a/libs/proposals/src/components/market-proposal-notification.tsx +++ b/libs/proposals/src/components/market-proposal-notification.tsx @@ -1,8 +1,8 @@ -import { t } from '@vegaprotocol/i18n'; import * as Schema from '@vegaprotocol/types'; import { ExternalLink, Intent, Notification } from '@vegaprotocol/ui-toolkit'; import { DApp, TOKEN_PROPOSAL, useLinks } from '@vegaprotocol/environment'; import { useUpdateProposal } from '../lib'; +import { useT } from '../use-t'; type MarketProposalNotificationProps = { marketId?: string; @@ -10,6 +10,7 @@ type MarketProposalNotificationProps = { export const MarketProposalNotification = ({ marketId, }: MarketProposalNotificationProps) => { + const t = useT(); const tokenLink = useLinks(DApp.Governance); const { data: proposal } = useUpdateProposal({ id: marketId, @@ -29,7 +30,7 @@ export const MarketProposalNotification = ({
); return ( -
+
{ + const t = useT(); const linkCreator = useLinks(DApp.Governance); return ( diff --git a/libs/proposals/src/components/proposals-list/proposals-list.tsx b/libs/proposals/src/components/proposals-list/proposals-list.tsx index 31f31a949..92aef168f 100644 --- a/libs/proposals/src/components/proposals-list/proposals-list.tsx +++ b/libs/proposals/src/components/proposals-list/proposals-list.tsx @@ -1,11 +1,11 @@ import type { FC } from 'react'; import { AgGrid } from '@vegaprotocol/datagrid'; -import { t } from '@vegaprotocol/i18n'; import * as Types from '@vegaprotocol/types'; import { removePaginationWrapper } from '@vegaprotocol/utils'; import type { ProposalListFieldsFragment } from '../../lib/proposals-data-provider/__generated__/Proposals'; import { useProposalsListQuery } from '../../lib/proposals-data-provider/__generated__/Proposals'; import { useColumnDefs } from './use-column-defs'; +import { useT } from '../../use-t'; export const getNewMarketProposals = (data: ProposalListFieldsFragment[]) => data.filter((proposal) => @@ -30,6 +30,7 @@ interface ProposalListProps { } export const ProposalsList = ({ cellRenderers }: ProposalListProps) => { + const t = useT(); const { data } = useProposalsListQuery({ variables: { proposalType: Types.ProposalType.TYPE_NEW_MARKET, diff --git a/libs/proposals/src/components/proposals-list/use-column-defs.tsx b/libs/proposals/src/components/proposals-list/use-column-defs.tsx index ed88837c2..ed511b8df 100644 --- a/libs/proposals/src/components/proposals-list/use-column-defs.tsx +++ b/libs/proposals/src/components/proposals-list/use-column-defs.tsx @@ -8,7 +8,6 @@ import { } from '@vegaprotocol/datagrid'; import compact from 'lodash/compact'; import { getDateTimeFormat } from '@vegaprotocol/utils'; -import { t } from '@vegaprotocol/i18n'; import type { VegaICellRendererParams, VegaValueFormatterParams, @@ -19,8 +18,11 @@ import { } from '@vegaprotocol/types'; import type { ProposalListFieldsFragment } from '../../lib/proposals-data-provider/__generated__/Proposals'; import { ProposalActionsDropdown } from '../proposal-actions-dropdown'; +import { useT } from '../../use-t'; export const useColumnDefs = () => { + const t = useT(); + const columnDefs: ColDef[] = useMemo(() => { return compact([ { @@ -124,7 +126,7 @@ export const useColumnDefs = () => { }, }, ]); - }, []); + }, [t]); return columnDefs; }; diff --git a/libs/proposals/src/components/protocol-upgrade-countdown.tsx b/libs/proposals/src/components/protocol-upgrade-countdown.tsx index e5acf94ff..07242d3f9 100644 --- a/libs/proposals/src/components/protocol-upgrade-countdown.tsx +++ b/libs/proposals/src/components/protocol-upgrade-countdown.tsx @@ -1,4 +1,3 @@ -import { t } from '@vegaprotocol/i18n'; import { useNextProtocolUpgradeProposal, useTimeToUpgrade } from '../lib'; import { convertToCountdownString } from '@vegaprotocol/utils'; import classNames from 'classnames'; @@ -9,6 +8,8 @@ import { } from '@vegaprotocol/ui-toolkit'; import { useProtocolUpgradeProposalLink } from '@vegaprotocol/environment'; import { useContext } from 'react'; +import { useT } from '../use-t'; +import { Trans } from 'react-i18next'; export enum ProtocolUpgradeCountdownMode { IN_BLOCKS, @@ -21,6 +22,7 @@ type ProtocolUpgradeCountdownProps = { export const ProtocolUpgradeCountdown = ({ mode = ProtocolUpgradeCountdownMode.IN_ESTIMATED_TIME_REMAINING, }: ProtocolUpgradeCountdownProps) => { + const t = useT(); const { theme } = useContext(NavigationContext); const { data, lastBlockHeight } = useNextProtocolUpgradeProposal(); @@ -45,12 +47,13 @@ export const ProtocolUpgradeCountdown = ({ switch (mode) { case ProtocolUpgradeCountdownMode.IN_BLOCKS: countdown = ( - <> - - {Number(data.upgradeBlockHeight) - Number(lastBlockHeight)} - {' '} - {t('blocks')} - + count]} + values={{ + count: Number(data.upgradeBlockHeight) - Number(lastBlockHeight), + }} + /> ); break; case ProtocolUpgradeCountdownMode.IN_ESTIMATED_TIME_REMAINING: @@ -61,7 +64,7 @@ export const ProtocolUpgradeCountdown = ({ ) : ( @@ -80,20 +83,19 @@ export const ProtocolUpgradeCountdown = ({
{' '} - - {t('Network upgrade in')} - {countdown} + + {t('Network upgrade in {{countdown}}', { countdown })}
diff --git a/libs/proposals/src/components/protocol-upgrade-in-progress-notification.tsx b/libs/proposals/src/components/protocol-upgrade-in-progress-notification.tsx index 66248d577..7f0bf72e7 100644 --- a/libs/proposals/src/components/protocol-upgrade-in-progress-notification.tsx +++ b/libs/proposals/src/components/protocol-upgrade-in-progress-notification.tsx @@ -1,6 +1,5 @@ import { useProtocolUpgradeProposalLink } from '@vegaprotocol/environment'; -import { t } from '@vegaprotocol/i18n'; import { ExternalLink, Intent, @@ -14,6 +13,7 @@ import { } from '../lib'; import { useLocalStorageSnapshot } from '@vegaprotocol/react-helpers'; import { useBlockRising } from '../lib/protocol-upgrade-proposals/use-block-rising'; +import { useT } from '../use-t'; /** * A flag determining whether to get the upgrade proposal data from local @@ -22,6 +22,7 @@ import { useBlockRising } from '../lib/protocol-upgrade-proposals/use-block-risi const ALLOW_STORED_PROPOSAL_DATA = true; export const ProtocolUpgradeInProgressNotification = () => { + const t = useT(); const { data, error } = useNextProtocolUpgradeProposal(undefined, true); const [nextUpgrade] = useLocalStorageSnapshot( NEXT_PROTOCOL_UPGRADE_PROPOSAL_SNAPSHOT @@ -71,7 +72,9 @@ export const ProtocolUpgradeInProgressNotification = () => { return (
- {t('The network is being upgraded to %s', vegaReleaseTag)} + {t('The network is being upgraded to {{vegaReleaseTag}}', { + vegaReleaseTag, + })}
{t( diff --git a/libs/proposals/src/components/protocol-upgrade-proposal-notification.tsx b/libs/proposals/src/components/protocol-upgrade-proposal-notification.tsx index b8075aa90..53467ae0f 100644 --- a/libs/proposals/src/components/protocol-upgrade-proposal-notification.tsx +++ b/libs/proposals/src/components/protocol-upgrade-proposal-notification.tsx @@ -4,11 +4,12 @@ import { NotificationBanner, } from '@vegaprotocol/ui-toolkit'; import { useNextProtocolUpgradeProposal, useTimeToUpgrade } from '../lib'; -import { t } from '@vegaprotocol/i18n'; import { useProtocolUpgradeProposalLink } from '@vegaprotocol/environment'; import { ProtocolUpgradeCountdownMode } from './protocol-upgrade-countdown'; import { convertToCountdownString } from '@vegaprotocol/utils'; import { useState } from 'react'; +import { useT } from '../use-t'; +import { Trans } from 'react-i18next'; type ProtocolUpgradeProposalNotificationProps = { mode?: ProtocolUpgradeCountdownMode; @@ -16,6 +17,7 @@ type ProtocolUpgradeProposalNotificationProps = { export const ProtocolUpgradeProposalNotification = ({ mode = ProtocolUpgradeCountdownMode.IN_BLOCKS, }: ProtocolUpgradeProposalNotificationProps) => { + const t = useT(); const [visible, setVisible] = useState(true); const { data, lastBlockHeight } = useNextProtocolUpgradeProposal(); const detailsLink = useProtocolUpgradeProposalLink(); @@ -40,10 +42,13 @@ export const ProtocolUpgradeProposalNotification = ({ switch (mode) { case ProtocolUpgradeCountdownMode.IN_BLOCKS: countdown = ( - <> - {blocksLeft}{' '} - {t('blocks')} - + count]} + values={{ + count: blocksLeft, + }} + /> ); break; case ProtocolUpgradeCountdownMode.IN_ESTIMATED_TIME_REMAINING: @@ -72,10 +77,13 @@ export const ProtocolUpgradeProposalNotification = ({ }} >
- {t('The network will upgrade to %s in ', [data.vegaReleaseTag])} - {countdown} + {t('The network will upgrade to {{vegaReleaseTag}} in {{countdown}}', { + vegaReleaseTag: data.vegaReleaseTag, + countdown, + })}
+ {t( 'Trading activity will be interrupted, manage your risk appropriately.' )}{' '} diff --git a/libs/proposals/src/components/vega-transaction-dialog/vega-transaction-dialog.tsx b/libs/proposals/src/components/vega-transaction-dialog/vega-transaction-dialog.tsx index 297c2cf29..3bcb5786c 100644 --- a/libs/proposals/src/components/vega-transaction-dialog/vega-transaction-dialog.tsx +++ b/libs/proposals/src/components/vega-transaction-dialog/vega-transaction-dialog.tsx @@ -1,10 +1,10 @@ import type { ReactNode } from 'react'; -import { t } from '@vegaprotocol/i18n'; import { Dialog, Icon, Intent, Loader } from '@vegaprotocol/ui-toolkit'; import { WalletClientError } from '@vegaprotocol/wallet-client'; import type { VegaTxState } from '../../lib/proposals-hooks/use-vega-transaction'; import { VegaTxStatus } from '../../lib/proposals-hooks/use-vega-transaction'; import { useVegaWallet } from '@vegaprotocol/wallet'; +import { useT } from '../../use-t'; export type VegaTransactionContentMap = { [C in VegaTxStatus]?: JSX.Element; @@ -28,8 +28,9 @@ export const VegaTransactionDialog = ({ icon, content, }: VegaTransactionDialogProps) => { + const t = useT(); const computedIntent = intent ? intent : getIntent(transaction); - const computedTitle = title ? title : getTitle(transaction); + const computedTitle = title ? title : getTitle(transaction, t); const computedIcon = icon ? icon : getIcon(transaction); return ( @@ -86,6 +87,7 @@ interface VegaDialogProps { * Default dialog content */ export const VegaDialog = ({ transaction }: VegaDialogProps) => { + const t = useT(); const { links, network } = useVegaWallet(); let content = null; @@ -99,7 +101,7 @@ export const VegaDialog = ({ transaction }: VegaDialogProps) => {

{network !== 'MAINNET' && (

- {t('[This is %s transaction only]').replace('%s', network)} + {t('[This is {{network}} transaction only]', { network })}

)} @@ -176,7 +178,7 @@ const getIntent = (transaction: VegaTxState) => { } }; -const getTitle = (transaction: VegaTxState) => { +const getTitle = (transaction: VegaTxState, t: ReturnType) => { switch (transaction.status) { case VegaTxStatus.Requested: return t('Confirm transaction in wallet'); diff --git a/libs/proposals/src/lib/proposals-hooks/use-proposal-toasts.tsx b/libs/proposals/src/lib/proposals-hooks/use-proposal-toasts.tsx index bfdd9b089..a00dafed1 100644 --- a/libs/proposals/src/lib/proposals-hooks/use-proposal-toasts.tsx +++ b/libs/proposals/src/lib/proposals-hooks/use-proposal-toasts.tsx @@ -1,6 +1,5 @@ import { DApp, TOKEN_PROPOSAL, useLinks } from '@vegaprotocol/environment'; import { getDateTimeFormat } from '@vegaprotocol/utils'; -import { t } from '@vegaprotocol/i18n'; import { ProposalChangeMapping, ProposalRejectionReasonMapping, @@ -16,6 +15,8 @@ import { useOnProposalSubscription, type OnProposalFragmentFragment, } from './__generated__/Proposal'; +import { Trans } from 'react-i18next'; +import { useT } from '../../use-t'; export const PROPOSAL_STATES_TO_TOAST = [ ProposalState.STATE_DECLINED, @@ -27,6 +28,7 @@ const CLOSE_AFTER = 0; type Proposal = OnProposalFragmentFragment; const ProposalDetails = ({ proposal }: { proposal: Proposal }) => { + const t = useT(); const change = proposal.terms.change; switch (change.__typename) { case 'UpdateNetworkParameter': @@ -43,8 +45,10 @@ const ProposalDetails = ({ proposal }: { proposal: Proposal }) => { {proposal.state === ProposalState.STATE_REJECTED && proposal.rejectionReason ? (

- {t('Rejection reason:')}{' '} - {ProposalRejectionReasonMapping[proposal.rejectionReason]} + {t('Rejection reason: {{reason}}', { + reason: + ProposalRejectionReasonMapping[proposal.rejectionReason], + })}

) : null} @@ -61,24 +65,30 @@ const UpdateNetworkParameterDetails = ({ if (change.__typename !== 'UpdateNetworkParameter') return null; return (

- '{t('Update ')} - {change.networkParameter.key} - {t(' to ')} - {change.networkParameter.value}' + key]} + />

); }; export const ProposalToastContent = ({ proposal }: { proposal: Proposal }) => { + const t = useT(); const tokenLink = useLinks(DApp.Governance); const change = proposal.terms.change; // Generates toast's title, // e.g. Update market proposal enacted, New transfer proposal open, ... - const title = t('%s proposal %s', [ - change.__typename ? ProposalChangeMapping[change.__typename] : 'Unknown', - ProposalStateMapping[proposal.state].toLowerCase(), - ]); + const title = change.__typename + ? t('{{proposalChange}} proposal {{proposalState}}', { + proposalChange: ProposalChangeMapping[change.__typename], + proposalState: ProposalStateMapping[proposal.state].toLowerCase(), + }) + : t('Unknown proposal {{proposalState}}', { + proposalState: ProposalStateMapping[proposal.state].toLowerCase(), + }); const enactment = Date.parse(proposal.terms.enactmentDatetime); @@ -88,7 +98,9 @@ export const ProposalToastContent = ({ proposal }: { proposal: Proposal }) => { {!isNaN(enactment) && (

- {t('Enactment date:')} {getDateTimeFormat().format(enactment)} + {t('Enactment date: {{date}}', { + date: getDateTimeFormat().format(enactment), + })}

)}

diff --git a/libs/proposals/src/setup-tests.ts b/libs/proposals/src/setup-tests.ts index 68773380a..191206936 100644 --- a/libs/proposals/src/setup-tests.ts +++ b/libs/proposals/src/setup-tests.ts @@ -1,4 +1,17 @@ import '@testing-library/jest-dom'; import ResizeObserver from 'resize-observer-polyfill'; +import '@testing-library/jest-dom'; +import { locales } from '@vegaprotocol/i18n'; +import i18n from 'i18next'; +import { initReactI18next } from 'react-i18next'; +// Set up i18n instance so that components have the correct default +// en translations +i18n.use(initReactI18next).init({ + // we init with resources + resources: locales, + fallbackLng: 'en', + ns: ['proposals'], + defaultNS: 'proposals', +}); global.ResizeObserver = ResizeObserver; diff --git a/libs/proposals/src/use-t.ts b/libs/proposals/src/use-t.ts new file mode 100644 index 000000000..b1495bf39 --- /dev/null +++ b/libs/proposals/src/use-t.ts @@ -0,0 +1,3 @@ +import { useTranslation } from 'react-i18next'; +export const ns = 'proposals'; +export const useT = () => useTranslation(ns).t; diff --git a/libs/proposals/src/utils/proposal-dialog-helpers.tsx b/libs/proposals/src/utils/proposal-dialog-helpers.tsx index 342a882a7..c4e5a1962 100644 --- a/libs/proposals/src/utils/proposal-dialog-helpers.tsx +++ b/libs/proposals/src/utils/proposal-dialog-helpers.tsx @@ -1,11 +1,12 @@ import { ProposalState } from '@vegaprotocol/types'; -import { t } from '@vegaprotocol/i18n'; import { Icon, Intent } from '@vegaprotocol/ui-toolkit'; import type { ReactNode } from 'react'; +import { useT } from '../use-t'; -export const getProposalDialogTitle = ( +export const useGetProposalDialogTitle = ( status?: ProposalState ): string | undefined => { + const t = useT(); if (!status) { return; }