diff --git a/eslint.config.js b/eslint.config.js index 4a7aa6fb04..43394020d5 100644 --- a/eslint.config.js +++ b/eslint.config.js @@ -141,6 +141,21 @@ module.exports = [ message: "Don't pass { history: 'push' } to nuqs useQueryState(s) — a history entry per URL write breaks the back button (useSafeBack steps through same-screen states instead of leaving). Use the default 'replace'; the URL stays shareable. If a flow genuinely needs push-per-step, add a scoped file exemption with a comment (see useNativePlugins).", }, + { + // Toast copy must come from next-intl. `react/jsx-no-literals` below + // only inspects JSX children, so toasts fired from hooks and contexts + // (authContext, useLogin, useSendMoney, QRScanner) shipped English to + // every locale unnoticed. + // + // Deliberately NOT extended to `throw new Error('…')`: those messages + // are developer/Sentry breadcrumbs that the friendly-error mapper + // collapses to `errors.genericSupport` before any user sees them, so + // translating them would only fragment Sentry issue grouping. + selector: + "CallExpression[callee.object.name='toast'][callee.property.name=/^(error|success|info|warning|loading)$/] > :matches(Literal, TemplateLiteral):first-child", + message: + "Don't pass a string literal to toast.* — copy must come from next-intl. Import the right namespace with useTranslations and pass t('…'). If the value genuinely isn't copy (an id, a URL), assign it to a named const first.", + }, ], }, }, diff --git a/src/app/(mobile-ui)/add-money/__tests__/add-money-states.test.tsx b/src/app/(mobile-ui)/add-money/__tests__/add-money-states.test.tsx index 1c9e6f0c0a..467d5cf4ad 100644 --- a/src/app/(mobile-ui)/add-money/__tests__/add-money-states.test.tsx +++ b/src/app/(mobile-ui)/add-money/__tests__/add-money-states.test.tsx @@ -16,8 +16,8 @@ /* eslint-disable @typescript-eslint/no-explicit-any, @typescript-eslint/no-unused-vars, react/display-name */ import React from 'react' import { render, screen, fireEvent, waitFor, act } from '@testing-library/react' +import { IntlWrapper } from '@/test-utils/intl' import { QueryClient, QueryClientProvider } from '@tanstack/react-query' -import { NextIntlClientProvider } from 'next-intl' import en from '@/i18n/app/messages/en.json' // ---------- module-level mocks (must be before imports that depend on them) ---------- @@ -897,9 +897,9 @@ function createQueryClient() { function renderWithProviders(component: React.ReactElement) { const queryClient = createQueryClient() return render( - + {component} - + ) } diff --git a/src/app/(mobile-ui)/qr-pay/__tests__/qr-pay-states.test.tsx b/src/app/(mobile-ui)/qr-pay/__tests__/qr-pay-states.test.tsx index 09d93db3ad..742d730b96 100644 --- a/src/app/(mobile-ui)/qr-pay/__tests__/qr-pay-states.test.tsx +++ b/src/app/(mobile-ui)/qr-pay/__tests__/qr-pay-states.test.tsx @@ -10,9 +10,8 @@ import React from 'react' import posthog from 'posthog-js' import { render, screen, fireEvent, waitFor, act } from '@testing-library/react' +import { IntlWrapper } from '@/test-utils/intl' import { QueryClient, QueryClientProvider } from '@tanstack/react-query' -import { NextIntlClientProvider } from 'next-intl' -import en from '@/i18n/app/messages/en.json' import { parseUnits } from 'viem' import type { RailCapability } from '@/types/capabilities' @@ -536,13 +535,13 @@ function renderQrPay(params: Record = {}) { } return render( - + - + ) } diff --git a/src/app/(mobile-ui)/receipt/page.tsx b/src/app/(mobile-ui)/receipt/page.tsx index 4c64cccea0..9c99cb1a2e 100644 --- a/src/app/(mobile-ui)/receipt/page.tsx +++ b/src/app/(mobile-ui)/receipt/page.tsx @@ -53,7 +53,7 @@ export default function NativeReceiptPage() { return (
- +
{isLoading || !entry ? ( diff --git a/src/app/(mobile-ui)/withdraw/__tests__/withdraw-states.test.tsx b/src/app/(mobile-ui)/withdraw/__tests__/withdraw-states.test.tsx index 289a25f3e9..356ccb7c75 100644 --- a/src/app/(mobile-ui)/withdraw/__tests__/withdraw-states.test.tsx +++ b/src/app/(mobile-ui)/withdraw/__tests__/withdraw-states.test.tsx @@ -9,9 +9,8 @@ */ import React from 'react' import { render, screen, fireEvent, waitFor } from '@testing-library/react' +import { IntlWrapper } from '@/test-utils/intl' import { QueryClient, QueryClientProvider } from '@tanstack/react-query' -import { NextIntlClientProvider } from 'next-intl' -import en from '@/i18n/app/messages/en.json' import { parseUnits } from 'viem' // ---------- module-level mocks (must be before imports that depend on them) ---------- @@ -226,11 +225,11 @@ function renderWithdraw(params: Record = {}) { setSearchParams(params) const queryClient = createQueryClient() return render( - + - + ) } diff --git a/src/app/(mobile-ui)/withdraw/crypto/__tests__/crypto-withdraw-confirm.test.tsx b/src/app/(mobile-ui)/withdraw/crypto/__tests__/crypto-withdraw-confirm.test.tsx index 563047ffbf..12a16931d1 100644 --- a/src/app/(mobile-ui)/withdraw/crypto/__tests__/crypto-withdraw-confirm.test.tsx +++ b/src/app/(mobile-ui)/withdraw/crypto/__tests__/crypto-withdraw-confirm.test.tsx @@ -14,8 +14,7 @@ */ import React from 'react' import { render as rtlRender, screen, fireEvent, waitFor } from '@testing-library/react' -import { NextIntlClientProvider } from 'next-intl' -import enMessages from '@/i18n/app/messages/en.json' +import { IntlWrapper } from '@/test-utils/intl' // ---------- module-level mocks ---------- @@ -252,12 +251,6 @@ jest.mock('@/features/payments/shared/hooks/usePaymentRecorder', () => ({ import WithdrawCryptoPage from '../page' -const IntlWrapper = ({ children }: { children: React.ReactNode }) => ( - - {children} - -) - const render = (ui: React.ReactElement, options?: Omit[1], 'wrapper'>) => rtlRender(ui, { wrapper: IntlWrapper, ...options }) diff --git a/src/app/receipt/[entryId]/page.tsx b/src/app/receipt/[entryId]/page.tsx index 68a4131f33..3514d97d9a 100644 --- a/src/app/receipt/[entryId]/page.tsx +++ b/src/app/receipt/[entryId]/page.tsx @@ -192,7 +192,7 @@ export default async function ReceiptPage({ return (
- +
diff --git a/src/components/AddMoney/components/__tests__/MantecaAddMoney.test.tsx b/src/components/AddMoney/components/__tests__/MantecaAddMoney.test.tsx index 4bd9f4f8f4..98c143596e 100644 --- a/src/components/AddMoney/components/__tests__/MantecaAddMoney.test.tsx +++ b/src/components/AddMoney/components/__tests__/MantecaAddMoney.test.tsx @@ -11,17 +11,10 @@ */ import React from 'react' import { render as rtlRender, screen } from '@testing-library/react' -import { NextIntlClientProvider } from 'next-intl' -import enMessages from '@/i18n/app/messages/en.json' +import { IntlWrapper } from '@/test-utils/intl' // jest.mock calls are hoisted above this import, so the mocks below apply to it import MantecaAddMoney from '../MantecaAddMoney' -const IntlWrapper = ({ children }: { children: React.ReactNode }) => ( - - {children} - -) - const render = (ui: React.ReactElement, options?: Omit[1], 'wrapper'>) => rtlRender(ui, { wrapper: IntlWrapper, ...options }) diff --git a/src/components/AddMoney/components/__tests__/MantecaPixQrDeposit.test.tsx b/src/components/AddMoney/components/__tests__/MantecaPixQrDeposit.test.tsx index 0a80826169..5149804217 100644 --- a/src/components/AddMoney/components/__tests__/MantecaPixQrDeposit.test.tsx +++ b/src/components/AddMoney/components/__tests__/MantecaPixQrDeposit.test.tsx @@ -8,15 +8,9 @@ */ import React from 'react' import { render as rtlRender, screen } from '@testing-library/react' -import { NextIntlClientProvider } from 'next-intl' -import en from '@/i18n/app/messages/en.json' +import { IntlWrapper } from '@/test-utils/intl' -const render = (ui: React.ReactElement) => - rtlRender( - - {ui} - - ) +const render = (ui: React.ReactElement) => rtlRender({ui}) const mockUseMantecaDepositPolling = jest.fn() jest.mock('@/components/AddMoney/hooks/useMantecaDepositPolling', () => ({ diff --git a/src/components/AddWithdraw/__tests__/AddWithdrawCountriesList.test.tsx b/src/components/AddWithdraw/__tests__/AddWithdrawCountriesList.test.tsx index ede4199b00..832a3d3acf 100644 --- a/src/components/AddWithdraw/__tests__/AddWithdrawCountriesList.test.tsx +++ b/src/components/AddWithdraw/__tests__/AddWithdrawCountriesList.test.tsx @@ -16,17 +16,11 @@ */ import React from 'react' import { render as rtlRender, screen, fireEvent, within } from '@testing-library/react' -import { NextIntlClientProvider } from 'next-intl' -import en from '@/i18n/app/messages/en.json' +import { IntlWrapper } from '@/test-utils/intl' import AddWithdrawCountriesList from '../AddWithdrawCountriesList' import underMaintenanceConfig from '@/config/underMaintenance.config' -const render = (ui: React.ReactElement) => - rtlRender( - - {ui} - - ) +const render = (ui: React.ReactElement) => rtlRender({ui}) // ---- routing ---- const mockPush = jest.fn() diff --git a/src/components/AddWithdraw/__tests__/AddWithdrawRouterView.test.tsx b/src/components/AddWithdraw/__tests__/AddWithdrawRouterView.test.tsx index 00f5d81235..28eef3d5e1 100644 --- a/src/components/AddWithdraw/__tests__/AddWithdrawRouterView.test.tsx +++ b/src/components/AddWithdraw/__tests__/AddWithdrawRouterView.test.tsx @@ -13,8 +13,7 @@ */ import React, { useEffect } from 'react' import { render, screen, fireEvent } from '@testing-library/react' -import { NextIntlClientProvider } from 'next-intl' -import en from '@/i18n/app/messages/en.json' +import { IntlWrapper } from '@/test-utils/intl' const mockRouterPush = jest.fn() jest.mock('next/navigation', () => ({ @@ -137,12 +136,12 @@ function SelectedMethodProbe() { function Harness({ user }: { user: MockUser }) { mockUser = user return ( - + - + ) } diff --git a/src/components/Badges/__tests__/BadgeEarnToast.test.tsx b/src/components/Badges/__tests__/BadgeEarnToast.test.tsx index 033af47fcd..ff556bf1c1 100644 --- a/src/components/Badges/__tests__/BadgeEarnToast.test.tsx +++ b/src/components/Badges/__tests__/BadgeEarnToast.test.tsx @@ -1,14 +1,8 @@ import { render as rtlRender, screen, act } from '@testing-library/react' -import type { ComponentProps, ReactNode } from 'react' -import { NextIntlClientProvider } from 'next-intl' -import en from '@/i18n/app/messages/en.json' +import { IntlWrapper } from '@/test-utils/intl' +import type { ComponentProps } from 'react' import BadgeEarnToast from '@/components/Badges/BadgeEarnToast' -const IntlWrapper = ({ children }: { children: ReactNode }) => ( - - {children} - -) const render = (ui: Parameters[0]) => rtlRender(ui, { wrapper: IntlWrapper }) // next/navigation — mutable pathname so we can exercise the /home gate; stable diff --git a/src/components/Badges/__tests__/BadgesRow.test.tsx b/src/components/Badges/__tests__/BadgesRow.test.tsx index b78cb2755a..fb79e5560f 100644 --- a/src/components/Badges/__tests__/BadgesRow.test.tsx +++ b/src/components/Badges/__tests__/BadgesRow.test.tsx @@ -1,16 +1,9 @@ import { render as rtlRender } from '@testing-library/react' +import { IntlWrapper } from '@/test-utils/intl' import React from 'react' -import { NextIntlClientProvider } from 'next-intl' -import enMessages from '@/i18n/app/messages/en.json' import type { ComponentProps } from 'react' import BadgesRow from '@/components/Badges/BadgesRow' -const IntlWrapper = ({ children }: { children: React.ReactNode }) => ( - - {children} - -) - const render = (ui: React.ReactElement, options?: Omit[1], 'wrapper'>) => rtlRender(ui, { wrapper: IntlWrapper, ...options }) diff --git a/src/components/Card/__tests__/ApplicationStatusScreen.test.tsx b/src/components/Card/__tests__/ApplicationStatusScreen.test.tsx index 2f3bddf37c..6a655b7f24 100644 --- a/src/components/Card/__tests__/ApplicationStatusScreen.test.tsx +++ b/src/components/Card/__tests__/ApplicationStatusScreen.test.tsx @@ -9,15 +9,10 @@ */ import React from 'react' import { render as rtlRender, screen, fireEvent } from '@testing-library/react' -import { NextIntlClientProvider } from 'next-intl' +import { IntlWrapper } from '@/test-utils/intl' import en from '@/i18n/app/messages/en.json' import ApplicationStatusScreen from '@/components/Card/ApplicationStatusScreen' -const IntlWrapper = ({ children }: { children: React.ReactNode }) => ( - - {children} - -) const render = (ui: React.ReactElement) => rtlRender(ui, { wrapper: IntlWrapper }) // NavHeader reads useAuth; stub it so the presentational screen renders alone. diff --git a/src/components/Card/__tests__/CardCountryConfirmScreen.test.tsx b/src/components/Card/__tests__/CardCountryConfirmScreen.test.tsx index eb41b18d79..ac55ddde16 100644 --- a/src/components/Card/__tests__/CardCountryConfirmScreen.test.tsx +++ b/src/components/Card/__tests__/CardCountryConfirmScreen.test.tsx @@ -10,15 +10,9 @@ */ import React from 'react' import { render as rtlRender, screen, fireEvent, waitFor } from '@testing-library/react' -import { NextIntlClientProvider } from 'next-intl' -import en from '@/i18n/app/messages/en.json' +import { IntlWrapper } from '@/test-utils/intl' import CardCountryConfirmScreen from '@/components/Card/CardCountryConfirmScreen' -const IntlWrapper = ({ children }: { children: React.ReactNode }) => ( - - {children} - -) const render = (ui: React.ReactElement) => rtlRender(ui, { wrapper: IntlWrapper }) // NavHeader reads useAuth; stub it so the presentational screen renders alone. diff --git a/src/components/Card/__tests__/CardFace.test.tsx b/src/components/Card/__tests__/CardFace.test.tsx index 5624667e16..83516ac401 100644 --- a/src/components/Card/__tests__/CardFace.test.tsx +++ b/src/components/Card/__tests__/CardFace.test.tsx @@ -8,15 +8,9 @@ */ import React from 'react' import { render as rtlRender, screen } from '@testing-library/react' -import { NextIntlClientProvider } from 'next-intl' -import en from '@/i18n/app/messages/en.json' +import { IntlWrapper } from '@/test-utils/intl' import CardFace, { type RevealedCardDetails } from '@/components/Card/CardFace' -const IntlWrapper = ({ children }: { children: React.ReactNode }) => ( - - {children} - -) const render = (ui: React.ReactElement) => rtlRender(ui, { wrapper: IntlWrapper }) const revealed: RevealedCardDetails = { diff --git a/src/components/Card/__tests__/PhysicalCardScreen.test.tsx b/src/components/Card/__tests__/PhysicalCardScreen.test.tsx index 5dfb9c8f27..95a0d1e1f4 100644 --- a/src/components/Card/__tests__/PhysicalCardScreen.test.tsx +++ b/src/components/Card/__tests__/PhysicalCardScreen.test.tsx @@ -7,18 +7,11 @@ */ import React from 'react' import { render as rtlRender, screen } from '@testing-library/react' -import { NextIntlClientProvider } from 'next-intl' -import enMessages from '@/i18n/app/messages/en.json' +import { IntlWrapper } from '@/test-utils/intl' import { QueryClient, QueryClientProvider } from '@tanstack/react-query' import PhysicalCardScreen from '@/components/Card/PhysicalCardScreen' import { rainApi } from '@/services/rain' -const IntlWrapper = ({ children }: { children: React.ReactNode }) => ( - - {children} - -) - const render = (ui: React.ReactElement, options?: Omit[1], 'wrapper'>) => rtlRender(ui, { wrapper: IntlWrapper, ...options }) diff --git a/src/components/Claim/Link/__tests__/SendLinkActionList.test.tsx b/src/components/Claim/Link/__tests__/SendLinkActionList.test.tsx index af26bf0040..5a627b90c2 100644 --- a/src/components/Claim/Link/__tests__/SendLinkActionList.test.tsx +++ b/src/components/Claim/Link/__tests__/SendLinkActionList.test.tsx @@ -8,8 +8,7 @@ */ import React from 'react' import { render, screen, fireEvent } from '@testing-library/react' -import { NextIntlClientProvider } from 'next-intl' -import en from '@/i18n/app/messages/en.json' +import { IntlWrapper } from '@/test-utils/intl' // ---------- module-level mocks (before importing the component) ---------- @@ -129,9 +128,9 @@ const claimLinkData = { function renderList() { return render( - + - + ) } diff --git a/src/components/Claim/__tests__/claim-states.test.tsx b/src/components/Claim/__tests__/claim-states.test.tsx index 7672a923a1..1e4f07a9f2 100644 --- a/src/components/Claim/__tests__/claim-states.test.tsx +++ b/src/components/Claim/__tests__/claim-states.test.tsx @@ -10,9 +10,8 @@ */ import React from 'react' import { render, screen, waitFor } from '@testing-library/react' +import { IntlWrapper } from '@/test-utils/intl' import { QueryClient, QueryClientProvider } from '@tanstack/react-query' -import { NextIntlClientProvider } from 'next-intl' -import en from '@/i18n/app/messages/en.json' // ---------- module-level mocks (must be before imports that depend on them) ---------- @@ -241,11 +240,11 @@ function createQueryClient() { function renderClaim() { const queryClient = createQueryClient() return render( - + - + ) } diff --git a/src/components/Global/BackendErrorScreen/index.tsx b/src/components/Global/BackendErrorScreen/index.tsx index 1cc3b9db23..3a99e6f00e 100644 --- a/src/components/Global/BackendErrorScreen/index.tsx +++ b/src/components/Global/BackendErrorScreen/index.tsx @@ -8,14 +8,8 @@ import posthog from 'posthog-js' import { ANALYTICS_EVENTS } from '@/constants/analytics.consts' // inline peanut icon svg to ensure it works without needing to fetch external assets -const PeanutIcon = ({ className }: { className?: string }) => ( - +const PeanutIcon = ({ className, label }: { className?: string; label: string }) => ( + {/* peanut shape */} ( */ export default function BackendErrorScreen() { const t = useTranslations('global') + const tNav = useTranslations('navigation') const { logoutUser, isLoggingOut } = useAuth() useEffect(() => { @@ -91,7 +86,7 @@ export default function BackendErrorScreen() { return (
- +

{t('backendErrorScreen.title')}

diff --git a/src/components/Global/Banner/index.tsx b/src/components/Global/Banner/index.tsx index dcab401801..282ff7ca2f 100644 --- a/src/components/Global/Banner/index.tsx +++ b/src/components/Global/Banner/index.tsx @@ -81,7 +81,7 @@ function FeedbackBanner() { {t('betaBanner')} - Thumbs up + {t('betaBannerThumbsUpAlt')} {!IS_PRODUCTION && version: {GIT_COMMIT_HASH}} {mode && ( // High-contrast yellow-on-black pill. Visually impossible diff --git a/src/components/Global/EasterEggModal/index.tsx b/src/components/Global/EasterEggModal/index.tsx index 7bec5f4375..1600b08db3 100644 --- a/src/components/Global/EasterEggModal/index.tsx +++ b/src/components/Global/EasterEggModal/index.tsx @@ -55,7 +55,7 @@ const EasterEggModal = ({ visible, onClose, countryCode }: EasterEggModalProps) icon={ Easter egg ( - - {children} - -) const render = (ui: Parameters[0]) => rtlRender(ui, { wrapper: IntlWrapper }) // Test case type definition for better maintainability diff --git a/src/components/Global/NavHeader/index.tsx b/src/components/Global/NavHeader/index.tsx index 9946fd6bce..2c3f5dfd33 100644 --- a/src/components/Global/NavHeader/index.tsx +++ b/src/components/Global/NavHeader/index.tsx @@ -1,4 +1,7 @@ 'use client' +import { useTranslations } from 'next-intl' +// type-only: erased at build, so the catalog is not bundled here +import type enMessages from '@/i18n/app/messages/en.json' import { Button } from '@/components/0_Bruddle/Button' import Link from 'next/link' import { twMerge } from 'tailwind-merge' @@ -9,6 +12,11 @@ interface NavHeaderProps { onPrev?: () => void disableBackBtn?: boolean title?: string + /** Localized title for callers that cannot call useTranslations — i.e. server + * components, since this app has no server-side next-intl setup (locale is + * resolved entirely client-side by AppIntlProvider). Resolved against the + * `navigation` namespace. Prefer plain `title` from client components. */ + titleKey?: keyof typeof enMessages.navigation href?: string hideLabel?: boolean icon?: IconName @@ -18,6 +26,7 @@ interface NavHeaderProps { const NavHeader = ({ title, + titleKey, icon = 'chevron-up', href, hideLabel = false, @@ -27,6 +36,8 @@ const NavHeader = ({ titleClassName, }: NavHeaderProps) => { const { logoutUser, isLoggingOut } = useAuth() + const tNav = useTranslations('navigation') + const label = title ?? (titleKey ? tNav(titleKey) : undefined) return (
@@ -62,7 +73,7 @@ const NavHeader = ({ titleClassName )} > - {title} + {label}
)} diff --git a/src/components/Global/OfflineScreen/index.tsx b/src/components/Global/OfflineScreen/index.tsx index 2f42aec40f..2ed8a67d88 100644 --- a/src/components/Global/OfflineScreen/index.tsx +++ b/src/components/Global/OfflineScreen/index.tsx @@ -6,14 +6,8 @@ import { useTranslations } from 'next-intl' import { useState } from 'react' // inline peanut icon svg to ensure it works offline without needing to fetch external assets -const PeanutIcon = ({ className }: { className?: string }) => ( - +const PeanutIcon = ({ className, label }: { className?: string; label: string }) => ( + {/* */} ( */ export default function OfflineScreen() { const t = useTranslations('global') + const tNav = useTranslations('navigation') const [isChecking, setIsChecking] = useState(false) // verify with a real fetch instead of trusting navigator.onLine @@ -145,7 +140,7 @@ export default function OfflineScreen() { return (
- +

{t('offlineScreen.title')}

diff --git a/src/components/Global/QRScanner/__tests__/index.test.tsx b/src/components/Global/QRScanner/__tests__/index.test.tsx index 0a4e9929d4..38a4d4f173 100644 --- a/src/components/Global/QRScanner/__tests__/index.test.tsx +++ b/src/components/Global/QRScanner/__tests__/index.test.tsx @@ -10,8 +10,7 @@ */ import React from 'react' import { render as rtlRender, screen, fireEvent, waitFor, act } from '@testing-library/react' -import { NextIntlClientProvider } from 'next-intl' -import enMessages from '@/i18n/app/messages/en.json' +import { IntlWrapper } from '@/test-utils/intl' import { Clipboard } from '@capacitor/clipboard' import { clipboardHasStrings } from '@/utils/clipboard-detect' import { isAndroidNative } from '@/utils/capacitor' @@ -47,12 +46,6 @@ jest.mock('../useQRScanner', () => ({ import QRScanner from '../index' -const IntlWrapper = ({ children }: { children: React.ReactNode }) => ( - - {children} - -) - const render = (ui: React.ReactElement, options?: Omit[1], 'wrapper'>) => rtlRender(ui, { wrapper: IntlWrapper, ...options }) diff --git a/src/components/Global/QRScanner/index.tsx b/src/components/Global/QRScanner/index.tsx index 7904f41d67..0a5da03486 100644 --- a/src/components/Global/QRScanner/index.tsx +++ b/src/components/Global/QRScanner/index.tsx @@ -12,7 +12,7 @@ import { useToast } from '@/components/0_Bruddle/Toast' import CameraPermissionModal from './CameraPermissionModal' import { Clipboard } from '@capacitor/clipboard' import { clipboardHasStrings } from '@/utils/clipboard-detect' -import { extractPaymentValue } from '@/utils/clipboard-extract.utils' +import { extractPaymentValue, readClipboard } from '@/utils/clipboard-extract.utils' import { isAndroidNative } from '@/utils/capacitor' import { printableAddress } from '@/utils/general.utils' @@ -20,11 +20,14 @@ import { printableAddress } from '@/utils/general.utils' // Configuration // ============================================================================ +// Brand names stay verbatim — they are proper nouns in every locale. The EVM +// row is the odd one out: its label and alt text are descriptive prose, so it +// carries a key instead and is resolved at render. const PAYMENT_METHODS = [ { src: PEANUTMAN, alt: 'Peanut', name: 'Peanut' }, { src: MERCADO_PAGO, alt: 'Mercado Pago', name: 'Mercado Pago' }, { src: PIX, alt: 'PIX', name: 'PIX' }, - { src: ETHEREUM_ICON, alt: 'Ethereum and EVMs', name: 'ETH & EVMs' }, + { src: ETHEREUM_ICON, alt: null, name: null }, ] as const const CORNER_POSITIONS = [ @@ -124,7 +127,12 @@ function ScanRegionOverlay({
{PAYMENT_METHODS.map((method) => ( - + ))}