From e680deb34a75b148439e4646349ff965b3fe73ef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ruveyda=20K=C4=B1=C5=9Fla?= Date: Thu, 24 Jul 2025 18:24:47 +0330 Subject: [PATCH 1/3] fix: remove preflight tailwind --- rollup.config.dev.js | 10 ++-- rollup.config.prod.js | 18 ++++--- src/components/Button/index.tsx | 2 +- src/components/CardItem/index.tsx | 2 +- src/components/Input/index.tsx | 2 +- src/components/Modal/index.tsx | 2 +- src/tailwind.css | 80 ++++++++++++++++++++++++++++++- 7 files changed, 98 insertions(+), 18 deletions(-) diff --git a/rollup.config.dev.js b/rollup.config.dev.js index da55098..45816b0 100644 --- a/rollup.config.dev.js +++ b/rollup.config.dev.js @@ -7,7 +7,7 @@ import resolve from '@rollup/plugin-node-resolve'; import typescript from '@rollup/plugin-typescript'; import peerDepsExternal from 'rollup-plugin-peer-deps-external'; -import pkg from './package.json' assert { type: 'json' }; +import pkg from './package.json' with { type: 'json' }; export default { input: 'src/index.ts', @@ -30,8 +30,8 @@ export default { { find: 'global', replacement: 'globalThis', - } - ] + }, + ], }), json(), peerDepsExternal(), @@ -53,9 +53,7 @@ export default { exclude: ['node_modules', 'motion'], }), ], - external: [ - ...Object.keys(pkg.peerDependencies || {}), - ], + external: [...Object.keys(pkg.peerDependencies || {})], watch: { clearScreen: false, include: 'src/**', diff --git a/rollup.config.prod.js b/rollup.config.prod.js index 034c63c..bc274c9 100644 --- a/rollup.config.prod.js +++ b/rollup.config.prod.js @@ -9,7 +9,7 @@ import peerDepsExternal from 'rollup-plugin-peer-deps-external'; import tailwindcss from '@tailwindcss/postcss'; -import pkg from './package.json' assert { type: 'json' }; +import pkg from './package.json' with { type: 'json' }; export default { input: 'src/index.ts', @@ -33,8 +33,8 @@ export default { { find: 'global', replacement: 'globalThis', - } - ] + }, + ], }), json(), peerDepsExternal(), @@ -54,7 +54,13 @@ export default { commonjs(), postcss({ extract: false, - inject: true, + extensions: ['.css'], + inject: { + insertAt: 'top', + }, + config: { + path: './postcss.config.mjs', + }, minimize: true, plugins: [tailwindcss], }), @@ -63,7 +69,5 @@ export default { exclude: ['node_modules', 'motion'], }), ], - external: [ - ...Object.keys(pkg.peerDependencies || {}), - ], + external: [...Object.keys(pkg.peerDependencies || {})], }; diff --git a/src/components/Button/index.tsx b/src/components/Button/index.tsx index 7f68da4..697cdca 100644 --- a/src/components/Button/index.tsx +++ b/src/components/Button/index.tsx @@ -20,7 +20,7 @@ interface ButtonProps { } const buttonBase = - 'bluxcc:flex bluxcc:justify-center bluxcc:items-center bluxcc:px-[10px] bluxcc:transition-all bluxcc:w-full'; + 'bluxcc:flex bluxcc:justify-center bluxcc:items-center bluxcc:px-[10px] bluxcc:transition-all bluxcc:duration-300 bluxcc:w-full'; const sizeClasses: Record = { small: 'bluxcc:h-8 bluxcc:!text-sm bluxcc:gap-1', diff --git a/src/components/CardItem/index.tsx b/src/components/CardItem/index.tsx index 9000cb8..1365ffc 100644 --- a/src/components/CardItem/index.tsx +++ b/src/components/CardItem/index.tsx @@ -70,7 +70,7 @@ const CardItem = ({ return (
)}
setIsFocused(true)} onBlur={() => setIsFocused(false)} onMouseEnter={onMouseEnter} diff --git a/src/components/Modal/index.tsx b/src/components/Modal/index.tsx index a7d35d3..8cfb832 100644 --- a/src/components/Modal/index.tsx +++ b/src/components/Modal/index.tsx @@ -87,7 +87,7 @@ const Modal = ({ onClick={(e) => e.target === e.currentTarget && handleClose(onClose)} >
Date: Sun, 27 Jul 2025 18:54:45 +0330 Subject: [PATCH 2/3] feat: add multi language --- src/constants/locales.ts | 296 +++++++++++++++++++++++++++++++++++++++ src/context/provider.tsx | 1 + src/hooks/useLang.ts | 11 ++ src/types/index.ts | 2 + src/utils/translate.ts | 14 ++ 5 files changed, 324 insertions(+) create mode 100644 src/constants/locales.ts create mode 100644 src/hooks/useLang.ts create mode 100644 src/utils/translate.ts diff --git a/src/constants/locales.ts b/src/constants/locales.ts new file mode 100644 index 0000000..9d78d81 --- /dev/null +++ b/src/constants/locales.ts @@ -0,0 +1,296 @@ +export type LanguageKey = 'en' | 'es'; + +export type Translations = { + [key: string]: { + [lang in LanguageKey]: string; + }; +}; + +export type TranslationKey = keyof typeof translations; + +const translations: Translations = { + // Page titles + logInOrSignUp: { + en: 'Log in or Sign up', + es: 'Inicia sesión o regístrate', + }, + profile: { + en: 'Profile', + es: 'Perfil', + }, + confirmation: { + en: 'Confirmation', + es: 'Confirmación', + }, + send: { + en: 'Send', + es: 'Enviar', + }, + activity: { + en: 'Activity', + es: 'Actividad', + }, + swap: { + en: 'Swap', + es: 'Intercambiar', + }, + receive: { + en: 'Receive', + es: 'Recibir', + }, + wrongNetwork: { + en: 'Wrong Network', + es: 'Red incorrecta', + }, + + // General / Shared + loading: { + en: 'Loading', + es: 'Cargando', + }, + tryAgain: { + en: 'Try again', + es: 'Intenta de nuevo', + }, + connecting: { + en: 'Connecting', + es: 'Conectando', + }, + signing: { + en: 'Signing', + es: 'Firmando', + }, + + // Onboarding Page + allStellarWallets: { + en: 'All Stellar wallets', + es: 'Todas las carteras Stellar', + }, + email: { + en: 'Email', + es: 'Correo electrónico', + }, + passkey: { + en: 'Passkey', + es: 'Llave de acceso', + }, + submit: { + en: 'Submit', + es: 'Enviar', + }, + poweredByBlux: { + en: 'Powered by Blux.cc', + es: 'Desarrollado por Blux.cc', + }, + + // Success modal + connectionSuccessfulTitle: { + en: 'Connection Successful', + es: 'Conexión exitosa', + }, + transactionSuccessfulTitle: { + en: 'Transaction Successful', + es: 'Transacción exitosa', + }, + connectionSuccessfulMessage: { + en: 'Your account has been successfully connected to ${appName}', + es: 'Tu cuenta se ha conectado correctamente a ${appName}', + }, + transactionSuccessfulMessage: { + en: 'Your transaction was successfully completed', + es: 'Tu transacción se completó con éxito', + }, + seeInExplorer: { + en: 'See in explorer', + es: 'Ver en el explorador', + }, + loggingIn: { + en: 'Logging In', + es: 'Iniciando sesión', + }, + done: { + en: 'Done', + es: 'Hecho', + }, + + // Sign transaction modal + signTransactionPrompt: { + en: '${appName} wants your permission to approve the following transaction.', + es: '${appName} quiere tu permiso para aprobar la siguiente transacción.', + }, + invalidXdr: { + en: 'Invalid XDR', + es: 'XDR inválido', + }, + lobstrWarning: { + en: 'Ensure that your LOBSTR wallet is set to the ${network} network. Otherwise, the transaction will definitely fail.', + es: 'Asegúrate de que tu cartera LOBSTR esté configurada en la red ${network}. De lo contrario, la transacción fallará.', + }, + yourWallet: { + en: 'Your wallet', + es: 'Tu cartera', + }, + noAddressFound: { + en: 'No address found', + es: 'No se encontró ninguna dirección', + }, + approve: { + en: 'Approve', + es: 'Aprobar', + }, + + // Activity Page + loadingActivity: { + en: 'Loading activity...', + es: 'Cargando actividad...', + }, + noActivityFound: { + en: 'No activity found', + es: 'No se encontró actividad', + }, + multiOperation: { + en: 'Multi Operation', + es: 'Operación múltiple', + }, + pathPaymentDescription: { + en: 'Path payment of ${amount} ${asset}', + es: 'Pago por ruta de ${amount} ${asset}', + }, + seeAllInExplorer: { + en: 'See all in explorer', + es: 'Ver todo en el explorador', + }, + + // ConfirmCode Page + enterConfirmationCodeTitle: { + en: 'Enter confirmation code', + es: 'Introduce el código de confirmación', + }, + enterConfirmationCodeHelp: { + en: 'Please check your email and enter confirmation code below', + es: 'Por favor revisa tu correo electrónico e introduce el código de confirmación abajo', + }, + invalidCodeError: { + en: 'Invalid code, please try again.', + es: 'Código inválido, por favor intenta de nuevo.', + }, + resendCode: { + en: 'Resend code', + es: 'Reenviar código', + }, + + // Profile Page + copied: { + en: 'Copied!', + es: '¡Copiado!', + }, + logout: { + en: 'Logout', + es: 'Cerrar sesión', + }, + + // SelectAssets Component + search: { + en: 'Search', + es: 'Buscar', + }, + noAssetsFound: { + en: 'No assets found', + es: 'No se encontraron activos', + }, + + // SendForm Page + amount: { + en: 'Amount', + es: 'Cantidad', + }, + max: { + en: 'Max', + es: 'Máx', + }, + to: { + en: 'To', + es: 'A', + }, + enterAddress: { + en: 'Enter address', + es: 'Introduce la dirección', + }, + addressRequired: { + en: 'Address is required', + es: 'La dirección es obligatoria', + }, + addressInvalid: { + en: 'Address is invalid', + es: 'La dirección es inválida', + }, + inactiveAccount: { + en: 'Account is inActive', + es: 'La cuenta está inactiva', + }, + memo: { + en: 'Memo', + es: 'Memo', + }, + enterMemo: { + en: 'Enter Memo (optional)', + es: 'Introduce una Memo (opcional)', + }, + paste: { + en: 'Paste', + es: 'Pegar', + }, + amountRequired: { + en: 'Amount is required', + es: 'La cantidad es obligatoria', + }, + amountExceedsBalance: { + en: 'Amount is greater than max balance', + es: 'La cantidad excede el saldo máximo', + }, + sendButton: { + en: 'Send', + es: 'Enviar', + }, + + // Waiting Modal + loginFailed: { + en: 'Login failed', + es: 'Fallo al iniciar sesión', + }, + signingFailed: { + en: 'Signing with ${walletName} failed', + es: 'La firma con ${walletName} falló', + }, + waitingFor: { + en: 'Waiting for ${walletName}', + es: 'Esperando a ${walletName}', + }, + signingWith: { + en: 'Signing with ${walletName}', + es: 'Firmando con ${walletName}', + }, + loginRetryMessage: { + en: 'Please try logging in again.', + es: 'Por favor intenta iniciar sesión nuevamente.', + }, + signingRetryMessage: { + en: 'Please try signing again.', + es: 'Por favor intenta firmar nuevamente.', + }, + acceptConnection: { + en: 'Accept connection', + es: 'Aceptar conexión', + }, + signRequestInWallet: { + en: 'Sign the request in your wallet', + es: 'Firma la solicitud en tu cartera', + }, + + // Wrong Network Page + wrongNetworkMessage: { + en: 'You are on a wrong network.', + es: 'Estás en una red incorrecta.', + }, +}; +export default translations; diff --git a/src/context/provider.tsx b/src/context/provider.tsx index f219124..1427eac 100644 --- a/src/context/provider.tsx +++ b/src/context/provider.tsx @@ -76,6 +76,7 @@ export const BluxProvider = ({ config: { ...config, explorer: config.explorer || 'stellarchain', + lang: 'en', appearance: { ...defaultLightTheme, ...config.appearance, diff --git a/src/hooks/useLang.ts b/src/hooks/useLang.ts new file mode 100644 index 0000000..4c77d2e --- /dev/null +++ b/src/hooks/useLang.ts @@ -0,0 +1,11 @@ +import { translate } from '../utils/translate'; +import { useProvider } from '../context/provider'; +import { LanguageKey, TranslationKey } from '../constants/locales'; + +export const useLang = () => { + const { value } = useProvider(); + const lang = value.config.lang as LanguageKey; + + return (key: TranslationKey, vars?: Record) => + translate(key, lang, vars || {}); +}; diff --git a/src/types/index.ts b/src/types/index.ts index abb363e..743215c 100644 --- a/src/types/index.ts +++ b/src/types/index.ts @@ -3,6 +3,7 @@ import { HorizonApi } from '@stellar/stellar-sdk/lib/horizon'; import { Url } from '../utils/network/url'; import { UseAccountResult } from '../useStellar/useAccount'; +import { LanguageKey } from '../constants/locales'; /** * Enum representing the supported wallets in the system. @@ -69,6 +70,7 @@ export interface IProviderConfig { appearance?: Partial; transports?: ITransports; explorer?: IExplorers; + lang?: LanguageKey; showWalletUIs?: boolean; loginMethods?: Array< | 'wallet' diff --git a/src/utils/translate.ts b/src/utils/translate.ts new file mode 100644 index 0000000..dc9e1ba --- /dev/null +++ b/src/utils/translate.ts @@ -0,0 +1,14 @@ +import translations, { LanguageKey } from '../constants/locales'; + +const interpolate = (template: string, vars: Record = {}) => { + return template.replace(/\$\{(\w+)\}/g, (_, key) => vars[key] || ''); +}; + +export const translate = ( + key: keyof typeof translations, + lang: LanguageKey, + vars: Record = {}, +): string => { + const template = translations[key]?.[lang] || translations[key]?.en || ''; + return interpolate(template, vars); +}; From 0b8e1856c63be392511908f1f78cd75f69e5584d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ruveyda=20K=C4=B1=C5=9Fla?= Date: Mon, 28 Jul 2025 01:02:54 +0330 Subject: [PATCH 3/3] feat: add spanish language --- src/components/CardItem/index.tsx | 8 ++-- src/constants/locales.ts | 18 ++++++--- src/containers/BluxModal/content.tsx | 27 ++++++++------ src/containers/BluxModal/index.tsx | 4 +- src/containers/Pages/Activity/index.tsx | 22 ++++++----- src/containers/Pages/ConfirmCode/index.tsx | 16 ++++---- src/containers/Pages/OnBoarding/index.tsx | 16 ++++---- src/containers/Pages/Profile/index.tsx | 18 +++++---- src/containers/Pages/SelectAsset/index.tsx | 8 ++-- src/containers/Pages/Send/SendForm.tsx | 26 +++++++------ src/containers/Pages/Send/index.tsx | 7 ++-- .../Pages/SignTransaction/index.tsx | 15 ++++---- src/containers/Pages/Successful/index.tsx | 23 +++++++----- src/containers/Pages/Waiting/index.tsx | 37 +++++++++++-------- src/containers/Pages/WrongNetwork/index.tsx | 8 ++-- src/context/provider.tsx | 2 +- 16 files changed, 149 insertions(+), 106 deletions(-) diff --git a/src/components/CardItem/index.tsx b/src/components/CardItem/index.tsx index 1365ffc..84f2a97 100644 --- a/src/components/CardItem/index.tsx +++ b/src/components/CardItem/index.tsx @@ -2,6 +2,7 @@ import React, { useState, MouseEvent } from 'react'; import { useProvider } from '../../context/provider'; import { ArrowRight } from '../../assets/Icons'; import hexToRgba from '../../utils/hexToRgba'; +import { useLang } from '../../hooks/useLang'; type CardItemProps = { variant?: 'social' | 'default' | 'input'; @@ -30,6 +31,7 @@ const CardItem = ({ }: CardItemProps) => { const context = useProvider(); const { appearance } = context.value.config; + const t = useLang(); const [inputValue, setInputValue] = useState(label || ''); const [isValid, setIsValid] = useState(false); @@ -105,7 +107,7 @@ const CardItem = ({ value={inputValue} onChange={handleInputChange} onKeyDown={handleKeyDown} - placeholder="Email" + placeholder={t('email')} className="bluxcc:mr-1 bluxcc:h-full bluxcc:w-full bluxcc:bg-transparent bluxcc:outline-hidden bluxcc:focus:outline-hidden" style={{ color: appearance.textColor }} onFocus={() => setIsFocused(true)} @@ -133,7 +135,7 @@ const CardItem = ({ : '1px', }} > - Submit + {t('submit')}
@@ -150,7 +152,7 @@ const CardItem = ({ backgroundColor: `${hexToRgba(appearance.accent, 0.1)}`, }} > - Recent + {t('recent')}
)} diff --git a/src/constants/locales.ts b/src/constants/locales.ts index 9d78d81..b3c6dfe 100644 --- a/src/constants/locales.ts +++ b/src/constants/locales.ts @@ -60,6 +60,14 @@ const translations: Translations = { en: 'Signing', es: 'Firmando', }, + or: { + en: 'or', + es: 'o', + }, + recent: { + en: 'recent', + es: 'reciente', + }, // Onboarding Page allStellarWallets: { @@ -70,9 +78,9 @@ const translations: Translations = { en: 'Email', es: 'Correo electrónico', }, - passkey: { - en: 'Passkey', - es: 'Llave de acceso', + logInWithPasskey: { + en: 'Log in with Passkey', + es: 'Iniciar sesión con llave de acceso', }, submit: { en: 'Submit', @@ -115,8 +123,8 @@ const translations: Translations = { // Sign transaction modal signTransactionPrompt: { - en: '${appName} wants your permission to approve the following transaction.', - es: '${appName} quiere tu permiso para aprobar la siguiente transacción.', + en: 'wants your permission to approve the following transaction.', + es: 'quiere tu permiso para aprobar la siguiente transacción.', }, invalidXdr: { en: 'Invalid XDR', diff --git a/src/containers/BluxModal/content.tsx b/src/containers/BluxModal/content.tsx index 3e7d532..2b654cc 100644 --- a/src/containers/BluxModal/content.tsx +++ b/src/containers/BluxModal/content.tsx @@ -1,7 +1,5 @@ -import React from 'react'; - -import Send from '../Pages/Send'; import { Routes } from '../../types'; +import Send from '../Pages/Send'; import Profile from '../Pages/Profile'; import Waiting from '../Pages/Waiting'; import Activity from '../Pages/Activity'; @@ -10,6 +8,9 @@ import OnBoarding from '../Pages/OnBoarding'; import ConfirmCode from '../Pages/ConfirmCode'; import WrongNetwork from '../Pages/WrongNetwork'; import SignTransaction from '../Pages/SignTransaction'; +import { LanguageKey } from '../../constants/locales'; +import React from 'react'; +import { translate } from '../../utils/translate'; type RouteContent = { title: string; @@ -17,13 +18,15 @@ type RouteContent = { Component: React.JSX.Element; }; -export const modalContent: Record = { +export const getModalContent = ( + lang: LanguageKey, +): Record => ({ [Routes.ONBOARDING]: { - title: 'Log in or Signup', + title: translate('logInOrSignUp', lang), Component: , }, [Routes.PROFILE]: { - title: 'Profile', + title: translate('profile', lang), Component: , }, [Routes.WAITING]: { @@ -35,24 +38,24 @@ export const modalContent: Record = { Component: , }, [Routes.SIGN_TRANSACTION]: { - title: 'Confirmation', + title: translate('confirmation', lang), Component: , }, [Routes.SEND]: { - title: 'Send', + title: translate('send', lang), Component: , }, [Routes.ACTIVITY]: { - title: 'Activity', + title: translate('activity', lang), Component: , }, [Routes.OTP]: { - title: '', + title: translate('enterConfirmationCodeTitle', lang), Component: , }, [Routes.WRONG_NETWORK]: { isSticky: true, - title: 'Wrong Network', + title: translate('wrongNetwork', lang), Component: , }, -}; +}); diff --git a/src/containers/BluxModal/index.tsx b/src/containers/BluxModal/index.tsx index 57d2ef4..e0b0d73 100644 --- a/src/containers/BluxModal/index.tsx +++ b/src/containers/BluxModal/index.tsx @@ -4,7 +4,8 @@ import Modal from '../../components/Modal'; import { useProvider } from '../../context/provider'; import { Routes } from '../../types'; -import { modalContent } from './content'; +import { getModalContent } from './content'; +import { LanguageKey } from '../../constants/locales'; interface BluxModalProps { isOpen: boolean; @@ -59,6 +60,7 @@ export default function BluxModal({ isOpen, closeModal }: BluxModalProps) { } } }; + const modalContent = getModalContent(value.config.lang as LanguageKey); const { title, Component, isSticky } = modalContent[route]; diff --git a/src/containers/Pages/Activity/index.tsx b/src/containers/Pages/Activity/index.tsx index 84f1b87..dd62a03 100644 --- a/src/containers/Pages/Activity/index.tsx +++ b/src/containers/Pages/Activity/index.tsx @@ -2,6 +2,7 @@ import { Horizon } from '@stellar/stellar-sdk'; import React, { useEffect, useState } from 'react'; import Button from '../../../components/Button'; +import { useLang } from '../../../hooks/useLang'; import { useTransactions } from '../../../useStellar'; import { useProvider } from '../../../context/provider'; import toTitleFormat from '../../../utils/toTitleFormat'; @@ -27,7 +28,7 @@ const Activity: React.FC = () => { }); const { value } = useProvider(); - + const t = useLang(); const userAddress = value.user.wallet?.address as string; const explorerUrl = getExplorerUrl( value.activeNetwork, @@ -60,12 +61,12 @@ const Activity: React.FC = () => { }; if (tx.operations.length > 1) { - details.title = 'Multi Operation'; + details.title = t('multiOperation'); } else if (op.type === 'payment') { - let title = 'Send'; + let title = t('send'); if (op.to.toLowerCase() === userAddress.toLowerCase()) { - title = 'Receive'; + title = t('receive'); } details.title = title; @@ -75,8 +76,11 @@ const Activity: React.FC = () => { Horizon.HorizonApi.OperationResponseType.pathPaymentStrictSend || op.type === Horizon.HorizonApi.OperationResponseType.pathPayment ) { - details.title = 'Swap'; - details.description = `Path payment of ${op.amount} ${handleAssetText(op)}`; + details.title = t('swap'); + details.description = t('pathPaymentDescription', { + amount: op.amount, + asset: handleAssetText(op), + }); } result.push(details); @@ -91,11 +95,11 @@ const Activity: React.FC = () => {
{loading ? (
- Loading activity... + {t('loadingActivity')}
) : isEmpty ? (
- No activity found + {t('noActivityFound')}
) : ( transactionsDetails.map((tx, index) => ( @@ -126,7 +130,7 @@ const Activity: React.FC = () => { size="medium" onClick={handleGoToExplorer} > - See all in explorer + {t('seeAllInExplorer')}
)} diff --git a/src/containers/Pages/ConfirmCode/index.tsx b/src/containers/Pages/ConfirmCode/index.tsx index fa2ffc9..25e9307 100644 --- a/src/containers/Pages/ConfirmCode/index.tsx +++ b/src/containers/Pages/ConfirmCode/index.tsx @@ -1,12 +1,14 @@ import React, { useState, useEffect } from 'react'; -import { EmailIcon } from '../../../assets/Icons'; +import { useLang } from '../../../hooks/useLang'; import Button from '../../../components/Button'; +import { EmailIcon } from '../../../assets/Icons'; import { useProvider } from '../../../context/provider'; import OTPInput from '../../../components/Input/OTPInput'; const ConfirmCode: React.FC = () => { const { value } = useProvider(); const appearance = value.config.appearance; + const t = useLang(); const email = value.user.email; const [otp, setOtp] = useState(Array(6).fill('')); @@ -36,7 +38,7 @@ const ConfirmCode: React.FC = () => { }, [otp, email]); return ( -
+
{

- Enter confirmation code + {t('enterConfirmationCodeTitle')}

{error ? (

- Invalid code, please try again. + {t('invalidCodeError')}

) : (

- Please check your email and enter confirmation code below + {t('enterConfirmationCodeHelp')}

)}
@@ -71,7 +73,7 @@ const ConfirmCode: React.FC = () => { {/* divider */}
{ color: appearance.accent, }} > - Resend code + {t('resendCode')}
); diff --git a/src/containers/Pages/OnBoarding/index.tsx b/src/containers/Pages/OnBoarding/index.tsx index 1392c8f..8632908 100644 --- a/src/containers/Pages/OnBoarding/index.tsx +++ b/src/containers/Pages/OnBoarding/index.tsx @@ -2,6 +2,7 @@ import React, { useState, useMemo } from 'react'; import CardItem from '../../../components/CardItem'; import handleLogos from '../../../utils/handleLogos'; +import { useLang } from '../../../hooks/useLang'; import { useProvider } from '../../../context/provider'; import { Routes, WalletInterface } from '../../../types'; import getContrastColor from '../../../utils/getContrastColor'; @@ -12,6 +13,7 @@ import isBackgroundDark from '../../../utils/isBackgroundDark'; const OnBoarding = () => { const { value, setValue, setRoute } = useProvider(); + const t = useLang(); const [inputValue, setInputValue] = useState(''); const wallets = value.availableWallets; @@ -88,7 +90,7 @@ const OnBoarding = () => { color: appearance.borderColor, }} > - or + {t('or')}
); @@ -143,7 +145,7 @@ const OnBoarding = () => { {hiddenWallets.length > 0 && !value.showAllWallets && ( { className="bluxcc:mt-6! bluxcc:flex bluxcc:h-4 bluxcc:cursor-pointer bluxcc:items-center bluxcc:justify-center bluxcc:text-sm bluxcc:leading-[28px] bluxcc:font-medium" style={{ color: appearance.accent }} > - Log in with Passkey + {t('logInWithPasskey')}{' '}
); } @@ -200,17 +202,17 @@ const OnBoarding = () => {
diff --git a/src/containers/Pages/Profile/index.tsx b/src/containers/Pages/Profile/index.tsx index a273621..ed61ebf 100644 --- a/src/containers/Pages/Profile/index.tsx +++ b/src/containers/Pages/Profile/index.tsx @@ -2,6 +2,7 @@ import React, { useState } from 'react'; import { Routes } from '../../../types'; import copyText from '../../../utils/copyText'; +import { useLang } from '../../../hooks/useLang'; import { useBlux } from '../../../hooks/useBlux'; import CardItem from '../../../components/CardItem'; import { useProvider } from '../../../context/provider'; @@ -11,6 +12,7 @@ import { Copy, History, LogOut, Send } from '../../../assets/Icons'; const Profile = () => { const { logout } = useBlux(); + const t = useLang(); const context = useProvider(); const [copied, setCopied] = useState(false); @@ -30,13 +32,13 @@ const Profile = () => { setCopied(false); }, 1000); }) - .catch(() => { }); + .catch(() => {}); }; const balance = context.value.account.account ? context.value.account.account.balances.find( - (b) => b.asset_type === 'native', - )?.balance + (b) => b.asset_type === 'native', + )?.balance : '0'; return ( @@ -51,7 +53,7 @@ const Profile = () => { style={{ color: appearance.textColor }} > {copied ? ( - 'Copied!' + t('copied') ) : ( {address ? shortenAddress(address, 5) : ''} @@ -63,13 +65,13 @@ const Profile = () => { className="bluxcc:text-center bluxcc:text-base" style={{ color: appearance.accent }} > - {balance ? `${humanizeAmount(balance)} XLM` : 'Loading...'} + {balance ? `${humanizeAmount(balance)} XLM` : t('loading')}

} onClick={() => { context.setRoute(Routes.SEND); @@ -78,7 +80,7 @@ const Profile = () => { } onClick={() => { context.setRoute(Routes.ACTIVITY); @@ -104,7 +106,7 @@ const Profile = () => { className="bluxcc:flex bluxcc:h-12 bluxcc:w-full bluxcc:cursor-pointer bluxcc:items-center bluxcc:justify-center bluxcc:gap-2" > - Logout + {t('logout')}
); diff --git a/src/containers/Pages/SelectAsset/index.tsx b/src/containers/Pages/SelectAsset/index.tsx index 2f2de03..1232014 100644 --- a/src/containers/Pages/SelectAsset/index.tsx +++ b/src/containers/Pages/SelectAsset/index.tsx @@ -2,6 +2,7 @@ import React, { useState, MouseEvent, ChangeEvent } from 'react'; import { IAsset } from '../../../types'; import { Search } from '../../../assets/Icons'; +import { useLang } from '../../../hooks/useLang'; import { useProvider } from '../../../context/provider'; import humanizeAmount from '../../../utils/humanizeAmount'; @@ -17,6 +18,7 @@ const SelectAssets = ({ setShowSelectAssetPage, }: SelectAssetsProps) => { const context = useProvider(); + const t = useLang(); const appearance = context.value.config.appearance; const [isFocused, setIsFocused] = useState(false); const [searchQuery, setSearchQuery] = useState(''); @@ -46,7 +48,7 @@ const SelectAssets = ({ }; if (context.value.account.loading) { - return
Loading
; + return
{t('loading')}
; } return ( @@ -76,7 +78,7 @@ const SelectAssets = ({ ) => setSearchQuery(e.target.value) @@ -135,7 +137,7 @@ const SelectAssets = ({ style={{ color: appearance.textColor }} className="bluxcc:mt-2 bluxcc:text-center" > - No assets found + {t('noAssetsFound')}
)} diff --git a/src/containers/Pages/Send/SendForm.tsx b/src/containers/Pages/Send/SendForm.tsx index ab5198f..b782767 100644 --- a/src/containers/Pages/Send/SendForm.tsx +++ b/src/containers/Pages/Send/SendForm.tsx @@ -11,6 +11,7 @@ import { StellarSmallLogo } from '../../../assets/logos'; import getContrastColor from '../../../utils/getContrastColor'; import paymentTransaction from '../../../utils/stellar/paymentTransaction'; import { StrKey } from '@stellar/stellar-sdk'; +import { useLang } from '../../../hooks/useLang'; type SendFormValues = { memo: string; @@ -19,6 +20,7 @@ type SendFormValues = { }; const SendForm = () => { + const t = useLang(); const { value, setValue } = useProvider(); const { sendTransaction } = useBlux(); const [errors, setErrors] = useState>({}); @@ -85,15 +87,15 @@ const SendForm = () => { const errorMessages: typeof errors = {}; if (!form.amount) { - errorMessages.amount = 'Amount is required'; + errorMessages.amount = t('amountRequired'); } else if (Number(form.amount) > Number(selectedAsset.balance)) { - errorMessages.amount = 'Amount is greater than max balance'; + errorMessages.amount = t('amountExceedsBalance'); } if (!form.address) { - errorMessages.address = 'Address is required'; + errorMessages.address = t('addressRequired'); } else if (!StrKey.isValidEd25519PublicKey(form.address)) { - errorMessages.address = 'Address is invalid'; + errorMessages.address = t('addressInvalid'); } setErrors(errorMessages); @@ -143,7 +145,7 @@ const SendForm = () => { { style={{ color: appearance.accent }} className="bluxcc:mr-2 bluxcc:inline-flex bluxcc:cursor-pointer" > - Max + {t('max')} } onButtonClick={handleOpenAssets} @@ -173,20 +175,20 @@ const SendForm = () => {
@@ -211,7 +213,7 @@ const SendForm = () => { state="enabled" onClick={handleSubmit} > - Send + {t('sendButton')}
diff --git a/src/containers/Pages/Send/index.tsx b/src/containers/Pages/Send/index.tsx index 949c38b..9657f4a 100644 --- a/src/containers/Pages/Send/index.tsx +++ b/src/containers/Pages/Send/index.tsx @@ -1,19 +1,20 @@ import React from 'react'; import { useProvider } from '../../../context/provider'; +import { useLang } from '../../../hooks/useLang'; import SendForm from './SendForm'; const Send = () => { const { value } = useProvider(); - + const t = useLang(); const { account, loading } = value.account; if (loading) { - return

Loading

; + return

{t('loading')}

; } if (!account) { - return

Account is inactive

; + return

{t('inactiveAccount')}

; } return ; diff --git a/src/containers/Pages/SignTransaction/index.tsx b/src/containers/Pages/SignTransaction/index.tsx index 64698c9..8dc56f7 100644 --- a/src/containers/Pages/SignTransaction/index.tsx +++ b/src/containers/Pages/SignTransaction/index.tsx @@ -10,8 +10,10 @@ import shortenAddress from '../../../utils/shortenAddress'; import Summary from '../../../components/Transaction/Summary'; import getActiveNetworkTitle from '../../../utils/network/getNetworkTitle'; import getTransactionDetails from '../../../utils/stellar/getTransactionDetails'; +import { useLang } from '../../../hooks/useLang'; const SignTransaction = () => { + const t = useLang(); const context = useProvider(); const { balance } = useBalance({ asset: 'native' }); @@ -33,7 +35,7 @@ const SignTransaction = () => { if (!txDetails) { return (
-

Invalid XDR

+

{t('invalidXdr')}

); } @@ -47,7 +49,7 @@ const SignTransaction = () => { {context.value.config.appName}{' '} - wants your permission to approve the following transaction. + {t('signTransactionPrompt')}

{ {isLobstr && (

- Ensure that your LOBSTR wallet is set to the {networkTitle} network. - Otherwise, the transaction will definitely fail. + {t('lobstrWarning', { network: networkTitle })}

)} @@ -76,7 +77,7 @@ const SignTransaction = () => { >

- Your wallet + {t('yourWallet')}

{ > {context.value.user.wallet?.address ? shortenAddress(context.value.user.wallet.address as string, 5) - : 'No address found'} + : t('noAddressFound')}

{ variant="fill" onClick={handleSignTx} > - Approve + {t('approve')}
); diff --git a/src/containers/Pages/Successful/index.tsx b/src/containers/Pages/Successful/index.tsx index 24a3fca..07dcf53 100644 --- a/src/containers/Pages/Successful/index.tsx +++ b/src/containers/Pages/Successful/index.tsx @@ -6,9 +6,11 @@ import { useProvider } from '../../../context/provider'; import getExplorerUrl from '../../../utils/stellar/getExplorerUrl'; import capitalizeFirstLetter from '../../../utils/capitalizeFirstLetter'; import { Horizon, rpc } from '@stellar/stellar-sdk'; +import { useLang } from '../../../hooks/useLang'; const Successful = () => { const context = useProvider(); + const t = useLang(); const waitingStatus = context.value.waitingStatus; const appearance = context.value.config.appearance; const { result, options } = context.value.signTransaction; @@ -71,20 +73,23 @@ const Successful = () => { }; return ( -
+

- {waitingStatus === 'connecting' ? 'Connection' : 'Transaction'}{' '} - Successful + {waitingStatus === 'connecting' + ? t('connectionSuccessfulTitle') + : t('transactionSuccessfulTitle')}

{waitingStatus === 'connecting' - ? `Your account has been successfully connected to ${capitalizeFirstLetter(context.value.config.appName)}` - : 'Your transaction was successfully completed'} + ? t('connectionSuccessfulMessage', { + appName: capitalizeFirstLetter(context.value.config.appName), + }) + : t('transactionSuccessfulMessage')}

{waitingStatus === 'signing' && @@ -97,14 +102,14 @@ const Successful = () => { className="mt-4" onClick={handleGoToExplorer} > - See in explorer + {t('seeInExplorer')} )} {/* divider */}
{ variant="outline" className="bluxcc:cursor-default!" > - Logging In + {t('loggingIn')} ) : ( )}
diff --git a/src/containers/Pages/Waiting/index.tsx b/src/containers/Pages/Waiting/index.tsx index 4bb8545..6e65dce 100644 --- a/src/containers/Pages/Waiting/index.tsx +++ b/src/containers/Pages/Waiting/index.tsx @@ -9,9 +9,11 @@ import isBackgroundDark from '../../../utils/isBackgroundDark'; import { Loading, RedExclamation } from '../../../assets/Icons'; import { setRecentConnectionMethod } from '../../../utils/setRecentConnectionMethod'; import handleTransactionSigning from '../../../utils/stellar/handleTransactionSigning'; +import { useLang } from '../../../hooks/useLang'; const Waiting = () => { const context = useProvider(); + const t = useLang(); const hasConnected = useRef(false); const [error, setError] = useState(false); const [matchedWallet, setMatchedWallet] = useState( @@ -107,7 +109,7 @@ const Waiting = () => { }; return ( -
+
{error ? (
{

{error - ? `${waitingStatus === 'connecting' - ? 'Login failed' - : `Signing with ${user?.wallet?.name} failed` - }` - : `${waitingStatus === 'connecting' ? 'Waiting for' : `Signing with` - } ${user?.wallet?.name}`} + ? waitingStatus === 'connecting' + ? t('loginFailed') + : t('signingFailed', { + walletName: user?.wallet?.name ?? 'wallet', + }) + : waitingStatus === 'connecting' + ? t('waitingFor', { walletName: user?.wallet?.name ?? 'wallet' }) + : t('signingWith', { + walletName: user?.wallet?.name ?? 'wallet', + })}

{error - ? `Please try ${waitingStatus === 'connecting' ? 'logging in' : 'signing'} again.` - : `${waitingStatus === 'connecting' - ? 'Accept connection' - : 'Sign the' - } request in your wallet`} + ? waitingStatus === 'connecting' + ? t('loginRetryMessage') + : t('signingRetryMessage') + : waitingStatus === 'connecting' + ? t('acceptConnection') + : t('signRequestInWallet')}

{/* divider */}
{ {error ? ( ) : ( )}
diff --git a/src/containers/Pages/WrongNetwork/index.tsx b/src/containers/Pages/WrongNetwork/index.tsx index c47fbda..69e8047 100644 --- a/src/containers/Pages/WrongNetwork/index.tsx +++ b/src/containers/Pages/WrongNetwork/index.tsx @@ -1,13 +1,13 @@ import React from 'react'; +import { useLang } from '../../../hooks/useLang'; const WrongNetwork = () => { + const t = useLang(); return (
-

You are on a wrong network.

+

{t('wrongNetworkMessage')}

- ) - + ); }; export default WrongNetwork; - diff --git a/src/context/provider.tsx b/src/context/provider.tsx index 1427eac..45386db 100644 --- a/src/context/provider.tsx +++ b/src/context/provider.tsx @@ -76,7 +76,7 @@ export const BluxProvider = ({ config: { ...config, explorer: config.explorer || 'stellarchain', - lang: 'en', + lang: config.lang, appearance: { ...defaultLightTheme, ...config.appearance,