From a4a7bb2739ea713ef3ba28be9244276f26d8cf71 Mon Sep 17 00:00:00 2001 From: Charlie McKenzie Date: Thu, 21 Dec 2023 15:17:09 +1100 Subject: [PATCH] feat: Checkout i18next support (#1278) --- .../definitions/configurations/widget.ts | 6 + .../src/widgets/definitions/events/bridge.ts | 1 + .../src/widgets/definitions/events/connect.ts | 1 + .../src/widgets/definitions/events/onramp.ts | 1 + .../src/widgets/definitions/events/sale.ts | 1 + .../src/widgets/definitions/events/swap.ts | 1 + .../src/widgets/definitions/events/wallet.ts | 1 + .../src/widgets/definitions/events/widgets.ts | 8 + .../widgets/definitions/parameters/bridge.ts | 3 + .../widgets/definitions/parameters/connect.ts | 4 + .../widgets/definitions/parameters/onramp.ts | 3 + .../widgets/definitions/parameters/sale.ts | 3 + .../widgets/definitions/parameters/swap.ts | 3 + .../widgets/definitions/parameters/wallet.ts | 5 +- packages/checkout/widgets-lib/package.json | 3 + .../checkout/widgets-lib/rollup.config.js | 2 +- .../components/NotEnoughImx/NotEnoughImx.tsx | 16 +- packages/checkout/widgets-lib/src/factory.ts | 1 + packages/checkout/widgets-lib/src/i18n.ts | 41 ++ .../checkout/widgets-lib/src/locales/en.json | 511 +++++++++++++++++ .../checkout/widgets-lib/src/locales/ja.json | 514 ++++++++++++++++++ .../checkout/widgets-lib/src/locales/ko.json | 511 +++++++++++++++++ .../checkout/widgets-lib/src/locales/zh.json | 511 +++++++++++++++++ .../widgets-lib/src/views/error/ErrorView.tsx | 13 +- .../src/views/top-up/TopUpView.tsx | 33 +- .../widgets-lib/src/widgets/BaseWidgetRoot.ts | 8 + .../src/widgets/bridge/BridgeWidget.tsx | 11 +- .../widgets/bridge/components/BridgeForm.tsx | 48 +- .../bridge/components/BridgeReviewSummary.tsx | 28 +- .../components/WalletAndNetworkSelector.tsx | 28 +- .../widgets/bridge/components/WalletItem.tsx | 6 +- .../bridge/views/ApproveTransaction.tsx | 14 +- .../src/widgets/bridge/views/Bridge.tsx | 7 +- .../src/widgets/bridge/views/BridgeReview.tsx | 7 +- .../widgets/bridge/views/MoveInProgress.tsx | 9 +- .../views/WalletNetworkSelectionView.tsx | 6 +- .../src/widgets/connect/ConnectWidget.tsx | 6 +- .../widgets/connect/components/WalletItem.tsx | 74 ++- .../widgets/connect/views/ConnectWallet.tsx | 9 +- .../widgets/connect/views/ReadyToConnect.tsx | 24 +- .../connect/views/SwitchNetworkEth.tsx | 17 +- .../connect/views/SwitchNetworkZkEVM.tsx | 17 +- .../src/widgets/swap/SwapWidget.tsx | 23 +- .../widgets/swap/components/SwapButton.tsx | 6 +- .../src/widgets/swap/components/SwapForm.tsx | 71 ++- .../widgets/swap/components/UnableToSwap.tsx | 10 +- .../swap/views/ApproveERC20Onboarding.tsx | 51 +- .../src/widgets/swap/views/SwapCoins.tsx | 7 +- .../src/widgets/swap/views/SwapInProgress.tsx | 6 +- .../components/NetworkMenu/NetworkMenu.tsx | 7 +- .../TokenBalanceList/TokenBalanceList.tsx | 7 +- .../TotalTokenBalance/TotalTokenBalance.tsx | 8 +- .../src/widgets/wallet/views/CoinInfo.tsx | 23 +- .../src/widgets/wallet/views/Settings.tsx | 9 +- .../widgets/wallet/views/WalletBalances.tsx | 8 +- .../src/components/ui/connect/connect.tsx | 4 + .../LanguageSelector.tsx | 41 ++ .../ui/marketplace-orchestrator/MainPage.tsx | 15 +- .../src/components/ui/wallet/wallet.tsx | 9 +- sdk/package.json | 3 + yarn.lock | 74 +++ 61 files changed, 2583 insertions(+), 315 deletions(-) create mode 100644 packages/checkout/widgets-lib/src/i18n.ts create mode 100644 packages/checkout/widgets-lib/src/locales/en.json create mode 100644 packages/checkout/widgets-lib/src/locales/ja.json create mode 100644 packages/checkout/widgets-lib/src/locales/ko.json create mode 100644 packages/checkout/widgets-lib/src/locales/zh.json create mode 100644 packages/checkout/widgets-sample-app/src/components/ui/marketplace-orchestrator/LanguageSelector.tsx diff --git a/packages/checkout/sdk/src/widgets/definitions/configurations/widget.ts b/packages/checkout/sdk/src/widgets/definitions/configurations/widget.ts index c692d5b669..444886e21f 100644 --- a/packages/checkout/sdk/src/widgets/definitions/configurations/widget.ts +++ b/packages/checkout/sdk/src/widgets/definitions/configurations/widget.ts @@ -7,4 +7,10 @@ import { WidgetTheme } from './theme'; export type WidgetConfiguration = { /** The theme of the Checkout Widget (default: "DARK") */ theme?: WidgetTheme; + language?: WidgetLanguage; }; + +/** + * Widget Language represents the language options for the Checkout Widgets. + */ +export type WidgetLanguage = 'en' | 'ja' | 'ko' | 'zh'; diff --git a/packages/checkout/sdk/src/widgets/definitions/events/bridge.ts b/packages/checkout/sdk/src/widgets/definitions/events/bridge.ts index dd57f32f96..60dc3aa9b1 100644 --- a/packages/checkout/sdk/src/widgets/definitions/events/bridge.ts +++ b/packages/checkout/sdk/src/widgets/definitions/events/bridge.ts @@ -5,6 +5,7 @@ export enum BridgeEventType { CLOSE_WIDGET = 'close-widget', FAILURE = 'failure', TRANSACTION_SENT = 'transaction-sent', + LANGUAGE_CHANGED = 'language-changed', } /** diff --git a/packages/checkout/sdk/src/widgets/definitions/events/connect.ts b/packages/checkout/sdk/src/widgets/definitions/events/connect.ts index 92960d153c..82cdce0a0e 100644 --- a/packages/checkout/sdk/src/widgets/definitions/events/connect.ts +++ b/packages/checkout/sdk/src/widgets/definitions/events/connect.ts @@ -8,6 +8,7 @@ export enum ConnectEventType { CLOSE_WIDGET = 'close-widget', SUCCESS = 'success', FAILURE = 'failure', + LANGUAGE_CHANGED = 'language-changed', } /** diff --git a/packages/checkout/sdk/src/widgets/definitions/events/onramp.ts b/packages/checkout/sdk/src/widgets/definitions/events/onramp.ts index 2f1fc931e2..667af1f65c 100644 --- a/packages/checkout/sdk/src/widgets/definitions/events/onramp.ts +++ b/packages/checkout/sdk/src/widgets/definitions/events/onramp.ts @@ -5,6 +5,7 @@ export enum OnRampEventType { CLOSE_WIDGET = 'close-widget', SUCCESS = 'success', FAILURE = 'failure', + LANGUAGE_CHANGED = 'language-changed', } /** diff --git a/packages/checkout/sdk/src/widgets/definitions/events/sale.ts b/packages/checkout/sdk/src/widgets/definitions/events/sale.ts index 9108a4fad5..52ab80da00 100644 --- a/packages/checkout/sdk/src/widgets/definitions/events/sale.ts +++ b/packages/checkout/sdk/src/widgets/definitions/events/sale.ts @@ -7,6 +7,7 @@ export enum SaleEventType { FAILURE = 'failure', REJECTED = 'rejected', TRANSACTION_SUCCESS = 'transaction-success', + LANGUAGE_CHANGED = 'language-changed', } /** diff --git a/packages/checkout/sdk/src/widgets/definitions/events/swap.ts b/packages/checkout/sdk/src/widgets/definitions/events/swap.ts index 09eb3cc001..533ff90bb9 100644 --- a/packages/checkout/sdk/src/widgets/definitions/events/swap.ts +++ b/packages/checkout/sdk/src/widgets/definitions/events/swap.ts @@ -6,6 +6,7 @@ export enum SwapEventType { SUCCESS = 'success', FAILURE = 'failure', REJECTED = 'rejected', + LANGUAGE_CHANGED = 'language-changed', } /** diff --git a/packages/checkout/sdk/src/widgets/definitions/events/wallet.ts b/packages/checkout/sdk/src/widgets/definitions/events/wallet.ts index 9631808446..902ae95d8b 100644 --- a/packages/checkout/sdk/src/widgets/definitions/events/wallet.ts +++ b/packages/checkout/sdk/src/widgets/definitions/events/wallet.ts @@ -7,6 +7,7 @@ export enum WalletEventType { CLOSE_WIDGET = 'close-widget', NETWORK_SWITCH = 'network-switch', DISCONNECT_WALLET = 'disconnect-wallet', + LANGUAGE_CHANGED = 'language-changed', } /** diff --git a/packages/checkout/sdk/src/widgets/definitions/events/widgets.ts b/packages/checkout/sdk/src/widgets/definitions/events/widgets.ts index b96eaa6c49..d34cfadd5c 100644 --- a/packages/checkout/sdk/src/widgets/definitions/events/widgets.ts +++ b/packages/checkout/sdk/src/widgets/definitions/events/widgets.ts @@ -1,4 +1,5 @@ import { Web3Provider } from '@ethersproject/providers'; +import { WidgetLanguage } from '../configurations'; /** * Enum representing the events emitted by the widgets. @@ -26,3 +27,10 @@ export enum ProviderEventType { export type ProviderUpdated = { provider: Web3Provider; }; + +/** + * Payload type for the LANGUAGE_CHANGED event + */ +export type LanguageChanged = { + language: WidgetLanguage; +}; diff --git a/packages/checkout/sdk/src/widgets/definitions/parameters/bridge.ts b/packages/checkout/sdk/src/widgets/definitions/parameters/bridge.ts index 5048210fa1..1ef404ef04 100644 --- a/packages/checkout/sdk/src/widgets/definitions/parameters/bridge.ts +++ b/packages/checkout/sdk/src/widgets/definitions/parameters/bridge.ts @@ -1,5 +1,6 @@ /* eslint-disable max-len */ import { WalletProviderName } from '../../../types'; +import { WidgetLanguage } from '../configurations'; /** * Bridge Widget parameters @@ -14,4 +15,6 @@ export type BridgeWidgetParams = { amount?: string; /** The wallet provider name to use for the bridge widget */ walletProviderName?: WalletProviderName; + /** The language to use for the bridge widget */ + language?: WidgetLanguage; }; diff --git a/packages/checkout/sdk/src/widgets/definitions/parameters/connect.ts b/packages/checkout/sdk/src/widgets/definitions/parameters/connect.ts index d0722b5137..dabd7e3b46 100644 --- a/packages/checkout/sdk/src/widgets/definitions/parameters/connect.ts +++ b/packages/checkout/sdk/src/widgets/definitions/parameters/connect.ts @@ -1,7 +1,11 @@ +import { WidgetLanguage } from '../configurations'; + export enum ConnectTargetLayer { LAYER1 = 'LAYER1', LAYER2 = 'LAYER2', } export type ConnectWidgetParams = { + /** The language to use for the connect widget */ + language?: WidgetLanguage; }; diff --git a/packages/checkout/sdk/src/widgets/definitions/parameters/onramp.ts b/packages/checkout/sdk/src/widgets/definitions/parameters/onramp.ts index 12cb8162b4..77aa4fbdf1 100644 --- a/packages/checkout/sdk/src/widgets/definitions/parameters/onramp.ts +++ b/packages/checkout/sdk/src/widgets/definitions/parameters/onramp.ts @@ -1,4 +1,5 @@ import { WalletProviderName } from '../../../types'; +import { WidgetLanguage } from '../configurations'; /** * OnRamp Widget parameters * @property {string | undefined} tokenAddress @@ -12,4 +13,6 @@ export type OnRampWidgetParams = { amount?: string; /** The wallet provider name to use for the onramp widget */ walletProviderName?: WalletProviderName; + /** The language to use for the onramp widget */ + language?: WidgetLanguage; }; diff --git a/packages/checkout/sdk/src/widgets/definitions/parameters/sale.ts b/packages/checkout/sdk/src/widgets/definitions/parameters/sale.ts index 749970fa7b..b2e3cd0b43 100644 --- a/packages/checkout/sdk/src/widgets/definitions/parameters/sale.ts +++ b/packages/checkout/sdk/src/widgets/definitions/parameters/sale.ts @@ -1,4 +1,5 @@ import { WalletProviderName } from '../../../types'; +import { WidgetLanguage } from '../configurations'; // Fixme: In SaleWidgetParams pass environmentId through from sdk when it is sorted with hub @@ -19,6 +20,8 @@ export type SaleWidgetParams = { items?: SaleItem[]; /** The wallet provider name to default to if no web3Provider is passed */ walletProviderName?: WalletProviderName; + /** The language to use for the sales widget */ + language?: WidgetLanguage; }; /** diff --git a/packages/checkout/sdk/src/widgets/definitions/parameters/swap.ts b/packages/checkout/sdk/src/widgets/definitions/parameters/swap.ts index e41f42d5bb..ec5fe7aa34 100644 --- a/packages/checkout/sdk/src/widgets/definitions/parameters/swap.ts +++ b/packages/checkout/sdk/src/widgets/definitions/parameters/swap.ts @@ -1,4 +1,5 @@ import { WalletProviderName } from '../../../types'; +import { WidgetLanguage } from '../configurations'; /** * Swap Widget parameters @@ -16,4 +17,6 @@ export type SwapWidgetParams = { toTokenAddress?: string; /** The wallet provider name to use for the swap widget */ walletProviderName?: WalletProviderName; + /** The language to use for the swap widget */ + language?: WidgetLanguage; }; diff --git a/packages/checkout/sdk/src/widgets/definitions/parameters/wallet.ts b/packages/checkout/sdk/src/widgets/definitions/parameters/wallet.ts index c3d8db702e..fce6cd69f1 100644 --- a/packages/checkout/sdk/src/widgets/definitions/parameters/wallet.ts +++ b/packages/checkout/sdk/src/widgets/definitions/parameters/wallet.ts @@ -1,5 +1,6 @@ /* eslint-disable max-len */ import { WalletProviderName } from '../../../types'; +import { WidgetLanguage } from '../configurations'; /** * Wallet Widget parameters @@ -7,5 +8,7 @@ import { WalletProviderName } from '../../../types'; */ export type WalletWidgetParams = { /** The wallet provider name to use for the wallet widget */ - walletProviderName?: WalletProviderName + walletProviderName?: WalletProviderName; + /** The language to use for the wallet widget */ + language?: WidgetLanguage; }; diff --git a/packages/checkout/widgets-lib/package.json b/packages/checkout/widgets-lib/package.json index c7a3a84407..36f0153510 100644 --- a/packages/checkout/widgets-lib/package.json +++ b/packages/checkout/widgets-lib/package.json @@ -30,8 +30,11 @@ "crypto-browserify": "^3.12.0", "ethers": "^5.7.2", "https-browserify": "^1.0.0", + "i18next": "^23.7.6", + "i18next-browser-languagedetector": "^7.2.0", "os-browserify": "^0.3.0", "pako": "^2.1.0", + "react-i18next": "^13.5.0", "stream-browserify": "^3.0.0", "stream-http": "^3.2.0", "url": "^0.11.0" diff --git a/packages/checkout/widgets-lib/rollup.config.js b/packages/checkout/widgets-lib/rollup.config.js index efb242092a..af564b4685 100644 --- a/packages/checkout/widgets-lib/rollup.config.js +++ b/packages/checkout/widgets-lib/rollup.config.js @@ -7,6 +7,7 @@ import replace from '@rollup/plugin-replace'; import nodePolyfills from 'rollup-plugin-polyfill-node'; const defaultPlugin = [ + json(), replace({ preventAssignment: true, 'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV || 'production'), @@ -41,7 +42,6 @@ export default [ }), nodePolyfills(), commonjs(), - json(), ...defaultPlugin, terser(), ] diff --git a/packages/checkout/widgets-lib/src/components/NotEnoughImx/NotEnoughImx.tsx b/packages/checkout/widgets-lib/src/components/NotEnoughImx/NotEnoughImx.tsx index a084e8b680..b7c66f4613 100644 --- a/packages/checkout/widgets-lib/src/components/NotEnoughImx/NotEnoughImx.tsx +++ b/packages/checkout/widgets-lib/src/components/NotEnoughImx/NotEnoughImx.tsx @@ -2,6 +2,7 @@ import { Body, Drawer, Box, Button, FramedImage, Heading, Logo, } from '@biom3/react'; +import { useTranslation } from 'react-i18next'; import { containerStyles, contentTextStyles, @@ -9,7 +10,6 @@ import { actionButtonContainerStyles, logoContainerStyles, } from './NotEnoughImxStyles'; -import { text } from '../../resources/text/textConfig'; type NotEnoughImxProps = { visible: boolean; @@ -22,8 +22,8 @@ type NotEnoughImxProps = { export function NotEnoughImx({ visible, showAdjustAmount, hasZeroImx, onCloseDrawer, onAddCoinsClick, }: NotEnoughImxProps) { - const { content, buttons } = text.drawers.notEnoughImx; - const { noImx, insufficientImx } = content; + const { t } = useTranslation(); + // const { noImx, insufficientImx } = content; const imxLogo = 'https://design-system.immutable.com/hosted-for-ds/currency-icons/currency--imx.svg'; @@ -49,10 +49,10 @@ export function NotEnoughImx({ sx={contentTextStyles} testId="not-enough-gas-heading" > - {hasZeroImx ? noImx.heading : insufficientImx.heading} + {t(`drawers.notEnoughImx.content.${hasZeroImx ? 'noImx' : 'insufficientImx'}.heading`)} - {hasZeroImx ? noImx.body : insufficientImx.body} + {t(`drawers.notEnoughImx.content.${hasZeroImx ? 'noImx' : 'insufficientImx'}.body`)} {showAdjustAmount && ( @@ -62,7 +62,7 @@ export function NotEnoughImx({ variant="tertiary" onClick={onCloseDrawer} > - {buttons.adjustAmount} + {t('drawers.notEnoughImx.buttons.adjustAmount')} )} diff --git a/packages/checkout/widgets-lib/src/factory.ts b/packages/checkout/widgets-lib/src/factory.ts index 3532dfdbb7..5b731cc235 100644 --- a/packages/checkout/widgets-lib/src/factory.ts +++ b/packages/checkout/widgets-lib/src/factory.ts @@ -17,6 +17,7 @@ import { sendProviderUpdatedEvent, addProviderListenersForWidgetRoot, } from './lib'; +import './i18n'; export class WidgetsFactory implements IWidgetsFactory { private sdk: Checkout; diff --git a/packages/checkout/widgets-lib/src/i18n.ts b/packages/checkout/widgets-lib/src/i18n.ts new file mode 100644 index 0000000000..b5c621d26c --- /dev/null +++ b/packages/checkout/widgets-lib/src/i18n.ts @@ -0,0 +1,41 @@ +/* eslint-disable @typescript-eslint/naming-convention */ +// eslint-disable-next-line import/no-named-as-default +import i18n, { type Resource } from 'i18next'; +import LanguageDetector from 'i18next-browser-languagedetector'; +import { initReactI18next } from 'react-i18next'; +import enTranslations from './locales/en.json'; +import jaTranslations from './locales/ja.json'; +import koTranslations from './locales/ko.json'; +import zhTranslations from './locales/zh.json'; + +const resources: Resource = { + en: { + translation: enTranslations, + }, + ja: { + translation: jaTranslations, + }, + ko: { + translation: koTranslations, + }, + zh: { + translation: zhTranslations, + }, +}; + +// eslint-disable-next-line import/no-named-as-default-member +i18n + .use(initReactI18next) // passes i18n down to react-i18next + .use(LanguageDetector) + .init({ + fallbackLng: 'en', + resources, + // lng: 'en', // language to use, more information here: https://www.i18next.com/overview/configuration-options#languages-namespaces-resources + // you can use the i18n.changeLanguage function to change the language manually: https://www.i18next.com/overview/api#changelanguage + // if you're using a language detector, do not define the lng optio + interpolation: { + escapeValue: false, // react already safes from xss + }, + }); + +export default i18n; diff --git a/packages/checkout/widgets-lib/src/locales/en.json b/packages/checkout/widgets-lib/src/locales/en.json new file mode 100644 index 0000000000..830b1e97f1 --- /dev/null +++ b/packages/checkout/widgets-lib/src/locales/en.json @@ -0,0 +1,511 @@ +{ + "views": { + "CONNECT_WALLET": { + "body": { + "heading": "Connect a wallet", + "content": "You'll need to connect or create a digital wallet to buy, sell, trade and store your coins and collectibles." + } + }, + "CONNECT_SUCCESS": { + "status": "Connection secure", + "action": "Continue" + }, + "READY_TO_CONNECT": { + "header": { + "title": "Connect" + }, + "metamask": { + "body": { + "heading": "Check for the pop-up from MetaMask", + "content": "Follow the prompts in the MetaMask popup to connect" + }, + "footer": { + "buttonText1": "Ready to connect", + "buttonText2": "Try again" + } + }, + "passport": { + "body": { + "heading": "Connect with Immutable Passport", + "content": "Follow the prompts to connect with Immutable Passport" + }, + "footer": { + "buttonText1": "Continue", + "buttonText2": "Try again" + } + } + }, + "SWITCH_NETWORK": { + "eth": { + "heading": "To move your coins, you'll need to switch to the Sepolia network", + "body": "You'll be prompted to switch networks in MetaMask. You'll be able to switch back when needed.", + "button": { + "text": "Ready to Switch", + "retryText": "Try Again" + } + }, + "zkEVM": { + "heading": "You’ll be asked to switch to the Immutable zkEVM network", + "body": "Check for the pop-up from MetaMask and 'Approve' to switch. If this is the first time, MetaMask will also ask you to add the network.", + "button": { + "text": "Ready to Switch", + "retryText": "Try Again" + } + } + }, + "ERROR_VIEW": { + "heading": "Something's gone wrong", + "body": ["You can try again or contact", "support", "for help."], + "actionText": "Try again" + }, + "SERVICE_UNAVAILABLE_ERROR_VIEW": { + "heading": { + "swap": "Swapping is not available in your region" + }, + "body": "We’re sorry we cannot provide this service in your region." + }, + "LOADING_VIEW": { + "text": "Loading" + }, + "WALLET_BALANCES": { + "header": { + "title": "Wallet" + }, + "networkStatus": { + "heading": "Network" + }, + "totalTokenBalance": { + "heading": "Coins", + "totalHeading": "Value" + }, + "tokenBalancesList": { + "noTokensFound": "No tokens found" + }, + "addCoins": "Add coins" + }, + "SETTINGS": { + "header": { + "title": "Settings" + }, + "disconnectButton": { + "label": "Disconnect Wallet" + } + }, + "COIN_INFO": { + "metamask": { + "heading": "Coins and collectibles are native to networks", + "body": "You can switch networks to add coins or move them from one network to another" + }, + "passport": { + "heading": "Coins and collectibles are native to networks", + "body1": "This network is called Immutable zkEVM. If you have other coins in your Passport and can’t see them here, they might be on another network. ", + "body2": " for more info.", + "linkText": "Visit our FAQs" + } + }, + "SWAP": { + "header": { + "title": "Swap coins" + }, + "content": { + "title": "What would you like to swap?", + "fiatPricePrefix": "Approx USD", + "availableBalancePrefix": "Available" + }, + "swapForm": { + "from": { + "label": "From", + "inputPlaceholder": "0", + "selectorTitle": "What would you like to swap from?" + }, + "to": { + "label": "To", + "inputPlaceholder": "0", + "selectorTitle": "What would you like to swap to?" + }, + "buttonText": "Swap" + }, + "fees": { + "title": "Fees total" + }, + "validation": { + "noAmountInputted": "Please input amount", + "insufficientBalance": "Insufficient balance", + "noFromTokenSelected": "Select a coin to swap", + "noToTokenSelected": "Select a coin to receive" + }, + "success": { + "text": "Success", + "actionText": "Continue" + }, + "failed": { + "text": "Transaction rejected", + "actionText": "Try again" + }, + "rejected": { + "text": "Price surge", + "actionText": "Review & try again" + }, + "IN_PROGRESS": { + "loading": { + "text": "Swap in progress" + } + } + }, + "APPROVE_ERC20": { + "approveSwap": { + "content": { + "heading": "Now you'll just need to confirm the transaction", + "body": "Follow the prompts in your wallet." + }, + "footer": { + "buttonText": "Okay", + "retryText": "Try again" + } + }, + "approveSpending": { + "content": { + "metamask": { + "heading": "You'll be asked to set a spending cap for this transaction", + "body": "Input at least {{amount}} for this transaction and future transactions, then follow the prompts." + }, + "passport": { + "heading": "You'll be asked to approve a spending cap for this transaction", + "body": "Follow the prompts in your wallet to approve the spending cap." + } + }, + "footer": { + "buttonText": "Got it", + "retryText": "Try again" + }, + "loading": { + "text": "Approving spending cap" + } + } + }, + "ONRAMP": { + "header": { + "title": "Add coins" + }, + "initialLoadingText": "Taking you to Transak", + "IN_PROGRESS_LOADING": { + "loading": { + "text": "Transak is processing your order" + } + }, + "IN_PROGRESS": { + "content": { + "heading": "Order in progress", + "body1": "You’ll receive an email from Transak when complete. This can take up to 3 mins.", + "body2": "You can close this window, the transaction will be reflected in your wallet once complete." + } + }, + "SUCCESS": { + "text": "Coins are on the way", + "actionText": "Done" + }, + "FAIL": { + "text": "Transaction failed", + "actionText": "Try again" + } + }, + "TOP_UP_VIEW": { + "header": { + "title": "How would you like to add coins?" + }, + "topUpOptions": { + "onramp": { + "heading": "Buy with card", + "caption": "Google pay & Apple pay available. Minimum $5.", + "subcaption": "Fees", + "disabledCaption": "" + }, + "swap": { + "heading": "Swap my coins", + "caption": "Using the coins I have on the same network", + "subcaption": "Fees", + "disabledCaption": "Not available in your region" + }, + "bridge": { + "heading": "Move my coins", + "caption": "From the coins I have on a different network", + "subcaption": "Fees ", + "disabledCaption": "" + } + } + }, + "FUND_WITH_SMART_CHECKOUT": { + "loading": { + "checkingBalances": "Crunching numbers" + }, + "currency": { + "usdEstimate": "≈ USD $", + "fees": "Fees" + }, + "fundingRouteDrawer": { + "header": "Available balance" + }, + "fundingRouteSelect": { + "heading": "Pay with your", + "noRoutesAvailable": "Insufficient coin balance. Please proceed with card instead.", + "continue": "Continue", + "payWithCardInstead": "No thanks, I'll pay with card", + "payWithCard": "Pay with card" + } + }, + "PAYMENT_METHODS": { + "header": { + "heading": "How would you like to pay?" + }, + "options": { + "CRYPTO": { + "heading": "Coins", + "caption": "Using the coins balance in your wallet", + "disabledCaption": "We can't see enough coins in your balance" + }, + "FIAT": { + "heading": "Card", + "caption": "GooglePay also available with Transak", + "disabledCaption": null + } + }, + "insufficientCoinsBanner": { + "caption": "Insufficient coin balance. Please proceed with card instead." + }, + "loading": { + "ready": "Ready to purchase", + "confirm": "Confirm in your wallet", + "processing": "Processing purchase" + } + }, + "PAY_WITH_COINS": { + "header": { + "heading": "Pay with your", + "caption": "Using the coins balance in your wallet" + }, + "button": { + "buyNow": "Buy now" + } + }, + "PAY_WITH_CARD": { + "screenTitle": "Pay with card", + "loading": "Taking you to Transak" + }, + "SALE_FAIL": { + "errors": { + "TRANSACTION_FAILED": { + "description": "Transaction failed", + "primaryAction": "Try again", + "secondaryAction": "View details" + }, + "SERVICE_BREAKDOWN": { + "description": "Sorry, we're unable to process your payment right now. Please try again in a few minutes.", + "secondaryAction": "Dismiss" + }, + "TRANSAK_FAILED": { + "description": "Sorry, something went wrong. Please try again.", + "primaryAction": "Try again", + "secondaryAction": "Dismiss" + }, + "WALLET_FAILED": { + "description": "Sorry, we're unable to process this right now.", + "primaryAction": "Go back", + "secondaryAction": "Dismiss" + }, + "WALLET_REJECTED_NO_FUNDS": { + "description": "Sorry, something went wrong. Please try again.", + "primaryAction": "Go back", + "secondaryAction": "Dismiss" + }, + "WALLET_REJECTED": { + "description": "You'll need to approve the transaction in your wallet to proceed.", + "primaryAction": "Try again", + "secondaryAction": "Cancel" + }, + "SMART_CHECKOUT_ERROR": { + "description": "Unable to check your wallets balance. Please try again.", + "primaryAction": "Try again", + "secondaryAction": "Cancel" + }, + "SMART_CHECKOUT_EXECUTE_ERROR": { + "description": "Sorry, something went wrong while moving funds. Please try again.", + "primaryAction": "Try again", + "secondaryAction": "Cancel" + }, + "DEFAULT": { + "description": "Sorry, something went wrong. Please try again.", + "primaryAction": "Try again", + "secondaryAction": "Dismiss" + } + } + }, + "SALE_SUCCESS": { + "text": "Order completed", + "actionText": "Continue" + }, + "WALLET_NETWORK_SELECTION": { + "layoutHeading": "Move", + "heading": "Where would you like to move funds between?", + "fromFormInput": { + "heading": "From", + "selectDefaultText": "Select wallet and network", + "walletSelectorHeading": "From wallet", + "networkSelectorHeading": "From network" + }, + "toFormInput": { + "heading": "To", + "selectDefaultText": "Select wallet and network", + "walletSelectorHeading": "To wallet" + }, + "submitButton": { + "text": "Next" + } + }, + "BRIDGE_FORM": { + "header": { + "title": "Move coins" + }, + "fees": { + "title": "Gas Fee", + "fiatPricePrefix": "~ USD $" + }, + "content": { + "title": "How much would you like to move?", + "fiatPricePrefix": "Approx USD", + "availableBalancePrefix": "Available" + }, + "bridgeForm": { + "from": { + "inputPlaceholder": "0", + "selectorTitle": "What would you like to move?" + }, + "buttonText": "Review" + }, + "validation": { + "noAmountInputted": "Please input amount", + "insufficientBalance": "Insufficient balance", + "noTokenSelected": "Select a coin to move" + } + }, + "BRIDGE_REVIEW": { + "layoutHeading": "Move", + "heading": "Ok, how does this look?", + "fromLabel": { + "amountHeading": "Moving", + "heading": "From" + }, + "toLabel": { + "heading": "To" + }, + "fees": { + "heading": "Gas fee" + }, + "submitButton": { + "buttonText": "Confirm move" + }, + "fiatPricePrefix": "~ USD $" + }, + "BRIDGE_FAILURE": { + "statusText": "Transaction failed", + "actionText": "Review & Try again" + }, + "APPROVE_TRANSACTION": { + "content": { + "heading": "Approve the transaction in your wallet", + "body": "Follow the prompts in your wallet popup to confirm." + }, + "footer": { + "buttonText": "Okay", + "retryText": "Try again" + }, + "loadingView": { + "text": "Initiating move" + } + }, + "IN_PROGRESS": { + "heading": "Move in progress", + "body1": "Less than 3 mins until your ${symbol} lands on zkEVM.", + "body2": "You can close this window, the transaction will be reflected in your wallet once complete." + } + }, + "footers": { + "quickswapFooter": { + "disclaimerText": "Quickswap is a third party app. Immutable neither builds, owns, operates or deploys Quickswap. For further info, refer to Quickswap’s website." + } + }, + "wallets": { + "passport": { + "heading": "Immutable Passport", + "accentText": "Recommended", + "description": "digital wallet and identity" + }, + "metamask": { + "heading": "MetaMask", + "description": "Digital wallet for accessing blockchain applications and web3" + } + }, + "drawers": { + "feesBreakdown": { + "heading": "Fee breakdown", + "total": "Fees total", + "fees": { + "gas": { + "label": "Gas fee" + } + } + }, + "transactionFailed": { + "content": { + "heading1": "We’ll need you to confirm in your", + "heading2": "wallet before proceeding", + "body1": "When the MetaMask pop up appears, be sure to", + "body2": "sign the transaction" + }, + "buttons": { + "retry": "Got it", + "cancel": "Dismiss" + } + }, + "coinSelector": { + "option": { + "fiatPricePrefix": "Approx USD $" + }, + "noCoins": "You have no available coins to select in your wallet." + }, + "notEnoughGas": { + "content": { + "heading": "Balance too low", + "body": "You're ETH balance is too low to cover the gas fee on this move. You could transfer more ETH into your wallet using MetaMask directly." + }, + "buttons": { + "adjustAmount": "Adjust amount", + "copyAddress": "Copy wallet address", + "cancel": "Dismiss" + } + }, + "notEnoughImx": { + "content": { + "noImx": { + "heading": "You'll need IMX coins to swap", + "body": "Swap fees are paid in IMX coins, so you'll need to add this before you can swap" + }, + "insufficientImx": { + "heading": "You'll need more IMX coins", + "body": "In order to cover the fees for the amount specified, you'll need to add more IMX coins" + } + }, + "buttons": { + "adjustAmount": "Adjust amount", + "addMoreImx": "Add IMX coins", + "cancel": "Dismiss" + } + }, + "unableToSwap": { + "heading": "Unable to swap this coin", + "body": "This coin pairing isn't available to swap right now. Try another selection.", + "buttons": { + "cancel": "Dismiss" + } + } + } +} diff --git a/packages/checkout/widgets-lib/src/locales/ja.json b/packages/checkout/widgets-lib/src/locales/ja.json new file mode 100644 index 0000000000..0aa5e20f0a --- /dev/null +++ b/packages/checkout/widgets-lib/src/locales/ja.json @@ -0,0 +1,514 @@ +{ + "views": { + "CONNECT_WALLET": { + "body": { + "heading": "ウォレットを接続する", + "content": "購入、販売、取引、およびコインとコレクティブルを保存するには、デジタルウォレットを接続または作成する必要があります。" + } + }, + "CONNECT_SUCCESS": { + "status": "接続が安全です", + "action": "続ける" + }, + "READY_TO_CONNECT": { + "header": { + "title": "接続する" + }, + "metamask": { + "body": { + "heading": "MetaMaskからのポップアップを確認する", + "content": "MetaMaskのポップアップに従って接続してください" + }, + "footer": { + "buttonText1": "接続する準備ができました", + "buttonText2": "再試行する" + } + }, + "passport": { + "body": { + "heading": "Immutable Passportで接続する", + "content": "Immutable Passportに接続するためのプロンプトに従ってください" + }, + "footer": { + "buttonText1": "続ける", + "buttonText2": "再試行する" + } + } + }, + "SWITCH_NETWORK": { + "eth": { + "heading": "コインを移動するには、セポリアネットワークに切り替える必要があります", + "body": "MetaMaskでネットワークを切り替えるように求められます。必要に応じて後で切り替えることができます。", + "button": { + "text": "切り替えの準備ができました", + "retryText": "再試行する" + } + }, + "zkEVM": { + "heading": "Immutable zkEVMネットワークに切り替えるように求められます", + "body": "MetaMaskからのポップアップを確認し、「承認」して切り替えてください。これが初めての場合、MetaMaskはネットワークを追加するように求めることもあります。", + "button": { + "text": "切り替えの準備ができました", + "retryText": "再試行する" + } + } + }, + "ERROR_VIEW": { + "heading": "何かがうまくいかない", + "body": ["もう一度やってみるか、", "サポート", "に連絡して助けを求めることができます。"], + "actionText": "もう一度試す" + }, + "SERVICE_UNAVAILABLE_ERROR_VIEW": { + "heading": { + "swap": "お使いの地域ではスワッピングは利用できません" + }, + "body": "お使いの地域ではこのサービスを提供できないことをお詫び申し上げます。" + }, + "LOADING_VIEW": { + "text": "読み込み中" + }, + "WALLET_BALANCES": { + "header": { + "title": "ウォレット" + }, + "networkStatus": { + "heading": "ネットワーク" + }, + "totalTokenBalance": { + "heading": "コイン", + "totalHeading": "価値" + }, + "tokenBalancesList": { + "noTokensFound": "トークンが見つかりません" + }, + "addCoins": "コインを追加" + }, + "SETTINGS": { + "header": { + "title": "設定" + }, + "disconnectButton": { + "label": "ウォレットを切断" + } + }, + "COIN_INFO": { + "metamask": { + "heading": "コインとコレクティブルはネットワーク固有です", + "body": "コインを追加したり、ネットワーク間でコインを移動したりするには、ネットワークを切り替えることができます" + }, + "passport": { + "heading": "コインとコレクティブルはネットワーク固有です", + "body1": "このネットワークはImmutable zkEVMと呼ばれます。Passportに他のコインがあり、ここに表示されない場合、それらは別のネットワークにあるかもしれません。", + "body2": "詳細については、", + "linkText": "FAQをご覧ください" + } + }, + "SWAP": { + "header": { + "title": "コインをスワップ" + }, + "content": { + "title": "何をスワップしたいですか?", + "fiatPricePrefix": "約USD", + "availableBalancePrefix": "利用可能" + }, + "swapForm": { + "from": { + "label": "出金元", + "inputPlaceholder": "0", + "selectorTitle": "何からスワップしたいですか?" + }, + "to": { + "label": "宛先", + "inputPlaceholder": "0", + "selectorTitle": "何にスワップしたいですか?" + }, + "buttonText": "スワップ" + }, + "fees": { + "title": "手数料合計" + }, + "validation": { + "noAmountInputted": "金額を入力してください", + "insufficientBalance": "残高不足", + "noFromTokenSelected": "スワップするコインを選択してください", + "noToTokenSelected": "受け取るコインを選択してください" + }, + "success": { + "text": "成功", + "actionText": "続行" + }, + "failed": { + "text": "トランザクションが拒否されました", + "actionText": "もう一度試す" + }, + "rejected": { + "text": "価格が急騰しています", + "actionText": "レビューしてもう一度試す" + }, + "IN_PROGRESS": { + "loading": { + "text": "スワップ進行中" + } + } + }, + "APPROVE_ERC20": { + "approveSwap": { + "content": { + "heading": "これでトランザクションを承認する必要があります", + "body": "ウォレットのプロンプトに従ってください。" + }, + "footer": { + "buttonText": "はい", + "retryText": "もう一度試す" + } + }, + "approveSpending": { + "content": { + "metamask": { + "heading": "このトランザクションのために支出上限を設定するように求められます", + "body": [ + "少なくとも入力してください", + "このトランザクションおよび将来のトランザクションのために、その後、プロンプトに従ってください。" + ] + }, + "passport": { + "heading": "このトランザクションのために支出上限を承認するように求められます", + "body": "ウォレットのプロンプトに従って支出上限を承認してください。" + } + }, + "footer": { + "buttonText": "了解", + "retryText": "もう一度試す" + }, + "loading": { + "text": "支出上限を承認しています" + } + } + }, + "ONRAMP": { + "header": { + "title": "コインを追加" + }, + "initialLoadingText": "Transakに移動しています", + "IN_PROGRESS_LOADING": { + "loading": { + "text": "Transakが注文を処理しています" + } + }, + "IN_PROGRESS": { + "content": { + "heading": "注文進行中", + "body1": "完了するとTransakからメールが届きます。これには最大3分かかる場合があります。", + "body2": "このウィンドウを閉じても、トランザクションは完了次第ウォレットに反映されます。" + } + }, + "SUCCESS": { + "text": "コインが途中にあります", + "actionText": "完了" + }, + "FAIL": { + "text": "トランザクションが失敗しました", + "actionText": "もう一度試す" + } + }, + "TOP_UP_VIEW": { + "header": { + "title": "どのようにしてコインを追加しますか?" + }, + "topUpOptions": { + "onramp": { + "heading": "カードで購入", + "caption": "Google PayおよびApple Payが利用可能です。最低$5。", + "subcaption": "手数料", + "disabledCaption": "" + }, + "swap": { + "heading": "コインをスワップ", + "caption": "同じネットワーク上の自分のコインを使用して", + "subcaption": "手数料", + "disabledCaption": "お使いの地域では利用できません" + }, + "bridge": { + "heading": "コインを移動", + "caption": "異なるネットワーク上の自分のコインから", + "subcaption": "手数料 ", + "disabledCaption": "" + } + } + }, + "FUND_WITH_SMART_CHECKOUT": { + "loading": { + "checkingBalances": "数値を計算しています" + }, + "currency": { + "usdEstimate": "≈ USD $", + "fees": "手数料" + }, + "fundingRouteDrawer": { + "header": "利用可能な残高" + }, + "fundingRouteSelect": { + "heading": "で支払う", + "noRoutesAvailable": "コインの残高が不足しています。代わりにカードで続行してください。", + "continue": "続行", + "payWithCardInstead": "いいえ、カードで支払います", + "payWithCard": "カードで支払う" + } + }, + "PAYMENT_METHODS": { + "header": { + "heading": "どのようにして支払いますか?" + }, + "options": { + "CRYPTO": { + "heading": "コイン", + "caption": "ウォレットのコイン残高を使用して", + "disabledCaption": "残高に十分なコインが見当たりません" + }, + "FIAT": { + "heading": "カード", + "caption": "GooglePayもTransakで利用可能", + "disabledCaption": "" + } + }, + "insufficientCoinsBanner": { + "caption": "コイン残高が不足しています。カードを使用してください。" + }, + "loading": { + "ready": "購入の準備ができました", + "confirm": "ウォレットで確認してください", + "processing": "購入処理中" + } + }, + "PAY_WITH_COINS": { + "header": { + "heading": "あなたので支払う", + "caption": "ウォレットのコイン残高を使用して" + }, + "button": { + "buyNow": "今すぐ購入" + } + }, + "PAY_WITH_CARD": { + "screenTitle": "カードで支払う", + "loading": "Transakに移動しています" + }, + "SALE_FAIL": { + "errors": { + "TRANSACTION_FAILED": { + "description": "トランザクションが失敗しました", + "primaryAction": "もう一度試す", + "secondaryAction": "詳細を表示" + }, + "SERVICE_BREAKDOWN": { + "description": "申し訳ありませんが、現在お支払いを処理できません。数分後にもう一度お試しください。", + "secondaryAction": "閉じる" + }, + "TRANSAK_FAILED": { + "description": "申し訳ありませんが、何かがうまくいかなかったようです。もう一度お試しください。", + "primaryAction": "もう一度試す", + "secondaryAction": "閉じる" + }, + "WALLET_FAILED": { + "description": "申し訳ありませんが、現在これを処理できません。", + "primaryAction": "戻る", + "secondaryAction": "閉じる" + }, + "WALLET_REJECTED_NO_FUNDS": { + "description": "申し訳ありませんが、何かがうまくいかなかったようです。もう一度お試しください。", + "primaryAction": "戻る", + "secondaryAction": "閉じる" + }, + "WALLET_REJECTED": { + "description": "取引を承認するには、ウォレットで承認する必要があります。", + "primaryAction": "もう一度試す", + "secondaryAction": "キャンセル" + }, + "SMART_CHECKOUT_ERROR": { + "description": "ウォレットの残高を確認できません。もう一度お試しください。", + "primaryAction": "もう一度試す", + "secondaryAction": "キャンセル" + }, + "SMART_CHECKOUT_EXECUTE_ERROR": { + "description": "資金を移動する際に何かがうまくいかなかったようです。もう一度お試しください。", + "primaryAction": "もう一度試す", + "secondaryAction": "キャンセル" + }, + "DEFAULT": { + "description": "申し訳ありませんが、何かがうまくいかなかったようです。もう一度お試しください。", + "primaryAction": "もう一度試す", + "secondaryAction": "閉じる" + } + } + }, + "SALE_SUCCESS": { + "text": "注文が完了しました", + "actionText": "続行" + }, + "WALLET_NETWORK_SELECTION": { + "layoutHeading": "移動", + "heading": "どこに資金を移動させたいですか?", + "fromFormInput": { + "heading": "From", + "selectDefaultText": "ウォレットとネットワークを選択", + "walletSelectorHeading": "From wallet", + "networkSelectorHeading": "From network" + }, + "toFormInput": { + "heading": "To", + "selectDefaultText": "ウォレットとネットワークを選択", + "walletSelectorHeading": "To wallet" + }, + "submitButton": { + "text": "次へ" + } + }, + "BRIDGE_FORM": { + "header": { + "title": "コインを移動" + }, + "fees": { + "title": "ガス手数料", + "fiatPricePrefix": "~ USD $" + }, + "content": { + "title": "いくら移動しますか?", + "fiatPricePrefix": "約USD", + "availableBalancePrefix": "利用可能" + }, + "bridgeForm": { + "from": { + "inputPlaceholder": "0", + "selectorTitle": "移動するコインを選択" + }, + "buttonText": "確認" + }, + "validation": { + "noAmountInputted": "金額を入力してください", + "insufficientBalance": "残高が不足しています", + "noTokenSelected": "移動するコインを選択してください" + } + }, + "BRIDGE_REVIEW": { + "layoutHeading": "移動", + "heading": "これはどう見えますか?", + "fromLabel": { + "amountHeading": "移動中", + "heading": "From" + }, + "toLabel": { + "heading": "To" + }, + "fees": { + "heading": "ガス手数料" + }, + "submitButton": { + "buttonText": "移動を確認" + }, + "fiatPricePrefix": "~ USD $" + }, + "BRIDGE_FAILURE": { + "statusText": "トランザクションが失敗しました", + "actionText": "再確認してもう一度試す" + }, + "APPROVE_TRANSACTION": { + "content": { + "heading": "ウォレットでトランザクションを承認してください", + "body": "ウォレットのポップアップで表示されるプロンプトに従って承認してください。" + }, + "footer": { + "buttonText": "OK", + "retryText": "もう一度試す" + }, + "loadingView": { + "text": "移動を開始しています" + } + }, + "IN_PROGRESS": { + "heading": "移動進行中", + "body1": "あなたの${symbol}がzkEVMに着陸するまで3分未満。", + "body2": "このウィンドウを閉じても、トランザクションは完了したらウォレットに反映されます。" + } + }, + "footers": { + "quickswapFooter": { + "disclaimerText": "Quickswapはサードパーティアプリケーションです。ImmutableはQuickswapをビルド、所有、運営、デプロイしていません。詳細については、Quickswapのウェブサイトを参照してください。" + } + }, + "wallets": { + "passport": { + "heading": "Immutable Passport", + "accentText": "おすすめ", + "description": "デジタルウォレットおよびアイデンティティ" + }, + "metamask": { + "heading": "MetaMask", + "description": "ブロックチェーンアプリケーションとWeb3へのアクセス用のデジタルウォレット" + } + }, + "drawers": { + "feesBreakdown": { + "heading": "手数料の内訳", + "total": "総手数料", + "fees": { + "gas": { + "label": "ガス手数料" + } + } + }, + "transactionFailed": { + "content": { + "heading1": "続行する前に、", + "heading2": "ウォレットで確認が必要です", + "body1": "MetaMaskのポップアップが表示されたら、", + "body2": "トランザクションに署名してください" + }, + "buttons": { + "retry": "了解", + "cancel": "閉じる" + } + }, + "coinSelector": { + "option": { + "fiatPricePrefix": "約USD $" + }, + "noCoins": "ウォレットで選択できるコインがありません。" + }, + "notEnoughGas": { + "content": { + "heading": "残高が低すぎます", + "body": "この移動のガス手数料をカバーするには、ETH残高が不足しています。MetaMaskを使用して直接ウォレットにETHを送金することができます。" + }, + "buttons": { + "adjustAmount": "金額を調整", + "copyAddress": "ウォレットアドレスをコピー", + "cancel": "閉じる" + } + }, + "notEnoughImx": { + "content": { + "noImx": { + "heading": "IMXコインが必要です", + "body": "スワップ手数料はIMXコインで支払われるため、スワップする前にこれを追加する必要があります。" + }, + "insufficientImx": { + "heading": "IMXコインが不足しています", + "body": "指定された金額の手数料をカバーするためには、IMXコインを追加する必要があります。" + } + }, + "buttons": { + "adjustAmount": "金額を調整", + "addMoreImx": "IMXコインを追加", + "cancel": "閉じる" + } + }, + "unableToSwap": { + "heading": "このコインはスワップできません", + "body": "このコインのペアは現在スワップできません。別の選択肢を試してください。", + "buttons": { + "cancel": "閉じる" + } + } + } +} diff --git a/packages/checkout/widgets-lib/src/locales/ko.json b/packages/checkout/widgets-lib/src/locales/ko.json new file mode 100644 index 0000000000..3d5970fa2d --- /dev/null +++ b/packages/checkout/widgets-lib/src/locales/ko.json @@ -0,0 +1,511 @@ +{ + "views": { + "CONNECT_WALLET": { + "body": { + "heading": "지갑 연결", + "content": "구매, 판매, 거래 및 코인과 수집품을 저장하려면 디지털 지갑을 연결하거나 만들어야 합니다." + } + }, + "CONNECT_SUCCESS": { + "status": "연결이 안전함", + "action": "계속하기" + }, + "READY_TO_CONNECT": { + "header": { + "title": "연결 준비됨" + }, + "metamask": { + "body": { + "heading": "MetaMask에서 팝업을 확인하세요", + "content": "MetaMask 팝업의 안내에 따라 연결하세요" + }, + "footer": { + "buttonText1": "연결 준비됨", + "buttonText2": "다시 시도" + } + }, + "passport": { + "body": { + "heading": "Immutable Passport로 연결", + "content": "Immutable Passport와 연결하기 위한 안내를 따르세요" + }, + "footer": { + "buttonText1": "계속", + "buttonText2": "다시 시도" + } + } + }, + "SWITCH_NETWORK": { + "eth": { + "heading": "코인을 옮기려면 Sepolia 네트워크로 전환해야 합니다", + "body": "MetaMask에서 네트워크 전환을 요청받게 됩니다. 필요할 때 다시 전환할 수 있습니다.", + "button": { + "text": "전환 준비됨", + "retryText": "다시 시도" + } + }, + "zkEVM": { + "heading": "Immutable zkEVM 네트워크로 전환하라는 요청을 받게 됩니다", + "body": "MetaMask 팝업에서 '승인'을 선택하고 전환하세요. 처음이라면 MetaMask에서 네트워크 추가를 요구할 수도 있습니다.", + "button": { + "text": "전환 준비됨", + "retryText": "다시 시도" + } + } + }, + "ERROR_VIEW": { + "heading": "문제가 발생했습니다", + "body": ["다시 시도하거나", "지원팀에", "도움을 요청하세요."], + "actionText": "다시 시도" + }, + "SERVICE_UNAVAILABLE_ERROR_VIEW": { + "heading": { + "swap": "당신의 지역에서는 교환이 가능하지 않습니다" + }, + "body": "당신의 지역에서 이 서비스를 제공할 수 없어 죄송합니다." + }, + "LOADING_VIEW": { + "text": "로딩 중" + }, + "WALLET_BALANCES": { + "header": { + "title": "지갑" + }, + "networkStatus": { + "heading": "네트워크" + }, + "totalTokenBalance": { + "heading": "코인", + "totalHeading": "가치" + }, + "tokenBalancesList": { + "noTokensFound": "토큰을 찾을 수 없습니다" + }, + "addCoins": "동전 추가" + }, + "SETTINGS": { + "header": { + "title": "설정" + }, + "disconnectButton": { + "label": "지갑 연결 해제" + } + }, + "COIN_INFO": { + "metamask": { + "heading": "코인과 수집품은 네트워크에 기반을 두고 있습니다", + "body": "네트워크를 전환하여 코인을 추가하거나 다른 네트워크로 옮길 수 있습니다" + }, + "passport": { + "heading": "코인과 수집품은 네트워크에 기반을 두고 있습니다", + "body1": "이 네트워크는 Immutable zkEVM입니다. Passport에 다른 코인이 있고 여기서 볼 수 없다면 다른 네트워크에 있을 수 있습니다.", + "body2": " 자세한 정보를 위해 우리의 FAQ를 방문하세요.", + "linkText": "FAQ 방문하기" + } + }, + "SWAP": { + "header": { + "title": "코인 교환" + }, + "content": { + "title": "무엇을 교환하고 싶으신가요?", + "fiatPricePrefix": "약 USD", + "availableBalancePrefix": "사용 가능" + }, + "swapForm": { + "from": { + "label": "From", + "inputPlaceholder": "0", + "selectorTitle": "무엇을 교환하고 싶으신가요?" + }, + "to": { + "label": "To", + "inputPlaceholder": "0", + "selectorTitle": "무엇을 받으시겠습니까?" + }, + "buttonText": "교환" + }, + "fees": { + "title": "수수료 총액" + }, + "validation": { + "noAmountInputted": "금액을 입력해 주세요", + "insufficientBalance": "잔고가 부족합니다", + "noFromTokenSelected": "교환할 코인을 선택하세요", + "noToTokenSelected": "받을 코인을 선택하세요" + }, + "success": { + "text": "성공", + "actionText": "계속하기" + }, + "failed": { + "text": "거래 거절됨", + "actionText": "다시 시도" + }, + "rejected": { + "text": "가격 급등", + "actionText": "검토하고 다시 시도하세요" + }, + "IN_PROGRESS": { + "loading": { + "text": "교환 진행 중" + } + } + }, + "APPROVE_ERC20": { + "approveSwap": { + "content": { + "heading": "이제 거래를 확인하기만 하면 됩니다", + "body": "지갑의 안내를 따르세요." + }, + "footer": { + "buttonText": "확인", + "retryText": "다시 시도" + } + }, + "approveSpending": { + "content": { + "metamask": { + "heading": "이 거래에 대한 지출 한도를 설정하라는 요청을 받게 될 것입니다", + "body": "이 거래 및 향후 거래를 위해 최소 {{amount}}을 입력한 후, 안내를 따르세요." + }, + "passport": { + "heading": "이 거래에 대한 지출 한도 승인을 받게 됩니다", + "body": "지출 한도를 승인하기 위해 지갑의 안내를 따르세요." + } + }, + "footer": { + "buttonText": "알겠습니다", + "retryText": "다시 시도" + }, + "loading": { + "text": "지출 한도 승인 중" + } + } + }, + "ONRAMP": { + "header": { + "title": "코인 추가" + }, + "initialLoadingText": "Transak으로 이동하는 중", + "IN_PROGRESS_LOADING": { + "loading": { + "text": "Transak가 주문을 처리 중입니다" + } + }, + "IN_PROGRESS": { + "content": { + "heading": "주문 진행 중", + "body1": "완료되면 Transak에서 이메일을 받게 됩니다. 최대 3분이 소요될 수 있습니다.", + "body2": "이 창을 닫을 수 있으며, 완료되면 거래가 지갑에 반영됩니다." + } + }, + "SUCCESS": { + "text": "코인이 도착하는 중입니다", + "actionText": "완료" + }, + "FAIL": { + "text": "거래 실패", + "actionText": "다시 시도" + } + }, + "TOP_UP_VIEW": { + "header": { + "title": "코인을 추가하시겠습니까?" + }, + "topUpOptions": { + "onramp": { + "heading": "카드로 구매", + "caption": "Google Pay 및 Apple Pay 사용 가능. 최소 $5.", + "subcaption": "수수료", + "disabledCaption": "" + }, + "swap": { + "heading": "내 코인 교환", + "caption": "동일 네트워크 내에서 내가 가진 코인을 이용하여", + "subcaption": "수수료", + "disabledCaption": "귀하의 지역에서 사용할 수 없습니다" + }, + "bridge": { + "heading": "내 코인 이동", + "caption": "다른 네트워크에서 가진 코인을 이동하여", + "subcaption": "수수료", + "disabledCaption": "" + } + } + }, + "FUND_WITH_SMART_CHECKOUT": { + "loading": { + "checkingBalances": "숫자를 계산하는 중" + }, + "currency": { + "usdEstimate": "≈ USD $", + "fees": "수수료" + }, + "fundingRouteDrawer": { + "header": "사용 가능한 잔액" + }, + "fundingRouteSelect": { + "heading": "Pay with your", + "noRoutesAvailable": "코인 잔액이 부족합니다. 대신 카드로 진행하세요.", + "continue": "계속", + "payWithCardInstead": "괜찮습니다, 카드로 결제할게요", + "payWithCard": "카드로 결제하기" + } + }, + "PAYMENT_METHODS": { + "header": { + "heading": "어떤 방법으로 결제하시겠습니까?" + }, + "options": { + "CRYPTO": { + "heading": "코인", + "caption": "지갑에 있는 코인 잔액을 이용하여", + "disabledCaption": "지갑의 충분한 코인을 볼 수 없습니다" + }, + "FIAT": { + "heading": "카드", + "caption": "Transak에서 GooglePay도 이용 가능합니다", + "disabledCaption": "" + } + }, + "insufficientCoinsBanner": { + "caption": "코인 잔액이 부족합니다. 대신 카드로 진행하세요." + }, + "loading": { + "ready": "구매 준비됨", + "confirm": "지갑에서 확인하세요", + "processing": "구매 처리 중" + } + }, + "PAY_WITH_COINS": { + "header": { + "heading": "코인으로 결제", + "caption": "지갑에 있는 코인 잔액을 이용하여" + }, + "button": { + "buyNow": "지금 구매" + } + }, + "PAY_WITH_CARD": { + "screenTitle": "카드로 결제", + "loading": "Transak으로 이동하는 중" + }, + "SALE_FAIL": { + "errors": { + "TRANSACTION_FAILED": { + "description": "거래 실패", + "primaryAction": "다시 시도", + "secondaryAction": "세부 정보 보기" + }, + "SERVICE_BREAKDOWN": { + "description": "죄송합니다, 현재 지불 처리가 불가능합니다. 몇 분 후에 다시 시도하세요.", + "secondaryAction": "닫기" + }, + "TRANSAK_FAILED": { + "description": "죄송합니다, 문제가 발생했습니다. 다시 시도하세요.", + "primaryAction": "다시 시도", + "secondaryAction": "닫기" + }, + "WALLET_FAILED": { + "description": "죄송합니다, 지금은 이를 처리할 수 없습니다.", + "primaryAction": "돌아가기", + "secondaryAction": "닫기" + }, + "WALLET_REJECTED_NO_FUNDS": { + "description": "죄송합니다, 문제가 발생했습니다. 다시 시도하세요.", + "primaryAction": "돌아가기", + "secondaryAction": "닫기" + }, + "WALLET_REJECTED": { + "description": "거래를 진행하려면 지갑에서 거래 승인이 필요합니다.", + "primaryAction": "다시 시도", + "secondaryAction": "취소" + }, + "SMART_CHECKOUT_ERROR": { + "description": "지갑 잔액을 확인할 수 없습니다. 다시 시도하세요.", + "primaryAction": "다시 시도", + "secondaryAction": "취소" + }, + "SMART_CHECKOUT_EXECUTE_ERROR": { + "description": "죄송합니다, 자금 이동 중 문제가 발생했습니다. 다시 시도하세요.", + "primaryAction": "다시 시도", + "secondaryAction": "취소" + }, + "DEFAULT": { + "description": "죄송합니다, 문제가 발생했습니다. 다시 시도하세요.", + "primaryAction": "다시 시도", + "secondaryAction": "닫기" + } + } + }, + "SALE_SUCCESS": { + "text": "주문 완료", + "actionText": "계속" + }, + "WALLET_NETWORK_SELECTION": { + "layoutHeading": "이동", + "heading": "자금을 어디에서 어디로 이동하시겠습니까?", + "fromFormInput": { + "heading": "From", + "selectDefaultText": "지갑과 네트워크를 선택하세요", + "walletSelectorHeading": "지갑에서", + "networkSelectorHeading": "네트워크에서" + }, + "toFormInput": { + "heading": "To", + "selectDefaultText": "지갑과 네트워크를 선택하세요", + "walletSelectorHeading": "지갑으로" + }, + "submitButton": { + "text": "다음" + } + }, + "BRIDGE_FORM": { + "header": { + "title": "코인 이동" + }, + "fees": { + "title": "가스 요금", + "fiatPricePrefix": "~ USD $" + }, + "content": { + "title": "얼마나 많이 이동하시겠습니까?", + "fiatPricePrefix": "약 USD", + "availableBalancePrefix": "사용 가능" + }, + "bridgeForm": { + "from": { + "inputPlaceholder": "0", + "selectorTitle": "무엇을 이동하고 싶으신가요?" + }, + "buttonText": "검토" + }, + "validation": { + "noAmountInputted": "금액을 입력해 주세요", + "insufficientBalance": "잔고가 부족합니다", + "noTokenSelected": "이동할 코인을 선택하세요" + } + }, + "BRIDGE_REVIEW": { + "layoutHeading": "이동", + "heading": "이렇게 보이면 괜찮으십니까?", + "fromLabel": { + "amountHeading": "이동 중", + "heading": "From" + }, + "toLabel": { + "heading": "To" + }, + "fees": { + "heading": "가스 요금" + }, + "submitButton": { + "buttonText": "이동 확인" + }, + "fiatPricePrefix": "~ USD $" + }, + "BRIDGE_FAILURE": { + "statusText": "거래 실패", + "actionText": "검토하고 다시 시도하세요" + }, + "APPROVE_TRANSACTION": { + "content": { + "heading": "지갑에서 거래 승인", + "body": "지갑 팝업의 안내를 따라 확인하세요." + }, + "footer": { + "buttonText": "확인", + "retryText": "다시 시도" + }, + "loadingView": { + "text": "이동 시작 중" + } + }, + "IN_PROGRESS": { + "heading": "이동 중", + "body1": "3분 미만으로 당신의 ${symbol}이 zkEVM에 도착합니다.", + "body2": "이 창을 닫아도 됩니다. 거래가 완료되면 지갑에 반영될 것입니다." + } + }, + "footers": { + "quickswapFooter": { + "disclaimerText": "Quickswap는 타사 앱입니다. Immutable은 Quickswap를 만들거나 소유하거나 운영하거나 배포하지 않습니다. 자세한 정보는 Quickswap의 웹사이트를 참조하십시오." + } + }, + "wallets": { + "passport": { + "heading": "Immutable Passport", + "accentText": "추천", + "description": "디지털 지갑 및 신원" + }, + "metamask": { + "heading": "MetaMask", + "description": "블록체인 애플리케이션 및 웹3에 액세스하기 위한 디지털 지갑" + } + }, + "drawers": { + "feesBreakdown": { + "heading": "수수료 내역", + "total": "수수료 총액", + "fees": { + "gas": { + "label": "가스 수수료" + } + } + }, + "transactionFailed": { + "content": { + "heading1": "계속하기 전에 지갑에서 확인이 필요합니다", + "heading2": "지갑 확인 필요", + "body1": "MetaMask 팝업이 나타날 때 거래에", + "body2": "서명을 꼭 하십시오" + }, + "buttons": { + "retry": "알겠습니다", + "cancel": "취소" + } + }, + "coinSelector": { + "option": { + "fiatPricePrefix": "대략 USD $" + }, + "noCoins": "지갑에 선택 가능한 코인이 없습니다." + }, + "notEnoughGas": { + "content": { + "heading": "잔액이 너무 낮습니다", + "body": "이 이동에 필요한 가스 수수료를 충당하기에 ETH 잔액이 너무 낮습니다. MetaMask를 직접 사용하여 지갑에 ETH를 더 이전할 수 있습니다." + }, + "buttons": { + "adjustAmount": "금액 조정", + "copyAddress": "지갑 주소 복사", + "cancel": "취소" + } + }, + "notEnoughImx": { + "content": { + "noImx": { + "heading": "IMX 코인이 필요합니다", + "body": "교환 수수료는 IMX 코인으로 지불되므로 교환 전에 이를 추가해야 합니다" + }, + "insufficientImx": { + "heading": "더 많은 IMX 코인이 필요합니다", + "body": "지정된 금액의 수수료를 충당하기 위해 더 많은 IMX 코인을 추가해야 합니다" + } + }, + "buttons": { + "adjustAmount": "금액 조정", + "addMoreImx": "IMX 코인 추가", + "cancel": "취소" + } + }, + "unableToSwap": { + "heading": "해당 코인 교환 불가", + "body": "지금은 이 코인 페어를 교환할 수 없습니다. 다른 선택을 시도해보세요.", + "buttons": { + "cancel": "취소" + } + } + } +} diff --git a/packages/checkout/widgets-lib/src/locales/zh.json b/packages/checkout/widgets-lib/src/locales/zh.json new file mode 100644 index 0000000000..5059a7f576 --- /dev/null +++ b/packages/checkout/widgets-lib/src/locales/zh.json @@ -0,0 +1,511 @@ +{ + "views": { + "CONNECT_WALLET": { + "body": { + "heading": "连接钱包", + "content": "您需要连接或创建数字钱包以购买、出售、交易和存储您的硬币和收藏品。" + } + }, + "CONNECT_SUCCESS": { + "status": "连接安全", + "action": "继续" + }, + "READY_TO_CONNECT": { + "header": { + "title": "连接" + }, + "metamask": { + "body": { + "heading": "检查MetaMask的弹窗", + "content": "按照MetaMask弹窗中的提示进行连接" + }, + "footer": { + "buttonText1": "准备好连接", + "buttonText2": "再试一次" + } + }, + "passport": { + "body": { + "heading": "使用Immutable Passport连接", + "content": "按照提示使用Immutable Passport进行连接" + }, + "footer": { + "buttonText1": "继续", + "buttonText2": "再试一次" + } + } + }, + "SWITCH_NETWORK": { + "eth": { + "heading": "要转移您的硬币,您需要切换到Sepolia网络", + "body": "MetaMask将提示您切换网络。需要时可以切回。", + "button": { + "text": "准备切换", + "retryText": "再试一次" + } + }, + "zkEVM": { + "heading": "将要求您切换到Immutable zkEVM网络", + "body": "检查MetaMask的弹窗并选择'批准'以切换。如果这是第一次,MetaMask还会要求您添加网络。", + "button": { + "text": "准备切换", + "retryText": "再试一次" + } + } + }, + "ERROR_VIEW": { + "heading": "出了些问题", + "body": ["您可以再试一次或联系", "支持", "寻求帮助。"], + "actionText": "再试一次" + }, + "SERVICE_UNAVAILABLE_ERROR_VIEW": { + "heading": { + "swap": "您所在的地区无法使用兑换服务" + }, + "body": "很抱歉我们无法在您的地区提供此项服务。" + }, + "LOADING_VIEW": { + "text": "加载中" + }, + "WALLET_BALANCES": { + "header": { + "title": "钱包" + }, + "networkStatus": { + "heading": "网络" + }, + "totalTokenBalance": { + "heading": "硬币", + "totalHeading": "价值" + }, + "tokenBalancesList": { + "noTokensFound": "未发现代币" + }, + "addCoins": "添加硬币" + }, + "SETTINGS": { + "header": { + "title": "设置" + }, + "disconnectButton": { + "label": "断开钱包连接" + } + }, + "COIN_INFO": { + "metamask": { + "heading": "硬币和收藏品是网络原生的", + "body": "您可以切换网络来添加硬币或将它们从一个网络移动到另一个网络" + }, + "passport": { + "heading": "硬币和收藏品是网络原生的", + "body1": "这个网络称为Immutable zkEVM。如果您在Passport中有其他硬币在这里看不到,它们可能在另一个网络上。", + "body2": "欲了解更多信息,请", + "linkText": "访问我们的常见问题" + } + }, + "SWAP": { + "header": { + "title": "兑换硬币" + }, + "content": { + "title": "您想要兑换什么?", + "fiatPricePrefix": "约合美元", + "availableBalancePrefix": "可用余额" + }, + "swapForm": { + "from": { + "label": "从", + "inputPlaceholder": "0", + "selectorTitle": "您想从哪里兑换?" + }, + "to": { + "label": "至", + "inputPlaceholder": "0", + "selectorTitle": "您想兑换到哪里?" + }, + "buttonText": "兑换" + }, + "fees": { + "title": "总费用" + }, + "validation": { + "noAmountInputted": "请输入金额", + "insufficientBalance": "余额不足", + "noFromTokenSelected": "选择一个要兑换的硬币", + "noToTokenSelected": "选择一个要接收的硬币" + }, + "success": { + "text": "成功", + "actionText": "继续" + }, + "failed": { + "text": "交易被拒绝", + "actionText": "再试一次" + }, + "rejected": { + "text": "价格飙升", + "actionText": "审查并重试" + }, + "IN_PROGRESS": { + "loading": { + "text": "交换进行中" + } + } + }, + "APPROVE_ERC20": { + "approveSwap": { + "content": { + "heading": "现在您只需要确认交易", + "body": "按照钱包中的提示操作。" + }, + "footer": { + "buttonText": "好的", + "retryText": "再试一次" + } + }, + "approveSpending": { + "content": { + "metamask": { + "heading": "您将被要求为这笔交易设置支出上限", + "body": "至少输入{{amount}}用于本次及未来交易,然后按照提示操作。" + }, + "passport": { + "heading": "您将被要求批准这笔交易的支出上限", + "body": "按照钱包中的提示批准支出上限。" + } + }, + "footer": { + "buttonText": "明白", + "retryText": "再试一次" + }, + "loading": { + "text": "批准支出上限" + } + } + }, + "ONRAMP": { + "header": { + "title": "添加硬币" + }, + "initialLoadingText": "带您前往Transak", + "IN_PROGRESS_LOADING": { + "loading": { + "text": "Transak正在处理您的订单" + } + }, + "IN_PROGRESS": { + "content": { + "heading": "订单进行中", + "body1": "当完成时,您将从Transak收到一封电子邮件。这可能需要长达3分钟的时间。", + "body2": "您可以关闭这个窗口,一旦交易完成,将会反映在您的钱包中。" + } + }, + "SUCCESS": { + "text": "硬币正在途中", + "actionText": "完成" + }, + "FAIL": { + "text": "交易失败", + "actionText": "再试一次" + } + }, + "TOP_UP_VIEW": { + "header": { + "title": "您想如何添加硬币?" + }, + "topUpOptions": { + "onramp": { + "heading": "用卡购买", + "caption": "支持Google pay与Apple pay。最低5美元。", + "subcaption": "费用", + "disabledCaption": "" + }, + "swap": { + "heading": "兑换我的硬币", + "caption": "使用我在同一网络上的硬币", + "subcaption": "费用", + "disabledCaption": "您所在的区域不可用" + }, + "bridge": { + "heading": "移动我的硬币", + "caption": "从我在不同网络上的硬币中", + "subcaption": "费用 ", + "disabledCaption": "" + } + } + }, + "FUND_WITH_SMART_CHECKOUT": { + "loading": { + "checkingBalances": "正在计算数字" + }, + "currency": { + "usdEstimate": "≈ 美元 $", + "fees": "费用" + }, + "fundingRouteDrawer": { + "header": "可用余额" + }, + "fundingRouteSelect": { + "heading": "用您的支付", + "noRoutesAvailable": "硬币余额不足。请改用卡继续操作。", + "continue": "继续", + "payWithCardInstead": "不用了,我要用卡支付", + "payWithCard": "用卡支付" + } + }, + "PAYMENT_METHODS": { + "header": { + "heading": "您希望如何支付?" + }, + "options": { + "CRYPTO": { + "heading": "硬币", + "caption": "使用您钱包中的硬币余额", + "disabledCaption": "我们看不到您余额中有足够多的硬币" + }, + "FIAT": { + "heading": "卡", + "caption": "Transak也支持使用GooglePay", + "disabledCaption": null + } + }, + "insufficientCoinsBanner": { + "caption": "硬币余额不足。请继续用卡支付。" + }, + "loading": { + "ready": "准备购买", + "confirm": "在您的钱包中确认", + "processing": "正在处理购买" + } + }, + "PAY_WITH_COINS": { + "header": { + "heading": "用您的硬币支付", + "caption": "使用您钱包中的硬币余额" + }, + "button": { + "buyNow": "立即购买" + } + }, + "PAY_WITH_CARD": { + "screenTitle": "用卡支付", + "loading": "带您前往Transak" + }, + "SALE_FAIL": { + "errors": { + "TRANSACTION_FAILED": { + "description": "交易失败", + "primaryAction": "再试一次", + "secondaryAction": "查看详情" + }, + "SERVICE_BREAKDOWN": { + "description": "抱歉,我们现在无法处理您的付款。请几分钟后再试。", + "secondaryAction": "关闭" + }, + "TRANSAK_FAILED": { + "description": "抱歉,出了点问题。请再试一次。", + "primaryAction": "再试一次", + "secondaryAction": "关闭" + }, + "WALLET_FAILED": { + "description": "抱歉,我们现在无法处理。请返回。", + "primaryAction": "返回", + "secondaryAction": "关闭" + }, + "WALLET_REJECTED_NO_FUNDS": { + "description": "抱歉,出了点问题。请再试一次。", + "primaryAction": "返回", + "secondaryAction": "关闭" + }, + "WALLET_REJECTED": { + "description": "您需要在钱包中批准交易才能继续。", + "primaryAction": "再试一次", + "secondaryAction": "取消" + }, + "SMART_CHECKOUT_ERROR": { + "description": "无法检查您的钱包余额。请再试一次。", + "primaryAction": "再试一次", + "secondaryAction": "取消" + }, + "SMART_CHECKOUT_EXECUTE_ERROR": { + "description": "抱歉,转移资金时出错。请再试一次。", + "primaryAction": "再试一次", + "secondaryAction": "取消" + }, + "DEFAULT": { + "description": "抱歉,出了点问题。请再试一次。", + "primaryAction": "再试一次", + "secondaryAction": "关闭" + } + } + }, + "SALE_SUCCESS": { + "text": "订单已完成", + "actionText": "继续" + }, + "WALLET_NETWORK_SELECTION": { + "layoutHeading": "转移资金", + "heading": "您想在哪两个地方之间转移资金?", + "fromFormInput": { + "heading": "从", + "selectDefaultText": "选择钱包和网络", + "walletSelectorHeading": "来自钱包", + "networkSelectorHeading": "来自网络" + }, + "toFormInput": { + "heading": "至", + "selectDefaultText": "选择钱包和网络", + "walletSelectorHeading": "至钱包" + }, + "submitButton": { + "text": "下一步" + } + }, + "BRIDGE_FORM": { + "header": { + "title": "转移硬币" + }, + "fees": { + "title": "燃气费", + "fiatPricePrefix": "~ 美元 $" + }, + "content": { + "title": "您想要转移多少金额?", + "fiatPricePrefix": "约美元", + "availableBalancePrefix": "可用余额" + }, + "bridgeForm": { + "from": { + "inputPlaceholder": "0", + "selectorTitle": "您想要转移什么?" + }, + "buttonText": "审阅" + }, + "validation": { + "noAmountInputted": "请输入金额", + "insufficientBalance": "余额不足", + "noTokenSelected": "选择一个要转移的硬币" + } + }, + "BRIDGE_REVIEW": { + "layoutHeading": "转移资金", + "heading": "这样看起来怎么样?", + "fromLabel": { + "amountHeading": "正在转移", + "heading": "从" + }, + "toLabel": { + "heading": "至" + }, + "fees": { + "heading": "燃气费" + }, + "submitButton": { + "buttonText": "确认转移" + }, + "fiatPricePrefix": "~ 美元 $" + }, + "BRIDGE_FAILURE": { + "statusText": "交易失败", + "actionText": "审查并重试" + }, + "APPROVE_TRANSACTION": { + "content": { + "heading": "在您的钱包中批准交易", + "body": "按照钱包弹出窗口中的提示进行确认。" + }, + "footer": { + "buttonText": "好的", + "retryText": "再试一次" + }, + "loadingView": { + "text": "开始转移" + } + }, + "IN_PROGRESS": { + "heading": "转移进行中", + "body1": "不到3分钟您的${symbol}就会着陆到zkEVM。", + "body2": "您可以关闭这个窗口,一旦交易完成,将会反映在您的钱包中。" + } + }, + "footers": { + "quickswapFooter": { + "disclaimerText": "Quickswap是第三方应用。Immutable不构建、拥有、操作或部署Quickswap。更多信息请参阅Quickswap的网站。" + } + }, + "wallets": { + "passport": { + "heading": "Immutable Passport", + "accentText": "推荐", + "description": "数字钱包和身份" + }, + "metamask": { + "heading": "MetaMask", + "description": "用于访问区块链应用程序和web3的数字钱包" + } + }, + "drawers": { + "feesBreakdown": { + "heading": "费用分解", + "total": "费用总计", + "fees": { + "gas": { + "label": "燃气费" + } + } + }, + "transactionFailed": { + "content": { + "heading1": "在继续前我们需要您在钱包中确认", + "heading2": "钱包确认", + "body1": "当MetaMask弹出时,请确保", + "body2": "签署交易" + }, + "buttons": { + "retry": "明白了", + "cancel": "关闭" + } + }, + "coinSelector": { + "option": { + "fiatPricePrefix": "约美元 $" + }, + "noCoins": "您的钱包中没有可用的硬币。" + }, + "notEnoughGas": { + "content": { + "heading": "Balance too low", + "body": "You're ETH balance is too low to cover the gas fee on this move. You could transfer more ETH into your wallet using MetaMask directly." + }, + "buttons": { + "adjustAmount": "Adjust amount", + "copyAddress": "Copy wallet address", + "cancel": "Dismiss" + } + }, + "notEnoughImx": { + "content": { + "noImx": { + "heading": "You'll need IMX coins to swap", + "body": "Swap fees are paid in IMX coins, so you'll need to add this before you can swap" + }, + "insufficientImx": { + "heading": "You'll need more IMX coins", + "body": "In order to cover the fees for the amount specified, you'll need to add more IMX coins" + } + }, + "buttons": { + "adjustAmount": "Adjust amount", + "addMoreImx": "Add IMX coins", + "cancel": "Dismiss" + } + }, + "unableToSwap": { + "heading": "Unable to swap this coin", + "body": "This coin pairing isn't available to swap right now. Try another selection.", + "buttons": { + "cancel": "Dismiss" + } + } + } +} diff --git a/packages/checkout/widgets-lib/src/views/error/ErrorView.tsx b/packages/checkout/widgets-lib/src/views/error/ErrorView.tsx index 64d4e11ba8..02290fbb57 100644 --- a/packages/checkout/widgets-lib/src/views/error/ErrorView.tsx +++ b/packages/checkout/widgets-lib/src/views/error/ErrorView.tsx @@ -1,11 +1,10 @@ import { Link } from '@biom3/react'; +import { useTranslation } from 'react-i18next'; import { SimpleLayout } from '../../components/SimpleLayout/SimpleLayout'; import { FooterButton } from '../../components/Footer/FooterButton'; import { HeaderNavigation } from '../../components/Header/HeaderNavigation'; import { SatelliteHero } from '../../components/Hero/SatelliteHero'; import { SimpleTextBody } from '../../components/Body/SimpleTextBody'; -import { text } from '../../resources/text/textConfig'; -import { SharedViews } from '../../context/view-context/ViewContext'; export interface ErrorViewProps { actionText: string; @@ -22,7 +21,7 @@ export function ErrorView({ errorEventActionLoading = false, onCloseClick, }: ErrorViewProps) { - const errorText = text.views[SharedViews.ERROR_VIEW]; + const { t } = useTranslation(); if (typeof errorEventAction === 'function') errorEventAction(); @@ -47,8 +46,8 @@ export function ErrorView({ floatHeader testId="error-view" > - - {errorText.body[0]} + + {t('views.ERROR_VIEW.errorText.body', { returnObjects: true })[0]} {' '} } > - {errorText.body[1]} + {t('views.ERROR_VIEW.errorText.body', { returnObjects: true })[1]} {' '} - {errorText.body[2]} + {t('views.ERROR_VIEW.errorText.body', { returnObjects: true })[2]} ); diff --git a/packages/checkout/widgets-lib/src/views/top-up/TopUpView.tsx b/packages/checkout/widgets-lib/src/views/top-up/TopUpView.tsx index 629a4aa928..f94baba80c 100644 --- a/packages/checkout/widgets-lib/src/views/top-up/TopUpView.tsx +++ b/packages/checkout/widgets-lib/src/views/top-up/TopUpView.tsx @@ -13,15 +13,14 @@ import { import { DEFAULT_TOKEN_SYMBOLS } from 'context/crypto-fiat-context/CryptoFiatProvider'; import { BridgeWidgetViews } from 'context/view-context/BridgeViewContextTypes'; import { Web3Provider } from '@ethersproject/providers'; +import { useTranslation } from 'react-i18next'; import { FooterLogo } from '../../components/Footer/FooterLogo'; import { HeaderNavigation } from '../../components/Header/HeaderNavigation'; import { SimpleLayout } from '../../components/SimpleLayout/SimpleLayout'; import { - SharedViews, ViewActions, ViewContext, } from '../../context/view-context/ViewContext'; -import { text } from '../../resources/text/textConfig'; import { orchestrationEvents } from '../../lib/orchestrationEvents'; import { SwapWidgetViews } from '../../context/view-context/SwapViewContextTypes'; import { @@ -63,10 +62,11 @@ export function TopUpView({ onCloseButtonClick, onBackButtonClick, }: TopUpViewProps) { + const { t } = useTranslation(); const { userJourney } = analytics; - const { header, topUpOptions } = text.views[SharedViews.TOP_UP_VIEW]; - const { onramp, swap, bridge } = topUpOptions; + // const { header, topUpOptions } = text.views[SharedViews.TOP_UP_VIEW]; + // const { onramp, swap, bridge } = topUpOptions; const { viewDispatch } = useContext(ViewContext); @@ -238,26 +238,30 @@ export function TopUpView({ { testId: 'onramp', icon: 'Wallet', - textConfig: onramp, + textConfigKey: 'views.TOP_UP_VIEW.topUpOptions.onramp', onClickEvent: onClickOnRamp, - fee: () => renderFees(`${onramp.subcaption} ≈ ${onRampFeesPercentage}%`), + fee: () => renderFees(`${t('views.TOP_UP_VIEW.topUpOptions.onramp.subcaption')} ≈ ${onRampFeesPercentage}%`), isAvailable: true, isEnabled: showOnrampOption, }, { testId: 'swap', icon: 'Coins', - textConfig: swap, + textConfigKey: 'views.TOP_UP_VIEW.topUpOptions.swap', onClickEvent: onClickSwap, - fee: () => renderFees(`${swap.subcaption} ≈ $${swapFeesInFiat} ${fiatSymbol.toUpperCase()}`), + fee: () => renderFees( + `${t('views.TOP_UP_VIEW.topUpOptions.swap.subcaption')} ≈ $${swapFeesInFiat} ${fiatSymbol.toUpperCase()}`, + ), isAvailable: isSwapAvailable, isEnabled: showSwapOption, }, { testId: 'bridge', icon: 'Minting', - textConfig: bridge, + textConfigKey: 'views.TOP_UP_VIEW.topUpOptions.bridge', onClickEvent: onClickBridge, - fee: () => renderFees(`${bridge.subcaption} ≈ $${bridgeFeesInFiat} ${fiatSymbol.toUpperCase()}`), + fee: () => renderFees( + `${t('views.TOP_UP_VIEW.topUpOptions.bridge.subcaption')} ≈ $${bridgeFeesInFiat} ${fiatSymbol.toUpperCase()}`, + ), isAvailable: true, isEnabled: showBridgeOption && !isPassport, }, @@ -275,17 +279,18 @@ export function TopUpView({ footer={} > - {header.title} + {t('views.TOP_UP_VIEW.header.title')} {topUpFeatures .sort((a, b) => Number(b.isAvailable) - Number(a.isAvailable)) .map((element) => element.isEnabled && ( implements Widget { console.warn('Updating a widget provider through the update() method is not supported yet'); } + if (props.config?.language) { + i18next.changeLanguage(props.config.language).then(() => { + // eslint-disable-next-line no-console + console.log('Language changed:', props.config?.language); + }); + } + this.render(); } diff --git a/packages/checkout/widgets-lib/src/widgets/bridge/BridgeWidget.tsx b/packages/checkout/widgets-lib/src/widgets/bridge/BridgeWidget.tsx index b93fc3b5ba..18a66d6c57 100644 --- a/packages/checkout/widgets-lib/src/widgets/bridge/BridgeWidget.tsx +++ b/packages/checkout/widgets-lib/src/widgets/bridge/BridgeWidget.tsx @@ -28,6 +28,7 @@ import { getL1ChainId, getL2ChainId } from 'lib'; import { Transactions } from 'components/Transactions/Transactions'; import { UserJourney, useAnalytics } from 'context/analytics-provider/SegmentAnalyticsProvider'; import { TopUpView } from 'views/top-up/TopUpView'; +import { useTranslation } from 'react-i18next'; import { ViewActions, ViewContext, @@ -47,7 +48,6 @@ import { BridgeReview } from './views/BridgeReview'; import { MoveInProgress } from './views/MoveInProgress'; import { ApproveTransaction } from './views/ApproveTransaction'; import { ErrorView } from '../../views/error/ErrorView'; -import { text } from '../../resources/text/textConfig'; import { EventTargetContext } from '../../context/event-target-context/EventTargetContext'; import { sendBridgeFailedEvent, sendBridgeWidgetCloseEvent } from './BridgeWidgetEvents'; @@ -64,15 +64,14 @@ export function BridgeWidget({ amount, tokenAddress, }: BridgeWidgetInputs) { + const { t } = useTranslation(); const { environment, isOnRampEnabled, isSwapEnabled, isBridgeEnabled, } = config; - const errorText = text.views[SharedViews.ERROR_VIEW]; const { eventTargetState: { eventTarget } } = useContext(EventTargetContext); - const bridgeFailureText = text.views[BridgeWidgetViews.BRIDGE_FAILURE]; const { page } = useAnalytics(); @@ -185,8 +184,8 @@ export function BridgeWidget({ && ( { @@ -219,7 +218,7 @@ export function BridgeWidget({ )} {viewState.view.type === SharedViews.ERROR_VIEW && ( sendBridgeWidgetCloseEvent(eventTarget)} errorEventAction={() => { diff --git a/packages/checkout/widgets-lib/src/widgets/bridge/components/BridgeForm.tsx b/packages/checkout/widgets-lib/src/widgets/bridge/components/BridgeForm.tsx index ebb84405b4..e42dd2403c 100644 --- a/packages/checkout/widgets-lib/src/widgets/bridge/components/BridgeForm.tsx +++ b/packages/checkout/widgets-lib/src/widgets/bridge/components/BridgeForm.tsx @@ -19,6 +19,7 @@ import { BigNumber, utils } from 'ethers'; import { FeesBreakdown } from 'components/FeesBreakdown/FeesBreakdown'; import { BridgeFeeActions } from '@imtbl/bridge-sdk'; import { UserJourney, useAnalytics } from 'context/analytics-provider/SegmentAnalyticsProvider'; +import { useTranslation } from 'react-i18next'; import { amountInputValidation } from '../../../lib/validations/amountInputValidations'; import { BridgeActions, BridgeContext } from '../context/BridgeContext'; import { @@ -27,7 +28,6 @@ import { SharedViews, } from '../../../context/view-context/ViewContext'; import { CryptoFiatActions, CryptoFiatContext } from '../../../context/crypto-fiat-context/CryptoFiatContext'; -import { text } from '../../../resources/text/textConfig'; import { TextInputForm } from '../../../components/FormComponents/TextInputForm/TextInputForm'; import { calculateCryptoToFiat, formatZeroAmount, isNativeToken, tokenValueFormat, @@ -65,6 +65,7 @@ interface BridgeFormProps { } export function BridgeForm(props: BridgeFormProps) { + const { t } = useTranslation(); const { bridgeDispatch, bridgeState: { @@ -87,11 +88,6 @@ export function BridgeForm(props: BridgeFormProps) { defaultTokenAddress, isTokenBalancesLoading, } = props; - const { - fees, - content, - bridgeForm, - } = text.views[BridgeWidgetViews.BRIDGE_FORM]; const { track } = useAnalytics(); @@ -105,7 +101,7 @@ export function BridgeForm(props: BridgeFormProps) { const [loading, setLoading] = useState(false); const hasSetDefaultState = useRef(false); const tokenBalanceSubtext = formToken - ? `${content.availableBalancePrefix} ${tokenValueFormat(formToken?.formattedBalance)}` + ? `${t('views.BRIDGE_FORM.content.availableBalancePrefix')} ${tokenValueFormat(formToken?.formattedBalance)}` : ''; // Fee estimates & transactions @@ -128,7 +124,7 @@ export function BridgeForm(props: BridgeFormProps) { return `${symbol.toLowerCase()}-${address.toLowerCase()}`; }, []); - const gasFiatAmount = `${fees.fiatPricePrefix} ${gasFeeFiatValue}`; + const gasFiatAmount = `${t('views.BRIDGE_FORM.fees.fiatPricePrefix')} ${gasFeeFiatValue}`; useEffect(() => { if (tokenBalances.length === 0) return; @@ -137,19 +133,19 @@ export function BridgeForm(props: BridgeFormProps) { const options = tokenBalances .filter((tokenBalance) => tokenBalance.balance.gt(0)) .map( - (t) => ({ - id: formatTokenOptionsId(t.token.symbol, t.token.address), - name: t.token.name, - symbol: t.token.symbol, - icon: t.token.icon, + (tokenBalance) => ({ + id: formatTokenOptionsId(tokenBalance.token.symbol, tokenBalance.token.address), + name: tokenBalance.token.name, + symbol: tokenBalance.token.symbol, + icon: tokenBalance.token.icon, balance: { formattedFiatAmount: cryptoFiatState.conversions.size === 0 ? formatZeroAmount('') : calculateCryptoToFiat( - t.formattedBalance, - t.token.symbol, + tokenBalance.formattedBalance, + tokenBalance.token.symbol, cryptoFiatState.conversions, ), - formattedAmount: tokenValueFormat(t.formattedBalance), + formattedAmount: tokenValueFormat(tokenBalance.formattedBalance), }, } as CoinSelectorOptionProps), ); @@ -329,7 +325,9 @@ export function BridgeForm(props: BridgeFormProps) { }; const handleSelectTokenChange = (value: OptionKey) => { - const selected = tokenBalances.find((t) => value === formatTokenOptionsId(t.token.symbol, t.token.address)); + const selected = tokenBalances.find((tokenBalance) => ( + value === formatTokenOptionsId(tokenBalance.token.symbol, tokenBalance.token.address) + )); if (!selected) return; setFormToken(selected); @@ -439,7 +437,7 @@ export function BridgeForm(props: BridgeFormProps) { weight="regular" sx={{ paddingBottom: 'base.spacing.x4' }} > - {content.title} + {t('views.BRIDGE_FORM.content.title')} {(!defaultTokenAddress || !isTokenBalancesLoading) && ( @@ -447,7 +445,7 @@ export function BridgeForm(props: BridgeFormProps) { testId="bridge-token" options={tokensOptions} optionsLoading={isTokenBalancesLoading} - coinSelectorHeading={bridgeForm.from.selectorTitle} + coinSelectorHeading={t('views.BRIDGE_FORM.bridgeForm.from.selectorTitle')} selectedOption={selectedOption} subtext={tokenBalanceSubtext} textAlign="left" @@ -458,8 +456,8 @@ export function BridgeForm(props: BridgeFormProps) { handleBridgeAmountChange(value)} @@ -481,13 +479,13 @@ export function BridgeForm(props: BridgeFormProps) { > - {fees.title} + {t('views.BRIDGE_FORM.fees.title')} @@ -501,7 +499,7 @@ export function BridgeForm(props: BridgeFormProps) { tokenSymbol={estimates?.token?.symbol ?? ''} fees={[ { - label: text.drawers.feesBreakdown.fees.gas.label, + label: t('views.drawers.feesBreakdown.fees.gas.label'), fiatAmount: gasFiatAmount, amount: gasFee, }, @@ -519,7 +517,7 @@ export function BridgeForm(props: BridgeFormProps) { > {loading ? ( - ) : bridgeForm.buttonText} + ) : t('views.BRIDGE_FORM.bridgeForm.buttonText')} - {heading} + {t('views.BRIDGE_REVIEW.heading')} {/* From review */} @@ -232,13 +230,13 @@ export function BridgeReviewSummary() { sx={topMenuItemStyles} > - {fromLabel.amountHeading} + {t('views.BRIDGE_REVIEW.fromLabel.amountHeading')} } price={displayAmount ?? '-'} - fiatAmount={`${fiatPricePrefix}${fromFiatAmount}`} + fiatAmount={`${t('views.BRIDGE_REVIEW.fiatPricePrefix')}${fromFiatAmount}`} /> )} - {fromLabel.heading} + {t('views.BRIDGE_REVIEW.fromLabel.heading')} {' '} )} - {toLabel.heading} + {t('views.BRIDGE_REVIEW.toLabel.heading')} {' '} - {fees.heading} + {t('views.BRIDGE_REVIEW.fees.heading')} @@ -347,17 +345,17 @@ export function BridgeReviewSummary() { > {loading ? ( - ) : submitButton.buttonText} + ) : t('views.BRIDGE_REVIEW.submitButton.buttonText')} - {heading} + {t('views.WALLET_NETWORK_SELECTION.heading')} - {fromFormInput.heading} + + {t('views.WALLET_NETWORK_SELECTION.fromFormInput.heading')} + {/* Show the from wallet target (select box) if no selections have been made yet */} - {toFormInput.heading} + + {t('views.WALLET_NETWORK_SELECTION.toFormInput.heading')} + { setFromNetworkDrawerOpen(false); @@ -501,7 +503,7 @@ export function WalletAndNetworkSelector() { size="large" onClick={handleSubmitDetails} > - {submitButton.text} + {t('views.WALLET_NETWORK_SELECTION.submitButton.text')} diff --git a/packages/checkout/widgets-lib/src/widgets/bridge/components/WalletItem.tsx b/packages/checkout/widgets-lib/src/widgets/bridge/components/WalletItem.tsx index 280929ec06..e5beb5aae2 100644 --- a/packages/checkout/widgets-lib/src/widgets/bridge/components/WalletItem.tsx +++ b/packages/checkout/widgets-lib/src/widgets/bridge/components/WalletItem.tsx @@ -1,7 +1,7 @@ import { WalletProviderName } from '@imtbl/checkout-sdk'; import { MenuItem } from '@biom3/react'; import { useState } from 'react'; -import { text } from '../../../resources/text/textConfig'; +import { useTranslation } from 'react-i18next'; import { walletItemLogoStyles } from './WalletItemStyles'; export interface WalletItemProps { @@ -16,7 +16,7 @@ export function WalletItem({ onWalletClick, loading, }: WalletItemProps) { - const { wallets } = text; + const { t } = useTranslation(); const [showLoadingIcon, setShowLoadingIcon] = useState(false); const logo = { @@ -45,7 +45,7 @@ export function WalletItem({ sx={walletItemLogoStyles} /> - {wallets[walletProviderName].heading} + {t(`wallets.${walletProviderName}.heading`)} {showLoadingIcon && ()} diff --git a/packages/checkout/widgets-lib/src/widgets/bridge/views/ApproveTransaction.tsx b/packages/checkout/widgets-lib/src/widgets/bridge/views/ApproveTransaction.tsx index cf96be170b..f376262ae5 100644 --- a/packages/checkout/widgets-lib/src/widgets/bridge/views/ApproveTransaction.tsx +++ b/packages/checkout/widgets-lib/src/widgets/bridge/views/ApproveTransaction.tsx @@ -8,11 +8,11 @@ import { import { CheckoutErrorType } from '@imtbl/checkout-sdk'; import { ApproveBridgeResponse, BridgeTxResponse } from '@imtbl/bridge-sdk'; import { UserJourney, useAnalytics } from 'context/analytics-provider/SegmentAnalyticsProvider'; +import { useTranslation } from 'react-i18next'; import { SimpleLayout } from '../../../components/SimpleLayout/SimpleLayout'; import { HeaderNavigation } from '../../../components/Header/HeaderNavigation'; import { sendBridgeWidgetCloseEvent } from '../BridgeWidgetEvents'; import { FooterButton } from '../../../components/Footer/FooterButton'; -import { text } from '../../../resources/text/textConfig'; import { SimpleTextBody } from '../../../components/Body/SimpleTextBody'; import { SharedViews, ViewActions, ViewContext } from '../../../context/view-context/ViewContext'; import { LoadingView } from '../../../views/loading/LoadingView'; @@ -28,13 +28,13 @@ export interface ApproveTransactionProps { } export function ApproveTransaction({ approveTransaction, transaction }: ApproveTransactionProps) { + const { t } = useTranslation(); const { bridgeState } = useContext(BridgeContext); const { checkout, from, } = bridgeState; const { viewDispatch } = useContext(ViewContext); - const { loadingView, content, footer } = text.views[BridgeWidgetViews.APPROVE_TRANSACTION]; const { eventTargetState: { eventTarget } } = useContext(EventTargetContext); const { page } = useAnalytics(); @@ -214,7 +214,7 @@ export function ApproveTransaction({ approveTransaction, transaction }: ApproveT return ( <> - {loading && ()} + {loading && ()} {!loading && ( )} > - - {content.body} + + {t('views.APPROVE_TRANSACTION.content.body')} )} diff --git a/packages/checkout/widgets-lib/src/widgets/bridge/views/Bridge.tsx b/packages/checkout/widgets-lib/src/widgets/bridge/views/Bridge.tsx index dff5e32df1..075fc98acc 100644 --- a/packages/checkout/widgets-lib/src/widgets/bridge/views/Bridge.tsx +++ b/packages/checkout/widgets-lib/src/widgets/bridge/views/Bridge.tsx @@ -5,14 +5,13 @@ import { useState, } from 'react'; import { TokenFilterTypes } from '@imtbl/checkout-sdk'; -import { BridgeWidgetViews } from 'context/view-context/BridgeViewContextTypes'; import { UserJourney, useAnalytics } from 'context/analytics-provider/SegmentAnalyticsProvider'; +import { useTranslation } from 'react-i18next'; import { sendBridgeWidgetCloseEvent } from '../BridgeWidgetEvents'; import { SimpleLayout } from '../../../components/SimpleLayout/SimpleLayout'; import { HeaderNavigation } from '../../../components/Header/HeaderNavigation'; import { FooterLogo } from '../../../components/Footer/FooterLogo'; import { BridgeForm } from '../components/BridgeForm'; -import { text } from '../../../resources/text/textConfig'; import { BridgeActions, BridgeContext } from '../context/BridgeContext'; import { useInterval } from '../../../lib/hooks/useInterval'; import { EventTargetContext } from '../../../context/event-target-context/EventTargetContext'; @@ -26,7 +25,7 @@ export interface BridgeProps { } export function Bridge({ amount, tokenAddress }: BridgeProps) { - const { header } = text.views[BridgeWidgetViews.BRIDGE_FORM]; + const { t } = useTranslation(); const { bridgeState, bridgeDispatch } = useContext(BridgeContext); const { checkout, from } = bridgeState; const { eventTargetState: { eventTarget } } = useContext(EventTargetContext); @@ -102,7 +101,7 @@ export function Bridge({ amount, tokenAddress }: BridgeProps) { header={( sendBridgeWidgetCloseEvent(eventTarget)} /> )} diff --git a/packages/checkout/widgets-lib/src/widgets/bridge/views/BridgeReview.tsx b/packages/checkout/widgets-lib/src/widgets/bridge/views/BridgeReview.tsx index 4184bd5145..c5d61f569d 100644 --- a/packages/checkout/widgets-lib/src/widgets/bridge/views/BridgeReview.tsx +++ b/packages/checkout/widgets-lib/src/widgets/bridge/views/BridgeReview.tsx @@ -3,15 +3,14 @@ import { SimpleLayout } from 'components/SimpleLayout/SimpleLayout'; import { FooterLogo } from 'components/Footer/FooterLogo'; import { useContext, useEffect } from 'react'; import { EventTargetContext } from 'context/event-target-context/EventTargetContext'; -import { text } from 'resources/text/textConfig'; -import { BridgeWidgetViews } from 'context/view-context/BridgeViewContextTypes'; import { UserJourney, useAnalytics } from 'context/analytics-provider/SegmentAnalyticsProvider'; +import { useTranslation } from 'react-i18next'; import { sendBridgeWidgetCloseEvent } from '../BridgeWidgetEvents'; import { BridgeReviewSummary } from '../components/BridgeReviewSummary'; export function BridgeReview() { + const { t } = useTranslation(); const { eventTargetState: { eventTarget } } = useContext(EventTargetContext); - const { layoutHeading } = text.views[BridgeWidgetViews.BRIDGE_REVIEW]; const { page } = useAnalytics(); @@ -28,7 +27,7 @@ export function BridgeReview() { header={( sendBridgeWidgetCloseEvent(eventTarget)} /> )} diff --git a/packages/checkout/widgets-lib/src/widgets/bridge/views/MoveInProgress.tsx b/packages/checkout/widgets-lib/src/widgets/bridge/views/MoveInProgress.tsx index 8eaeb2f77c..8deb78c023 100644 --- a/packages/checkout/widgets-lib/src/widgets/bridge/views/MoveInProgress.tsx +++ b/packages/checkout/widgets-lib/src/widgets/bridge/views/MoveInProgress.tsx @@ -1,11 +1,10 @@ import { useContext, useEffect } from 'react'; -import { BridgeWidgetViews } from 'context/view-context/BridgeViewContextTypes'; import { UserJourney, useAnalytics } from 'context/analytics-provider/SegmentAnalyticsProvider'; +import { useTranslation } from 'react-i18next'; import { SimpleTextBody } from '../../../components/Body/SimpleTextBody'; import { HeaderNavigation } from '../../../components/Header/HeaderNavigation'; import { RocketHero } from '../../../components/Hero/RocketHero'; import { SimpleLayout } from '../../../components/SimpleLayout/SimpleLayout'; -import { text } from '../../../resources/text/textConfig'; import { sendBridgeTransactionSentEvent, sendBridgeWidgetCloseEvent } from '../BridgeWidgetEvents'; import { FooterLogo } from '../../../components/Footer/FooterLogo'; import { EventTargetContext } from '../../../context/event-target-context/EventTargetContext'; @@ -16,10 +15,10 @@ export interface MoveInProgressProps { } export function MoveInProgress({ transactionHash }: MoveInProgressProps) { + const { t } = useTranslation(); const { eventTargetState: { eventTarget } } = useContext(EventTargetContext); const { page } = useAnalytics(); - const { heading, body2 } = text.views[BridgeWidgetViews.IN_PROGRESS]; const { bridgeState: { checkout }, } = useContext(BridgeContext); @@ -50,8 +49,8 @@ export function MoveInProgress({ transactionHash }: MoveInProgressProps) { heroContent={} floatHeader > - - {body2} + + {t('views.IN_PROGRESS.body2')} ); diff --git a/packages/checkout/widgets-lib/src/widgets/bridge/views/WalletNetworkSelectionView.tsx b/packages/checkout/widgets-lib/src/widgets/bridge/views/WalletNetworkSelectionView.tsx index 175ec9740c..34649bf129 100644 --- a/packages/checkout/widgets-lib/src/widgets/bridge/views/WalletNetworkSelectionView.tsx +++ b/packages/checkout/widgets-lib/src/widgets/bridge/views/WalletNetworkSelectionView.tsx @@ -3,20 +3,20 @@ import { SimpleLayout } from 'components/SimpleLayout/SimpleLayout'; import { FooterLogo } from 'components/Footer/FooterLogo'; import { useContext, useEffect } from 'react'; import { EventTargetContext } from 'context/event-target-context/EventTargetContext'; -import { text } from 'resources/text/textConfig'; import { BridgeWidgetViews } from 'context/view-context/BridgeViewContextTypes'; import { ButtonNavigationStyles } from 'components/Header/HeaderStyles'; import { ButtCon } from '@biom3/react'; import { ViewActions, ViewContext } from 'context/view-context/ViewContext'; import { UserJourney, useAnalytics } from 'context/analytics-provider/SegmentAnalyticsProvider'; +import { useTranslation } from 'react-i18next'; import { sendBridgeWidgetCloseEvent } from '../BridgeWidgetEvents'; import { WalletAndNetworkSelector } from '../components/WalletAndNetworkSelector'; export function WalletNetworkSelectionView() { + const { t } = useTranslation(); const { viewDispatch } = useContext(ViewContext); const { eventTargetState: { eventTarget } } = useContext(EventTargetContext); - const { layoutHeading } = text.views[BridgeWidgetViews.WALLET_NETWORK_SELECTION]; const { page } = useAnalytics(); @@ -32,7 +32,7 @@ export function WalletNetworkSelectionView() { testId="bridge-view" header={( sendBridgeWidgetCloseEvent(eventTarget)} rightActions={( sendCloseEvent()} onRenderEvent={handleConnectSuccess} statusType={StatusType.SUCCESS} diff --git a/packages/checkout/widgets-lib/src/widgets/connect/components/WalletItem.tsx b/packages/checkout/widgets-lib/src/widgets/connect/components/WalletItem.tsx index 46eb6a76bb..2af0e927b0 100644 --- a/packages/checkout/widgets-lib/src/widgets/connect/components/WalletItem.tsx +++ b/packages/checkout/widgets-lib/src/widgets/connect/components/WalletItem.tsx @@ -1,59 +1,49 @@ import { WalletProviderName, WalletInfo } from '@imtbl/checkout-sdk'; import { Box, MenuItem } from '@biom3/react'; -import { text } from '../../../resources/text/textConfig'; +import { useTranslation } from 'react-i18next'; export interface WalletProps { onWalletClick: (walletProviderName: WalletProviderName) => void; wallet: WalletInfo; } export function WalletItem(props: WalletProps) { + const { t } = useTranslation(); const { wallet, onWalletClick } = props; - const { wallets } = text; - - const walletText = wallets[wallet.walletProviderName]; const logo = { [WalletProviderName.PASSPORT]: 'PassportSymbolOutlined', [WalletProviderName.METAMASK]: 'MetaMaskSymbol', }; return ( - // TODO: Fragments should contain more than one child - otherwise, there’s no need for a Fragment at all. - // Consider checking !walletText and rendering a callback component instead, then it would make sense - // to use a Fragment. - // eslint-disable-next-line react/jsx-no-useless-fragment - <> - {walletText && ( - onWalletClick(wallet.walletProviderName)} - sx={{ marginBottom: 'base.spacing.x1' }} - > - - - {wallets[wallet.walletProviderName].heading} - - - - {wallet.walletProviderName === WalletProviderName.PASSPORT ? ( - } sx={{ c: 'base.gradient.1' }}> - {wallets[wallet.walletProviderName].accentText} - - ) : null} - {' '} - {wallets[wallet.walletProviderName].description} - - - )} - + onWalletClick(wallet.walletProviderName)} + sx={{ marginBottom: 'base.spacing.x1' }} + > + + + {t(`wallets.${wallet.walletProviderName}.heading`)} + + + + {wallet.walletProviderName === WalletProviderName.PASSPORT ? ( + } sx={{ c: 'base.gradient.1' }}> + {t(`wallets.${wallet.walletProviderName}.accentText`)} + + ) : null} + {' '} + {t(`wallets.${wallet.walletProviderName}.description`)} + + ); } diff --git a/packages/checkout/widgets-lib/src/widgets/connect/views/ConnectWallet.tsx b/packages/checkout/widgets-lib/src/widgets/connect/views/ConnectWallet.tsx index b2fb51db32..9a82cc2394 100644 --- a/packages/checkout/widgets-lib/src/widgets/connect/views/ConnectWallet.tsx +++ b/packages/checkout/widgets-lib/src/widgets/connect/views/ConnectWallet.tsx @@ -1,16 +1,15 @@ import { useContext, useEffect } from 'react'; import { Body, Box, Heading } from '@biom3/react'; +import { useTranslation } from 'react-i18next'; import { FooterLogo } from '../../../components/Footer/FooterLogo'; import { HeaderNavigation } from '../../../components/Header/HeaderNavigation'; import { SimpleLayout } from '../../../components/SimpleLayout/SimpleLayout'; -import { ConnectWidgetViews } from '../../../context/view-context/ConnectViewContextTypes'; -import { text } from '../../../resources/text/textConfig'; import { WalletList } from '../components/WalletList'; import { ConnectContext } from '../context/ConnectContext'; import { UserJourney, useAnalytics } from '../../../context/analytics-provider/SegmentAnalyticsProvider'; export function ConnectWallet() { - const { body } = text.views[ConnectWidgetViews.CONNECT_WALLET]; + const { t } = useTranslation(); const { connectState: { sendCloseEvent }, } = useContext(ConnectContext); @@ -49,7 +48,7 @@ export function ConnectWallet() { paddingX: 'base.spacing.x4', }} > - {body.heading} + {t('views.CONNECT_WALLET.body.heading')} - {body.content} + {t('views.CONNECT_WALLET.body.content')} diff --git a/packages/checkout/widgets-lib/src/widgets/connect/views/ReadyToConnect.tsx b/packages/checkout/widgets-lib/src/widgets/connect/views/ReadyToConnect.tsx index 4434d71819..b900344376 100644 --- a/packages/checkout/widgets-lib/src/widgets/connect/views/ReadyToConnect.tsx +++ b/packages/checkout/widgets-lib/src/widgets/connect/views/ReadyToConnect.tsx @@ -7,6 +7,7 @@ import { useContext, useState, useCallback, useMemo, useEffect, } from 'react'; import { addProviderListenersForWidgetRoot } from 'lib'; +import { useTranslation } from 'react-i18next'; import { SimpleTextBody } from '../../../components/Body/SimpleTextBody'; import { FooterButton } from '../../../components/Footer/FooterButton'; import { HeaderNavigation } from '../../../components/Header/HeaderNavigation'; @@ -14,7 +15,6 @@ import { MetamaskConnectHero } from '../../../components/Hero/MetamaskConnectHer import { PassportConnectHero } from '../../../components/Hero/PassportConnectHero'; import { SimpleLayout } from '../../../components/SimpleLayout/SimpleLayout'; import { ConnectWidgetViews } from '../../../context/view-context/ConnectViewContextTypes'; -import { text } from '../../../resources/text/textConfig'; import { ConnectContext, ConnectActions } from '../context/ConnectContext'; import { ViewContext, ViewActions } from '../../../context/view-context/ViewContext'; import { isMetaMaskProvider, isPassportProvider } from '../../../lib/providerUtils'; @@ -26,6 +26,7 @@ export interface ReadyToConnectProps { allowedChains: ChainId[]; } export function ReadyToConnect({ targetChainId, allowedChains }: ReadyToConnectProps) { + const { t } = useTranslation(); const { connectState: { checkout, provider, sendCloseEvent }, connectDispatch, @@ -65,15 +66,8 @@ export function ReadyToConnect({ targetChainId, allowedChains }: ReadyToConnectP } }, [isPassport, isMetaMask]); - const textView = () => { - if (isPassport) { - return text.views[ConnectWidgetViews.READY_TO_CONNECT].passport; - } - return text.views[ConnectWidgetViews.READY_TO_CONNECT].metamask; - }; - const { header } = text.views[ConnectWidgetViews.READY_TO_CONNECT]; - const { body, footer } = textView(); - const [footerButtonText, setFooterButtonText] = useState(footer.buttonText1); + const textView = () => `views.READY_TO_CONNECT.${isPassport ? 'passport' : 'metamask'}`; + const [footerButtonTextKey, setFooterButtonTextKey] = useState(`${textView()}.footer.buttonText1`); const [loading, setLoading] = useState(false); const heroContent = () => { if (isPassport) { @@ -149,9 +143,9 @@ export function ReadyToConnect({ targetChainId, allowedChains }: ReadyToConnectP handleConnectViewUpdate(provider); } catch (err: any) { setLoading(false); - setFooterButtonText(footer.buttonText2); + setFooterButtonTextKey(`${textView()}.footer.buttonText2`); } - }, [checkout, provider, connectDispatch, viewDispatch, footer.buttonText2, identify]); + }, [checkout, provider, connectDispatch, viewDispatch, identify]); return ( @@ -169,12 +163,12 @@ export function ReadyToConnect({ targetChainId, allowedChains }: ReadyToConnectP footer={( )} > - {body.content} + {t(`${textView()}.body.content`)} ); } diff --git a/packages/checkout/widgets-lib/src/widgets/connect/views/SwitchNetworkEth.tsx b/packages/checkout/widgets-lib/src/widgets/connect/views/SwitchNetworkEth.tsx index 48f505fd10..f8dfb35772 100644 --- a/packages/checkout/widgets-lib/src/widgets/connect/views/SwitchNetworkEth.tsx +++ b/packages/checkout/widgets-lib/src/widgets/connect/views/SwitchNetworkEth.tsx @@ -1,13 +1,13 @@ import { useCallback, useContext, useEffect, useState, } from 'react'; +import { useTranslation } from 'react-i18next'; import { SimpleTextBody } from '../../../components/Body/SimpleTextBody'; import { FooterButton } from '../../../components/Footer/FooterButton'; import { HeaderNavigation } from '../../../components/Header/HeaderNavigation'; import { EthereumPlanetHero } from '../../../components/Hero/EthereumPlanetHero'; import { SimpleLayout } from '../../../components/SimpleLayout/SimpleLayout'; import { ConnectWidgetViews } from '../../../context/view-context/ConnectViewContextTypes'; -import { text } from '../../../resources/text/textConfig'; import { ConnectActions, ConnectContext } from '../context/ConnectContext'; import { getL1ChainId } from '../../../lib/networkUtils'; import { @@ -17,12 +17,11 @@ import { import { UserJourney, useAnalytics } from '../../../context/analytics-provider/SegmentAnalyticsProvider'; export function SwitchNetworkEth() { + const { t } = useTranslation(); const { viewDispatch } = useContext(ViewContext); const { connectDispatch, connectState } = useContext(ConnectContext); const { checkout, provider, sendCloseEvent } = connectState; - const { heading, body, button } = text.views[ConnectWidgetViews.SWITCH_NETWORK].eth; - - const [buttonText, setButtonText] = useState(button.text); + const [buttonTextKey, setButtonTextKey] = useState('views.SWITCH_NETWORK.eth.button.text'); const { page, track } = useAnalytics(); @@ -64,7 +63,7 @@ export function SwitchNetworkEth() { }, }); } catch (err: any) { - setButtonText(button.retryText); + setButtonTextKey('views.SWITCH_NETWORK.eth.button.retryText'); } }, [provider, checkout, track]); @@ -79,14 +78,18 @@ export function SwitchNetworkEth() { )} footer={( )} heroContent={} floatHeader > - {body} + + {t('views.SWITCH_NETWORK.eth.body')} + ); } diff --git a/packages/checkout/widgets-lib/src/widgets/connect/views/SwitchNetworkZkEVM.tsx b/packages/checkout/widgets-lib/src/widgets/connect/views/SwitchNetworkZkEVM.tsx index 4ddbc40b30..5cb313100f 100644 --- a/packages/checkout/widgets-lib/src/widgets/connect/views/SwitchNetworkZkEVM.tsx +++ b/packages/checkout/widgets-lib/src/widgets/connect/views/SwitchNetworkZkEVM.tsx @@ -1,12 +1,12 @@ import { useCallback, useContext, useEffect, useState, } from 'react'; +import { useTranslation } from 'react-i18next'; import { SimpleTextBody } from '../../../components/Body/SimpleTextBody'; import { FooterButton } from '../../../components/Footer/FooterButton'; import { HeaderNavigation } from '../../../components/Header/HeaderNavigation'; import { SimpleLayout } from '../../../components/SimpleLayout/SimpleLayout'; import { ConnectWidgetViews } from '../../../context/view-context/ConnectViewContextTypes'; -import { text } from '../../../resources/text/textConfig'; import { ConnectActions, ConnectContext } from '../context/ConnectContext'; import { ViewContext, ViewActions } from '../../../context/view-context/ViewContext'; import { getL2ChainId } from '../../../lib'; @@ -14,12 +14,11 @@ import { ImmutablePlanetHero } from '../../../components/Hero/ImmutablePlanetHer import { UserJourney, useAnalytics } from '../../../context/analytics-provider/SegmentAnalyticsProvider'; export function SwitchNetworkZkEVM() { + const { t } = useTranslation(); const { viewDispatch } = useContext(ViewContext); const { connectDispatch, connectState } = useContext(ConnectContext); const { checkout, provider, sendCloseEvent } = connectState; - const { heading, body, button } = text.views[ConnectWidgetViews.SWITCH_NETWORK].zkEVM; - - const [buttonText, setButtonText] = useState(button.text); + const [buttonTextKey, setButtonTextKey] = useState('views.SWITCH_NETWORK.zkEVM.button.text'); const { page, track } = useAnalytics(); useEffect(() => { @@ -60,7 +59,7 @@ export function SwitchNetworkZkEVM() { }, }); } catch (err: any) { - setButtonText(button.retryText); + setButtonTextKey('views.SWITCH_NETWORK.zkEVM.button.retryText'); } }, [provider, checkout]); @@ -75,14 +74,18 @@ export function SwitchNetworkZkEVM() { )} footer={( )} heroContent={} floatHeader > - {body} + + {t('views.SWITCH_NETWORK.zkEVM.body')} + ); } diff --git a/packages/checkout/widgets-lib/src/widgets/swap/SwapWidget.tsx b/packages/checkout/widgets-lib/src/widgets/swap/SwapWidget.tsx index 22d685737f..d7e6eb9a01 100644 --- a/packages/checkout/widgets-lib/src/widgets/swap/SwapWidget.tsx +++ b/packages/checkout/widgets-lib/src/widgets/swap/SwapWidget.tsx @@ -11,6 +11,7 @@ import { } from '@imtbl/checkout-sdk'; import { ImmutableConfiguration } from '@imtbl/config'; import { Exchange, ExchangeOverrides } from '@imtbl/dex-sdk'; +import { useTranslation } from 'react-i18next'; import { SwapCoins } from './views/SwapCoins'; import { LoadingView } from '../../views/loading/LoadingView'; import { @@ -36,7 +37,6 @@ import { StrongCheckoutWidgetsConfig } from '../../lib/withDefaultWidgetConfig'; import { DEFAULT_BALANCE_RETRY_POLICY, getL2ChainId } from '../../lib'; import { StatusView } from '../../components/Status/StatusView'; import { StatusType } from '../../components/Status/StatusType'; -import { text } from '../../resources/text/textConfig'; import { ErrorView } from '../../views/error/ErrorView'; import { sendSwapFailedEvent, @@ -62,10 +62,7 @@ export function SwapWidget({ toTokenAddress, config, }: SwapWidgetInputs) { - const { success, failed, rejected } = text.views[SwapWidgetViews.SWAP]; - const loadingText = text.views[SharedViews.LOADING_VIEW].text; - const { actionText } = text.views[SharedViews.ERROR_VIEW]; - + const { t } = useTranslation(); const { eventTargetState: { eventTarget }, } = useContext(EventTargetContext); @@ -210,7 +207,7 @@ export function SwapWidget({ {viewState.view.type === SharedViews.LOADING_VIEW && ( - + )} {viewState.view.type === SwapWidgetViews.SWAP && ( { page({ userJourney: UserJourney.SWAP, @@ -255,8 +252,8 @@ export function SwapWidget({ )} {viewState.view.type === SwapWidgetViews.FAIL && ( { page({ userJourney: UserJourney.SWAP, @@ -284,8 +281,8 @@ export function SwapWidget({ )} {viewState.view.type === SwapWidgetViews.PRICE_SURGE && ( { page({ userJourney: UserJourney.SWAP, @@ -313,7 +310,7 @@ export function SwapWidget({ )} {viewState.view.type === SharedViews.ERROR_VIEW && ( { setErrorViewLoading(true); const data = viewState.view as ErrorViewType; diff --git a/packages/checkout/widgets-lib/src/widgets/swap/components/SwapButton.tsx b/packages/checkout/widgets-lib/src/widgets/swap/components/SwapButton.tsx index e2c8c047aa..a8c91b527b 100644 --- a/packages/checkout/widgets-lib/src/widgets/swap/components/SwapButton.tsx +++ b/packages/checkout/widgets-lib/src/widgets/swap/components/SwapButton.tsx @@ -2,7 +2,7 @@ import { Box, Button } from '@biom3/react'; import { useContext, useState } from 'react'; import { TransactionResponse } from '@imtbl/dex-sdk'; import { CheckoutErrorType } from '@imtbl/checkout-sdk'; -import { text } from '../../../resources/text/textConfig'; +import { useTranslation } from 'react-i18next'; import { PrefilledSwapForm, SwapWidgetViews } from '../../../context/view-context/SwapViewContextTypes'; import { ViewContext, @@ -31,11 +31,11 @@ export interface SwapButtonProps { export function SwapButton({ loading, updateLoading, validator, transaction, data, insufficientFundsForGas, openNotEnoughImxDrawer, }: SwapButtonProps) { + const { t } = useTranslation(); const [showTxnRejectedState, setShowTxnRejectedState] = useState(false); const { viewDispatch } = useContext(ViewContext); const { connectLoaderState } = useContext(ConnectLoaderContext); const { checkout, provider } = connectLoaderState; - const { buttonText } = text.views[SwapWidgetViews.SWAP].swapForm; const { track } = useAnalytics(); const sendTransaction = async () => { const isValid = validator(); @@ -165,7 +165,7 @@ export function SwapButton({ > {loading ? ( - ) : buttonText} + ) : t('views.SWAP.swapForm.buttonText')} b.balance.gt(0)) .map( - (t) => ({ - id: formatTokenOptionsId(t.token.symbol, t.token.address), - name: t.token.name, - symbol: t.token.symbol, - icon: t.token.icon, + (tokenBalance) => ({ + id: formatTokenOptionsId(tokenBalance.token.symbol, tokenBalance.token.address), + name: tokenBalance.token.name, + symbol: tokenBalance.token.symbol, + icon: tokenBalance.token.icon, balance: { - formattedAmount: tokenValueFormat(t.formattedBalance), + formattedAmount: tokenValueFormat(tokenBalance.formattedBalance), formattedFiatAmount: cryptoFiatState.conversions.size === 0 ? formatZeroAmount('') : calculateCryptoToFiat( - t.formattedBalance, - t.token.symbol || '', + tokenBalance.formattedBalance, + tokenBalance.token.symbol || '', cryptoFiatState.conversions, ), }, @@ -168,25 +168,25 @@ export function SwapForm({ data }: SwapFromProps) { if (data?.fromTokenAddress) { setFromToken( - allowedTokens.find((t) => (isNativeToken(t.address) + allowedTokens.find((token) => (isNativeToken(token.address) && data?.fromTokenAddress?.toLowerCase() === NATIVE) - || t.address?.toLowerCase() + || token.address?.toLowerCase() === data?.fromTokenAddress?.toLowerCase()), ); setFromBalance( tokenBalances.find( - (t) => ( - isNativeToken(t.token.address) + (tokenBalance) => ( + isNativeToken(tokenBalance.token.address) && data?.fromTokenAddress?.toLowerCase() === NATIVE) - || (t.token.address?.toLowerCase() === data?.fromTokenAddress?.toLowerCase()), + || (tokenBalance.token.address?.toLowerCase() === data?.fromTokenAddress?.toLowerCase()), )?.formattedBalance ?? '', ); } if (shouldSetToAddress(data?.toTokenAddress, data?.fromTokenAddress)) { - setToToken(allowedTokens.find((t) => ( - isNativeToken(t.address) && data?.toTokenAddress?.toLowerCase() === NATIVE - ) || (t.address?.toLowerCase() === data?.toTokenAddress?.toLowerCase()))); + setToToken(allowedTokens.find((token) => ( + isNativeToken(token.address) && data?.toTokenAddress?.toLowerCase() === NATIVE + ) || (token.address?.toLowerCase() === data?.toTokenAddress?.toLowerCase()))); } } }, [ @@ -207,10 +207,10 @@ export function SwapForm({ data }: SwapFromProps) { const tokensOptionsTo = useMemo(() => allowedTokens .map( - (t) => ({ - id: formatTokenOptionsId(t.symbol, t.address), - name: t.name, - symbol: t.symbol, + (token) => ({ + id: formatTokenOptionsId(token.symbol, token.address), + name: token.name, + symbol: token.symbol, icon: undefined, // todo: add correct image once available on token info } as CoinSelectorOptionProps), ), [allowedTokens, fromToken]); @@ -482,7 +482,7 @@ export function SwapForm({ data }: SwapFromProps) { const onFromSelectChange = useCallback((value: OptionKey) => { const selected = tokenBalances - .find((t) => value === formatTokenOptionsId(t.token.symbol, t.token.address)); + .find((tokenBalance) => value === formatTokenOptionsId(tokenBalance.token.symbol, tokenBalance.token.address)); if (!selected) return; if (toToken && value === formatTokenOptionsId(toToken.symbol, toToken?.address)) { @@ -530,7 +530,7 @@ export function SwapForm({ data }: SwapFromProps) { // TO // // ------------// const onToSelectChange = useCallback((value: OptionKey) => { - const selected = allowedTokens.find((t) => value === formatTokenOptionsId(t.symbol, t.address)); + const selected = allowedTokens.find((token) => value === formatTokenOptionsId(token.symbol, token.address)); if (!selected) return; if (fromToken && value === formatTokenOptionsId(fromToken.symbol, fromToken?.address)) { @@ -561,7 +561,6 @@ export function SwapForm({ data }: SwapFromProps) { setShowNotEnoughImxDrawer(true); }; - const { content, swapForm, fees } = text.views[SwapWidgetViews.SWAP]; const SwapFormValidator = (): boolean => { const validateFromTokenError = validateFromToken(fromToken); const validateFromAmountError = validateFromAmount(fromAmount, fromBalance); @@ -616,7 +615,7 @@ export function SwapForm({ data }: SwapFromProps) { weight="regular" sx={{ paddingBottom: 'base.spacing.x4' }} > - {content.title} + {t('views.SWAP.content.title')} - {swapForm.from.label} + {t('views.SWAP.swapForm.from.label')} @@ -683,7 +682,7 @@ export function SwapForm({ data }: SwapFromProps) { paddingBottom: 'base.spacing.x1', }} > - {swapForm.to.label} + {t('views.SWAP.swapForm.to.label')} onToTextInputChange(v)} @@ -712,13 +711,13 @@ export function SwapForm({ data }: SwapFromProps) { selectedOption={toToken ? formatTokenOptionsId(toToken.symbol, toToken.address) : undefined} - coinSelectorHeading={swapForm.to.selectorTitle} + coinSelectorHeading={t('views.SWAP.swapForm.to.selectorTitle')} /> - {heading} + {t('drawers.unableToSwap.heading')} - {body} + {t('drawers.unableToSwap.body')} diff --git a/packages/checkout/widgets-lib/src/widgets/swap/views/ApproveERC20Onboarding.tsx b/packages/checkout/widgets-lib/src/widgets/swap/views/ApproveERC20Onboarding.tsx index fd67410098..9a5c45c4c3 100644 --- a/packages/checkout/widgets-lib/src/widgets/swap/views/ApproveERC20Onboarding.tsx +++ b/packages/checkout/widgets-lib/src/widgets/swap/views/ApproveERC20Onboarding.tsx @@ -3,11 +3,11 @@ import { useCallback, useContext, useEffect, useMemo, useState, } from 'react'; import { CheckoutErrorType, TokenInfo } from '@imtbl/checkout-sdk'; +import { useTranslation } from 'react-i18next'; import { SimpleLayout } from '../../../components/SimpleLayout/SimpleLayout'; import { HeaderNavigation } from '../../../components/Header/HeaderNavigation'; import { sendSwapWidgetCloseEvent } from '../SwapWidgetEvents'; import { FooterButton } from '../../../components/Footer/FooterButton'; -import { text } from '../../../resources/text/textConfig'; import { ApproveERC20SwapData, PrefilledSwapForm, @@ -28,11 +28,11 @@ export interface ApproveERC20Props { data: ApproveERC20SwapData; } export function ApproveERC20Onboarding({ data }: ApproveERC20Props) { + const { t } = useTranslation(); const { swapState: { allowedTokens } } = useContext(SwapContext); const { connectLoaderState } = useContext(ConnectLoaderContext); const { checkout, provider } = connectLoaderState; const { viewDispatch } = useContext(ViewContext); - const { approveSpending, approveSwap } = text.views[SwapWidgetViews.APPROVE_ERC20]; const { eventTargetState: { eventTarget } } = useContext(EventTargetContext); const isPassport = isPassportProvider(provider); @@ -201,24 +201,33 @@ export function ApproveERC20Onboarding({ data }: ApproveERC20Props) { setApprovalTxnLoading, ]); - const approveSpendingContent = useMemo(() => { - const { metamask, passport } = approveSpending.content; - return ( - - {isPassport && ({passport.body})} + const approveSpendingContent = useMemo( + () => ( + + {isPassport && ({t('views.APPROVE_ERC20.approveSpending.content.passport.body')})} {!isPassport - // eslint-disable-next-line max-len - && ({`${metamask.body[0]} ${data.swapFormInfo.fromAmount} ${fromToken?.symbol || ''} ${metamask.body[1]}`})} + // eslint-disable-next-line max-len + && ( + + {t( + 'views.APPROVE_ERC20.approveSpending.content.metamask.body', + { amount: `${data.swapFormInfo.fromAmount} ${fromToken?.symbol || ''}` }, + )} + + )} - ); - }, [data.swapFormInfo, fromToken, isPassport]); + ), + [data.swapFormInfo, fromToken, isPassport], + ); const approveSpendingFooter = useMemo(() => ( ), [rejectedSpending, handleApproveSpendingClick, loading]); @@ -291,24 +300,26 @@ export function ApproveERC20Onboarding({ data }: ApproveERC20Props) { ]); const approveSwapContent = ( - - {approveSwap.content.body} + + {t('views.APPROVE_ERC20.approveSwap.content.body')} ); const approveSwapFooter = useMemo(() => ( ), [rejectedSwap, handleApproveSwapClick, loading]); return ( <> - {approvalTxnLoading && ()} + {approvalTxnLoading && ( + + )} {!approvalTxnLoading && ( sendSwapWidgetCloseEvent(eventTarget)} /> )} diff --git a/packages/checkout/widgets-lib/src/widgets/swap/views/SwapInProgress.tsx b/packages/checkout/widgets-lib/src/widgets/swap/views/SwapInProgress.tsx index 9fce091526..4517e2326a 100644 --- a/packages/checkout/widgets-lib/src/widgets/swap/views/SwapInProgress.tsx +++ b/packages/checkout/widgets-lib/src/widgets/swap/views/SwapInProgress.tsx @@ -1,5 +1,6 @@ import { TransactionResponse } from '@ethersproject/providers'; import { useContext, useEffect } from 'react'; +import { useTranslation } from 'react-i18next'; import { ViewActions, ViewContext, @@ -9,7 +10,6 @@ import { SwapWidgetViews, } from '../../../context/view-context/SwapViewContextTypes'; import { LoadingView } from '../../../views/loading/LoadingView'; -import { text } from '../../../resources/text/textConfig'; import { UserJourney, useAnalytics } from '../../../context/analytics-provider/SegmentAnalyticsProvider'; interface SwapInProgressProps { @@ -18,8 +18,8 @@ interface SwapInProgressProps { } export function SwapInProgress({ transactionResponse, swapForm }: SwapInProgressProps) { + const { t } = useTranslation(); const { viewDispatch } = useContext(ViewContext); - const { IN_PROGRESS: { loading } } = text.views[SwapWidgetViews.SWAP]; const { page } = useAnalytics(); @@ -79,6 +79,6 @@ export function SwapInProgress({ transactionResponse, swapForm }: SwapInProgress }, [transactionResponse]); return ( - + ); } diff --git a/packages/checkout/widgets-lib/src/widgets/wallet/components/NetworkMenu/NetworkMenu.tsx b/packages/checkout/widgets-lib/src/widgets/wallet/components/NetworkMenu/NetworkMenu.tsx index b14fe8519d..cb291767e7 100644 --- a/packages/checkout/widgets-lib/src/widgets/wallet/components/NetworkMenu/NetworkMenu.tsx +++ b/packages/checkout/widgets-lib/src/widgets/wallet/components/NetworkMenu/NetworkMenu.tsx @@ -12,8 +12,8 @@ import { SwitchNetworkParams, } from '@imtbl/checkout-sdk'; import { logoColour, networkIcon } from 'lib'; +import { useTranslation } from 'react-i18next'; import { WalletContext } from '../../context/WalletContext'; -import { text } from '../../../../resources/text/textConfig'; import { sendNetworkSwitchEvent } from '../../WalletWidgetEvents'; import { activeNetworkButtonStyle, @@ -28,7 +28,6 @@ import { ViewActions, SharedViews, } from '../../../../context/view-context/ViewContext'; -import { WalletWidgetViews } from '../../../../context/view-context/WalletViewContextTypes'; import { ConnectLoaderContext, } from '../../../../context/connect-loader-context/ConnectLoaderContext'; @@ -40,12 +39,12 @@ export interface NetworkMenuProps { } export function NetworkMenu({ setBalancesLoading }: NetworkMenuProps) { + const { t } = useTranslation(); const { connectLoaderState } = useContext(ConnectLoaderContext); const { eventTargetState: { eventTarget } } = useContext(EventTargetContext); const { checkout, provider } = connectLoaderState; const { viewDispatch } = useContext(ViewContext); const { walletState, walletDispatch } = useContext(WalletContext); - const { networkStatus } = text.views[WalletWidgetViews.WALLET_BALANCES]; const { network } = walletState; const [allowedNetworks, setNetworks] = useState( [], @@ -107,7 +106,7 @@ export function NetworkMenu({ setBalancesLoading }: NetworkMenuProps) { return ( - {networkStatus.heading} + {t('views.WALLET_BALANCES.networkStatus.heading')} {checkout diff --git a/packages/checkout/widgets-lib/src/widgets/wallet/components/TokenBalanceList/TokenBalanceList.tsx b/packages/checkout/widgets-lib/src/widgets/wallet/components/TokenBalanceList/TokenBalanceList.tsx index 1014a88f1e..d3b209a9b8 100644 --- a/packages/checkout/widgets-lib/src/widgets/wallet/components/TokenBalanceList/TokenBalanceList.tsx +++ b/packages/checkout/widgets-lib/src/widgets/wallet/components/TokenBalanceList/TokenBalanceList.tsx @@ -1,9 +1,8 @@ import { Body, Box } from '@biom3/react'; +import { useTranslation } from 'react-i18next'; import { BalanceItem } from '../BalanceItem/BalanceItem'; import { tokenBalanceListStyle, noTokensStyle } from './TokenBalanceListStyles'; -import { text } from '../../../../resources/text/textConfig'; import { BalanceInfo } from '../../functions/tokenBalances'; -import { WalletWidgetViews } from '../../../../context/view-context/WalletViewContextTypes'; import { isNativeToken } from '../../../../lib/utils'; import { ZERO_BALANCE_STRING } from '../../../../lib'; @@ -20,7 +19,7 @@ export function TokenBalanceList({ balanceInfoItems, bridgeToL2OnClick, }: TokenBalanceListProps) { - const { noTokensFound } = text.views[WalletWidgetViews.WALLET_BALANCES].tokenBalancesList; + const { t } = useTranslation(); const filteredBalances = filterZeroBalances(balanceInfoItems); return ( @@ -28,7 +27,7 @@ export function TokenBalanceList({ {filteredBalances.length === 0 && ( - {noTokensFound} + {t('views.WALLET_BALANCES.tokenBalancesList.noTokensFound')} )} {filteredBalances.map((balance) => ( diff --git a/packages/checkout/widgets-lib/src/widgets/wallet/components/TotalTokenBalance/TotalTokenBalance.tsx b/packages/checkout/widgets-lib/src/widgets/wallet/components/TotalTokenBalance/TotalTokenBalance.tsx index 875af04147..24a3c7f32a 100644 --- a/packages/checkout/widgets-lib/src/widgets/wallet/components/TotalTokenBalance/TotalTokenBalance.tsx +++ b/packages/checkout/widgets-lib/src/widgets/wallet/components/TotalTokenBalance/TotalTokenBalance.tsx @@ -2,6 +2,7 @@ import { Body, Box, ButtCon, } from '@biom3/react'; import { useContext } from 'react'; +import { useTranslation } from 'react-i18next'; import { coinInfoButtonStyle, totalTokenBalanceStyle, @@ -12,7 +13,6 @@ import { ViewContext, } from '../../../../context/view-context/ViewContext'; import { WalletWidgetViews } from '../../../../context/view-context/WalletViewContextTypes'; -import { text } from '../../../../resources/text/textConfig'; interface TotalTokenBalanceProps { totalBalance: number; @@ -20,13 +20,13 @@ interface TotalTokenBalanceProps { } export function TotalTokenBalance(props: TotalTokenBalanceProps) { + const { t } = useTranslation(); const { viewDispatch } = useContext(ViewContext); - const { totalTokenBalance } = text.views[WalletWidgetViews.WALLET_BALANCES]; const { totalBalance, loading } = props; return ( - {totalTokenBalance.heading} + {t('views.WALLET_BALANCES.totalTokenBalance.heading')} - {totalTokenBalance.totalHeading} + {t('views.WALLET_BALANCES.totalTokenBalance.totalHeading')} {!loading && ( diff --git a/packages/checkout/widgets-lib/src/widgets/wallet/views/CoinInfo.tsx b/packages/checkout/widgets-lib/src/widgets/wallet/views/CoinInfo.tsx index aa683eabbe..f1c390fa9f 100644 --- a/packages/checkout/widgets-lib/src/widgets/wallet/views/CoinInfo.tsx +++ b/packages/checkout/widgets-lib/src/widgets/wallet/views/CoinInfo.tsx @@ -1,10 +1,9 @@ import { useContext, useEffect } from 'react'; import { Link } from '@biom3/react'; +import { useTranslation } from 'react-i18next'; import { FooterLogo } from '../../../components/Footer/FooterLogo'; import { HeaderNavigation } from '../../../components/Header/HeaderNavigation'; import { SimpleLayout } from '../../../components/SimpleLayout/SimpleLayout'; -import { text } from '../../../resources/text/textConfig'; -import { WalletWidgetViews } from '../../../context/view-context/WalletViewContextTypes'; import { SimpleTextBody } from '../../../components/Body/SimpleTextBody'; import { IMXCoinsHero } from '../../../components/Hero/IMXCoinsHero'; import { ConnectLoaderContext } from '../../../context/connect-loader-context/ConnectLoaderContext'; @@ -13,13 +12,9 @@ import { FAQS_LINK } from '../../../lib'; import { UserJourney, useAnalytics } from '../../../context/analytics-provider/SegmentAnalyticsProvider'; export function CoinInfo() { + const { t } = useTranslation(); const { connectLoaderState: { provider } } = useContext(ConnectLoaderContext); - const coinInfoText = text.views[WalletWidgetViews.COIN_INFO]; const isPassport = isPassportProvider(provider); - const { heading, body } = coinInfoText.metamask; - const { - heading: passportHeading, body1, body2, linkText, - } = coinInfoText.passport; const { page } = useAnalytics(); @@ -38,12 +33,16 @@ export function CoinInfo() { heroContent={} floatHeader > - {!isPassport && {body}} + {!isPassport && ( + + {t('views.COIN_INFO.metamask.body')} + + )} {isPassport && ( - - {body1} - window.open(FAQS_LINK)}>{linkText} - {body2} + + {t('views.COIN_INFO.passport.body1')} + window.open(FAQS_LINK)}>{t('views.COIN_INFO.passport.linkText')} + {t('views.COIN_INFO.passport.body2')} )} diff --git a/packages/checkout/widgets-lib/src/widgets/wallet/views/Settings.tsx b/packages/checkout/widgets-lib/src/widgets/wallet/views/Settings.tsx index 26b5086857..6ddb7b56d1 100644 --- a/packages/checkout/widgets-lib/src/widgets/wallet/views/Settings.tsx +++ b/packages/checkout/widgets-lib/src/widgets/wallet/views/Settings.tsx @@ -1,11 +1,10 @@ import { Box, Button } from '@biom3/react'; import { useContext, useEffect } from 'react'; +import { useTranslation } from 'react-i18next'; import { FooterLogo } from '../../../components/Footer/FooterLogo'; import { HeaderNavigation } from '../../../components/Header/HeaderNavigation'; import { SimpleLayout } from '../../../components/SimpleLayout/SimpleLayout'; -import { text } from '../../../resources/text/textConfig'; import { sendDisconnectWalletEvent, sendWalletWidgetCloseEvent } from '../WalletWidgetEvents'; -import { WalletWidgetViews } from '../../../context/view-context/WalletViewContextTypes'; import { WalletAddress } from '../components/WalletAddress/WalletAddress'; import { settingsBoxStyle, settingsDisconnectButtonStyle } from './SettingsStyles'; import { ConnectLoaderContext } from '../../../context/connect-loader-context/ConnectLoaderContext'; @@ -14,9 +13,9 @@ import { EventTargetContext } from '../../../context/event-target-context/EventT import { UserJourney, useAnalytics } from '../../../context/analytics-provider/SegmentAnalyticsProvider'; export function Settings() { + const { t } = useTranslation(); const { connectLoaderState } = useContext(ConnectLoaderContext); const { provider } = connectLoaderState; - const { header, disconnectButton } = text.views[WalletWidgetViews.SETTINGS]; const { eventTargetState: { eventTarget } } = useContext(EventTargetContext); const isPassport = isPassportProvider(provider); @@ -36,7 +35,7 @@ export function Settings() { header={( sendWalletWidgetCloseEvent(eventTarget)} /> )} @@ -53,7 +52,7 @@ export function Settings() { sx={settingsDisconnectButtonStyle} onClick={() => sendDisconnectWalletEvent(eventTarget)} > - {disconnectButton.label} + {t('views.SETTINGS.disconnectButton.label')} )} diff --git a/packages/checkout/widgets-lib/src/widgets/wallet/views/WalletBalances.tsx b/packages/checkout/widgets-lib/src/widgets/wallet/views/WalletBalances.tsx index 51546562e3..52ee4d3671 100644 --- a/packages/checkout/widgets-lib/src/widgets/wallet/views/WalletBalances.tsx +++ b/packages/checkout/widgets-lib/src/widgets/wallet/views/WalletBalances.tsx @@ -7,10 +7,10 @@ import { utils } from 'ethers'; import { fetchTokenSymbols } from 'lib/fetchTokenSymbols'; import { CryptoFiatActions, CryptoFiatContext } from 'context/crypto-fiat-context/CryptoFiatContext'; import { ButtonNavigationStyles } from 'components/Header/HeaderStyles'; +import { useTranslation } from 'react-i18next'; import { FooterLogo } from '../../../components/Footer/FooterLogo'; import { HeaderNavigation } from '../../../components/Header/HeaderNavigation'; import { SimpleLayout } from '../../../components/SimpleLayout/SimpleLayout'; -import { text } from '../../../resources/text/textConfig'; import { TotalTokenBalance } from '../components/TotalTokenBalance/TotalTokenBalance'; import { TokenBalanceList } from '../components/TokenBalanceList/TokenBalanceList'; import { NetworkMenu } from '../components/NetworkMenu/NetworkMenu'; @@ -51,6 +51,7 @@ export function WalletBalances({ balancesLoading, setBalancesLoading, }: WalletBalancesProps) { + const { t } = useTranslation(); const { connectLoaderState } = useContext(ConnectLoaderContext); const { checkout, provider } = connectLoaderState; const { cryptoFiatState, cryptoFiatDispatch } = useContext(CryptoFiatContext); @@ -59,7 +60,6 @@ export function WalletBalances({ const { viewDispatch } = useContext(ViewContext); const [totalFiatAmount, setTotalFiatAmount] = useState(0.0); - const { header } = text.views[WalletWidgetViews.WALLET_BALANCES]; const { network, supportedTopUps, @@ -204,7 +204,7 @@ export function WalletBalances({ testId="wallet-balances" header={( - Add coins + {t('views.WALLET_BALANCES.addCoins')} )} + + + + ); } diff --git a/packages/checkout/widgets-sample-app/src/components/ui/marketplace-orchestrator/LanguageSelector.tsx b/packages/checkout/widgets-sample-app/src/components/ui/marketplace-orchestrator/LanguageSelector.tsx new file mode 100644 index 0000000000..cf92de11e6 --- /dev/null +++ b/packages/checkout/widgets-sample-app/src/components/ui/marketplace-orchestrator/LanguageSelector.tsx @@ -0,0 +1,41 @@ +import { Box, MenuItem, OverflowPopoverMenu } from '@biom3/react'; + +// @ts-ignore +export const LanguageSelector = ({ onLanguageChange, language, ...args }) => { + + const handleLanguageChange = (language: string) => { + if (onLanguageChange) { + onLanguageChange(language); + } + }; + + const isSelected = (selectedLanguage: string) => { + return selectedLanguage === language; + } + + return ( + + + handleLanguageChange('en')} selected={isSelected('en')}> + English + + handleLanguageChange('ja')} selected={isSelected('ja')}> + 日本語 + + handleLanguageChange('ko')} selected={isSelected('ko')}> + 한국어 + + handleLanguageChange('zh')} selected={isSelected('zh')}> + 中文 + + + + ) +} diff --git a/packages/checkout/widgets-sample-app/src/components/ui/marketplace-orchestrator/MainPage.tsx b/packages/checkout/widgets-sample-app/src/components/ui/marketplace-orchestrator/MainPage.tsx index c3bfdece37..e09b5a5647 100644 --- a/packages/checkout/widgets-sample-app/src/components/ui/marketplace-orchestrator/MainPage.tsx +++ b/packages/checkout/widgets-sample-app/src/components/ui/marketplace-orchestrator/MainPage.tsx @@ -15,10 +15,11 @@ import { SwapEventType, WalletEventType, WalletNetworkSwitch, - WidgetTheme, WidgetType, ProviderEventType, ProviderUpdated + WidgetTheme, WidgetType, ProviderEventType, ProviderUpdated, WidgetConfiguration, WidgetProperties } from '@imtbl/checkout-sdk'; import { Environment } from '@imtbl/config'; import { passport } from './passport'; +import { LanguageSelector } from './LanguageSelector'; // Create one instance of Checkout and inject Passport const checkout = new Checkout({ @@ -46,6 +47,7 @@ export const MainPage = () => { // local state for enabling/disabling and changing buttons const [doneSwap, setDoneSwap] = useState(false); + const [selectedLanguage, setSelectedLanguage] = useState('en'); const [web3Provider, setWeb3Provider] = useState(undefined); useEffect(() => { @@ -110,6 +112,16 @@ export const MainPage = () => { await passport.logout(); }, [passport]) + const updateLanguage = useCallback((language: string) => { + setSelectedLanguage(language); + const languageUpdate: WidgetProperties = { config: { language } } as WidgetProperties; + connectWidget.update(languageUpdate); + walletWidget.update(languageUpdate); + bridgeWidget.update(languageUpdate); + swapWidget.update(languageUpdate); + onRampWidget.update(languageUpdate); + }, [onRampWidget, web3Provider]) + return ( @@ -120,6 +132,7 @@ export const MainPage = () => { + updateLanguage(language)} language={selectedLanguage} /> {passport && web3Provider && (web3Provider.provider as any)?.isPassport && } diff --git a/packages/checkout/widgets-sample-app/src/components/ui/wallet/wallet.tsx b/packages/checkout/widgets-sample-app/src/components/ui/wallet/wallet.tsx index 6dfcc331cd..6d7e59a54e 100644 --- a/packages/checkout/widgets-sample-app/src/components/ui/wallet/wallet.tsx +++ b/packages/checkout/widgets-sample-app/src/components/ui/wallet/wallet.tsx @@ -4,12 +4,13 @@ import { WidgetsFactory } from '@imtbl/checkout-widgets'; function WalletUI() { const checkout = useMemo(() => new Checkout(), []) - const wallet = useMemo(() => new WidgetsFactory(checkout, {}).create(WidgetType.WALLET), [checkout]) + const wallet = useMemo(() => new WidgetsFactory(checkout, {}).create(WidgetType.WALLET), [checkout]) const unmount = () => {wallet.unmount()} const mount = () => {wallet.mount('wallet')} const update = (theme: WidgetTheme) => {wallet.update({config: {theme}})} - + const updateLanguage = (language: any) => {wallet.update({config: {language}})} + useEffect(() => { mount() wallet.addListener(WalletEventType.NETWORK_SWITCH, (data) => {console.log('NETWORK_SWITCH', data)}) @@ -24,6 +25,10 @@ function WalletUI() { + + + + ); } diff --git a/sdk/package.json b/sdk/package.json index d1c4a952f7..f95a045336 100644 --- a/sdk/package.json +++ b/sdk/package.json @@ -31,11 +31,14 @@ "enc-utils": "^3.0.0", "ethers": "^5.7.2", "https-browserify": "^1.0.0", + "i18next": "^23.7.6", + "i18next-browser-languagedetector": "^7.2.0", "jwt-decode": "^3.1.2", "magic-sdk": "^21.2.0", "oidc-client-ts": "^2.2.1", "os-browserify": "^0.3.0", "pako": "^2.1.0", + "react-i18next": "^13.5.0", "stream-browserify": "^3.0.0", "stream-http": "^3.2.0", "url": "^0.11.0" diff --git a/yarn.lock b/yarn.lock index bc93be35dc..1d82be01f3 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2092,6 +2092,15 @@ __metadata: languageName: node linkType: hard +"@babel/runtime@npm:^7.22.5, @babel/runtime@npm:^7.23.2": + version: 7.23.6 + resolution: "@babel/runtime@npm:7.23.6" + dependencies: + regenerator-runtime: ^0.14.0 + checksum: 1a8eaf3d3a103ef5227b60ca7ab5c589118c36ca65ef2d64e65380b32a98a3f3b5b3ef96660fa0471b079a18b619a8317f3e7f03ab2b930c45282a8b69ed9a16 + languageName: node + linkType: hard + "@babel/template@npm:^7.22.15": version: 7.22.15 resolution: "@babel/template@npm:7.22.15" @@ -3627,11 +3636,14 @@ __metadata: eslint: ^8.40.0 ethers: ^5.7.2 https-browserify: ^1.0.0 + i18next: ^23.7.6 + i18next-browser-languagedetector: ^7.2.0 jest: ^29.4.3 local-cypress: ^1.2.6 os-browserify: ^0.3.0 pako: ^2.1.0 react-app-rewired: ^2.2.1 + react-i18next: ^13.5.0 react-scripts: 5.0.1 rollup: ^3.17.2 rollup-plugin-svg: ^2.0.0 @@ -4163,11 +4175,14 @@ __metadata: ethers: ^5.7.2 glob: ^10.2.3 https-browserify: ^1.0.0 + i18next: ^23.7.6 + i18next-browser-languagedetector: ^7.2.0 jwt-decode: ^3.1.2 magic-sdk: ^21.2.0 oidc-client-ts: ^2.2.1 os-browserify: ^0.3.0 pako: ^2.1.0 + react-i18next: ^13.5.0 rollup: ^3.17.2 rollup-plugin-dts: ^5.3.0 rollup-plugin-polyfill-node: ^0.12.0 @@ -18438,6 +18453,15 @@ __metadata: languageName: node linkType: hard +"html-parse-stringify@npm:^3.0.1": + version: 3.0.1 + resolution: "html-parse-stringify@npm:3.0.1" + dependencies: + void-elements: 3.1.0 + checksum: 334fdebd4b5c355dba8e95284cead6f62bf865a2359da2759b039db58c805646350016d2017875718bc3c4b9bf81a0d11be5ee0cf4774a3a5a7b97cde21cfd67 + languageName: node + linkType: hard + "html-webpack-plugin@npm:^5.5.0": version: 5.5.3 resolution: "html-webpack-plugin@npm:5.5.3" @@ -18770,6 +18794,24 @@ __metadata: languageName: node linkType: hard +"i18next-browser-languagedetector@npm:^7.2.0": + version: 7.2.0 + resolution: "i18next-browser-languagedetector@npm:7.2.0" + dependencies: + "@babel/runtime": ^7.23.2 + checksum: 757845c7ae7dfc541f5150855c3a3e4f6d29bcee113796d44dc781594abc7f16f2750a2a70d786904c16d23ba952eba2741c0bcfeaa381016669522a6236998f + languageName: node + linkType: hard + +"i18next@npm:^23.7.6": + version: 23.7.11 + resolution: "i18next@npm:23.7.11" + dependencies: + "@babel/runtime": ^7.23.2 + checksum: 50aeaa279f95d27ea9a6a0bf58e28ef883c0056b89e17fd21e252287269e9a8debbdbcb753047c03ceabbb2b240a9cf668f820c9306cedbe54957e2e64ea1c87 + languageName: node + linkType: hard + "iconv-lite@npm:0.4.24, iconv-lite@npm:^0.4.24": version: 0.4.24 resolution: "iconv-lite@npm:0.4.24" @@ -25613,6 +25655,24 @@ __metadata: languageName: node linkType: hard +"react-i18next@npm:^13.5.0": + version: 13.5.0 + resolution: "react-i18next@npm:13.5.0" + dependencies: + "@babel/runtime": ^7.22.5 + html-parse-stringify: ^3.0.1 + peerDependencies: + i18next: ">= 23.2.3" + react: ">= 16.8.0" + peerDependenciesMeta: + react-dom: + optional: true + react-native: + optional: true + checksum: 2f68ccd24daf72ddd2d11a526fb3c2b66c11ea4fcd2e24ac7aed42bf57ec7bffa7455ad1dc93679968ff629e9b1896465cdf6d1a61c29b92138ef88098e8dcba + languageName: node + linkType: hard + "react-inspector@npm:^6.0.0": version: 6.0.2 resolution: "react-inspector@npm:6.0.2" @@ -25973,6 +26033,13 @@ __metadata: languageName: node linkType: hard +"regenerator-runtime@npm:^0.14.0": + version: 0.14.1 + resolution: "regenerator-runtime@npm:0.14.1" + checksum: 9f57c93277b5585d3c83b0cf76be47b473ae8c6d9142a46ce8b0291a04bb2cf902059f0f8445dcabb3fb7378e5fe4bb4ea1e008876343d42e46d3b484534ce38 + languageName: node + linkType: hard + "regenerator-transform@npm:^0.15.1": version: 0.15.1 resolution: "regenerator-transform@npm:0.15.1" @@ -29883,6 +29950,13 @@ __metadata: languageName: node linkType: hard +"void-elements@npm:3.1.0": + version: 3.1.0 + resolution: "void-elements@npm:3.1.0" + checksum: 0390f818107fa8fce55bb0a5c3f661056001c1d5a2a48c28d582d4d847347c2ab5b7f8272314cac58acf62345126b6b09bea623a185935f6b1c3bbce0dfd7f7f + languageName: node + linkType: hard + "vscode-oniguruma@npm:^1.7.0": version: 1.7.0 resolution: "vscode-oniguruma@npm:1.7.0"