From c4282f58701c2db0154196e644cc885ae4100663 Mon Sep 17 00:00:00 2001 From: Kurdistan Tech Ministry Date: Sat, 14 Feb 2026 18:16:08 +0300 Subject: [PATCH] feat(i18n): replace all hardcoded strings with translation calls - Add translation keys for dashboard, send, receive, history, swap, pools, staking, lpStaking, fees, tokens, errors, validation, time, and context sections to types.ts and all 6 language files - Replace hardcoded Kurdish/Turkish strings in all wallet components with useTranslation() hook t() calls - Replace hardcoded strings in non-React files (crypto, utils, error-tracking, wallet-storage, contexts) with standalone translate() - Fix Turkish strings incorrectly used in Kurdish codebase --- package.json | 2 +- src/components/wallet/FundFeesModal.tsx | 56 +++-- src/components/wallet/HEZStakingModal.tsx | 103 ++++---- src/components/wallet/LPStakingModal.tsx | 62 ++--- src/components/wallet/PoolsModal.tsx | 73 +++--- src/components/wallet/SwapModal.tsx | 28 ++- src/components/wallet/TokensCard.tsx | 30 ++- src/components/wallet/WalletDashboard.tsx | 135 +++++----- src/contexts/ReferralContext.tsx | 5 +- src/contexts/WalletContext.tsx | 13 +- src/i18n/index.tsx | 38 +++ src/i18n/translations/ar.ts | 275 +++++++++++++++++++++ src/i18n/translations/ckb.ts | 275 +++++++++++++++++++++ src/i18n/translations/en.ts | 275 +++++++++++++++++++++ src/i18n/translations/fa.ts | 275 +++++++++++++++++++++ src/i18n/translations/krd.ts | 285 ++++++++++++++++++++++ src/i18n/translations/tr.ts | 276 +++++++++++++++++++++ src/i18n/types.ts | 275 +++++++++++++++++++++ src/lib/crypto.ts | 15 +- src/lib/error-tracking.ts | 20 +- src/lib/utils.ts | 20 +- src/lib/wallet-storage.ts | 5 +- src/version.json | 6 +- 23 files changed, 2294 insertions(+), 253 deletions(-) diff --git a/package.json b/package.json index 6312665..a69a13d 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "pezkuwi-telegram-miniapp", - "version": "1.0.189", + "version": "1.0.190", "type": "module", "description": "Pezkuwichain Telegram Mini App - Forum, Announcements, Rewards", "author": "Pezkuwichain Team", diff --git a/src/components/wallet/FundFeesModal.tsx b/src/components/wallet/FundFeesModal.tsx index 3638ecc..470f6c7 100644 --- a/src/components/wallet/FundFeesModal.tsx +++ b/src/components/wallet/FundFeesModal.tsx @@ -16,6 +16,7 @@ import { } from 'lucide-react'; import { useWallet } from '@/contexts/WalletContext'; import { useTelegram } from '@/hooks/useTelegram'; +import { useTranslation } from '@/i18n'; type TargetChain = 'asset-hub' | 'people'; @@ -31,14 +32,14 @@ const TARGET_CHAINS: ChainInfo[] = [ { id: 'asset-hub', name: 'Asset Hub', - description: 'Ji bo PEZ veguheztin', + description: 'fees.forTransfers', teyrchainId: 1000, color: 'blue', }, { id: 'people', name: 'People Chain', - description: 'Ji bo nasname', + description: 'fees.forIdentity', teyrchainId: 1004, color: 'purple', }, @@ -52,6 +53,7 @@ interface Props { export function FundFeesModal({ isOpen, onClose }: Props) { const { api, assetHubApi, peopleApi, address, keypair } = useWallet(); const { hapticImpact, showAlert } = useTelegram(); + const { t } = useTranslation(); const [targetChain, setTargetChain] = useState('asset-hub'); const [toRelay, setToRelay] = useState(false); // false = Relay→Teyrchain, true = Teyrchain→Relay @@ -142,7 +144,7 @@ export function FundFeesModal({ isOpen, onClose }: Props) { const handleTeleport = async () => { if (!address || !keypair) { - showAlert('Cizdan girêdayî nîne'); + showAlert(t('fees.walletNotConnected')); return; } @@ -151,18 +153,18 @@ export function FundFeesModal({ isOpen, onClose }: Props) { const sourceApi: any = toRelay ? (targetChain === 'asset-hub' ? assetHubApi : peopleApi) : api; if (!sourceApi) { - showAlert('API girêdayî nîne'); + showAlert(t('fees.apiNotConnected')); return; } if (!amount || parseFloat(amount) <= 0) { - showAlert('Mîqdarek rast binivîse'); + showAlert(t('fees.enterValidAmount')); return; } const sourceBalance = getSourceBalance(); if (sourceBalance === '--') { - showAlert('Zincîr girêdayî nîne'); + showAlert(t('fees.chainNotConnected')); return; } @@ -170,7 +172,7 @@ export function FundFeesModal({ isOpen, onClose }: Props) { const currentBalance = parseFloat(sourceBalance); if (sendAmount > currentBalance) { - showAlert('Bakiye têrê nake'); + showAlert(t('fees.insufficientBalance')); return; } @@ -282,7 +284,7 @@ export function FundFeesModal({ isOpen, onClose }: Props) { const xcmPallet = toRelay ? (sourceApi.tx as any).pezkuwiXcm : sourceApi.tx.xcmPallet; if (!xcmPallet?.limitedTeleportAssets) { - throw new Error('XCM pallet nehate dîtin'); + throw new Error(t('fees.xcmPalletNotFound')); } const tx = xcmPallet.limitedTeleportAssets( @@ -306,7 +308,7 @@ export function FundFeesModal({ isOpen, onClose }: Props) { }) => { if (status.isFinalized) { if (dispatchError) { - let errorMessage = 'Teleport neserketî'; + let errorMessage = t('fees.teleportFailed'); if (dispatchError.isModule) { const decoded = sourceApi.registry.findMetaError(dispatchError.asModule); @@ -337,7 +339,7 @@ export function FundFeesModal({ isOpen, onClose }: Props) { setTxStatus('error'); setIsTransferring(false); hapticImpact('heavy'); - showAlert(error instanceof Error ? error.message : 'Çewtiyekî çêbû'); + showAlert(error instanceof Error ? error.message : t('fees.errorOccurred')); } }; @@ -361,8 +363,8 @@ export function FundFeesModal({ isOpen, onClose }: Props) {
-

Fee Zêde Bike

-

HEZ teleport

+

{t('fees.title')}

+

{t('fees.subtitle')}

) : (
{/* Target Chain Selection */}
- +
{TARGET_CHAINS.map((chain) => ( ))}
@@ -499,13 +505,15 @@ export function FundFeesModal({ isOpen, onClose }: Props) { targetChain === 'asset-hub' ? 'text-blue-400' : 'text-purple-400' }`} > - {selectedChain.description} kêmî 0.1 HEZ tê pêşniyarkirin. + {t('fees.minRecommended', { description: t(selectedChain.description as any) })}

{/* Amount Input */}
- + -

Danûstandinê îmze bikin...

+

{t('fees.signing')}

)} @@ -545,7 +553,7 @@ export function FundFeesModal({ isOpen, onClose }: Props) {

- XCM Teleport tê çêkirin... + {t('fees.xcmTeleportPending')}

)} @@ -559,12 +567,12 @@ export function FundFeesModal({ isOpen, onClose }: Props) { {isTransferring ? ( <> - {txStatus === 'signing' ? 'Tê îmzekirin...' : 'Tê çêkirin...'} + {txStatus === 'signing' ? t('fees.signingButton') : t('fees.processing')} ) : ( <> - Bo {getDestName()} Bişîne + {t('fees.sendTo', { chain: getDestName() })} )} diff --git a/src/components/wallet/HEZStakingModal.tsx b/src/components/wallet/HEZStakingModal.tsx index e63e1ea..d9e02b8 100644 --- a/src/components/wallet/HEZStakingModal.tsx +++ b/src/components/wallet/HEZStakingModal.tsx @@ -7,6 +7,7 @@ import { useState, useEffect, useCallback } from 'react'; import { X, Lock, Unlock, Users, AlertCircle, Loader2, Shield, TrendingUp } from 'lucide-react'; import { useWallet } from '@/contexts/WalletContext'; import { useTelegram } from '@/hooks/useTelegram'; +import { useTranslation } from '@/i18n'; import { cn } from '@/lib/utils'; interface StakingInfo { @@ -35,6 +36,7 @@ const UNITS = 1_000_000_000_000; // 10^12 export function HEZStakingModal({ isOpen, onClose }: HEZStakingModalProps) { const { api, keypair, address, balance } = useWallet(); const { hapticImpact, hapticNotification, showAlert } = useTelegram(); + const { t } = useTranslation(); const [stakingInfo, setStakingInfo] = useState(null); const [validators, setValidators] = useState([]); @@ -55,7 +57,7 @@ export function HEZStakingModal({ isOpen, onClose }: HEZStakingModalProps) { // eslint-disable-next-line @typescript-eslint/no-explicit-any const stakingPallet = api.query.staking as any; if (!stakingPallet) { - setError('Staking palleti bulunamadı'); + setError(t('staking.palletNotFound')); setIsLoading(false); return; } @@ -114,7 +116,7 @@ export function HEZStakingModal({ isOpen, onClose }: HEZStakingModalProps) { setValidators(validatorList); } catch (err) { console.error('Error fetching staking info:', err); - setError('Staking bilgileri alınamadı'); + setError(t('staking.fetchError')); } finally { setIsLoading(false); } @@ -165,7 +167,7 @@ export function HEZStakingModal({ isOpen, onClose }: HEZStakingModalProps) { }) => { if (status.isFinalized) { if (dispatchError) { - let errorMsg = 'Bond neserketî'; + let errorMsg = t('staking.bondFailed'); if (dispatchError.isModule) { const decoded = api.registry.findMetaError(dispatchError.asModule); errorMsg = `${decoded.section}.${decoded.name}`; @@ -180,13 +182,13 @@ export function HEZStakingModal({ isOpen, onClose }: HEZStakingModalProps) { }); hapticNotification('success'); - showAlert(`${bondAmount} HEZ stake kirin serketî!`); + showAlert(t('staking.bondSuccess', { amount: bondAmount })); setBondAmount(''); fetchStakingInfo(); setActiveTab('status'); } catch (err) { console.error('Bond error:', err); - setError(err instanceof Error ? err.message : 'Bond neserketî'); + setError(err instanceof Error ? err.message : t('staking.bondFailed')); hapticNotification('error'); } finally { setIsProcessing(false); @@ -216,7 +218,7 @@ export function HEZStakingModal({ isOpen, onClose }: HEZStakingModalProps) { }) => { if (status.isFinalized) { if (dispatchError) { - let errorMsg = 'Nominate neserketî'; + let errorMsg = t('staking.nominateFailed'); if (dispatchError.isModule) { const decoded = api.registry.findMetaError(dispatchError.asModule); errorMsg = `${decoded.section}.${decoded.name}`; @@ -231,12 +233,12 @@ export function HEZStakingModal({ isOpen, onClose }: HEZStakingModalProps) { }); hapticNotification('success'); - showAlert(`${selectedValidators.length} validator nominate kirin serketî!`); + showAlert(t('staking.nominateSuccess', { count: selectedValidators.length })); fetchStakingInfo(); setActiveTab('status'); } catch (err) { console.error('Nominate error:', err); - setError(err instanceof Error ? err.message : 'Nominate neserketî'); + setError(err instanceof Error ? err.message : t('staking.nominateFailed')); hapticNotification('error'); } finally { setIsProcessing(false); @@ -268,7 +270,7 @@ export function HEZStakingModal({ isOpen, onClose }: HEZStakingModalProps) { }) => { if (status.isFinalized) { if (dispatchError) { - let errorMsg = 'Unbond neserketî'; + let errorMsg = t('staking.unbondFailed'); if (dispatchError.isModule) { const decoded = api.registry.findMetaError(dispatchError.asModule); errorMsg = `${decoded.section}.${decoded.name}`; @@ -283,13 +285,13 @@ export function HEZStakingModal({ isOpen, onClose }: HEZStakingModalProps) { }); hapticNotification('success'); - showAlert(`${unbondAmount} HEZ unbond kirin serketî! (28 roj li bendê)`); + showAlert(t('staking.unbondSuccess', { amount: unbondAmount })); setUnbondAmount(''); fetchStakingInfo(); setActiveTab('status'); } catch (err) { console.error('Unbond error:', err); - setError(err instanceof Error ? err.message : 'Unbond neserketî'); + setError(err instanceof Error ? err.message : t('staking.unbondFailed')); hapticNotification('error'); } finally { setIsProcessing(false); @@ -330,10 +332,10 @@ export function HEZStakingModal({ isOpen, onClose }: HEZStakingModalProps) { {/* Tabs */}
{[ - { id: 'status' as const, label: 'Durum', icon: TrendingUp }, - { id: 'bond' as const, label: 'Bond', icon: Lock }, - { id: 'nominate' as const, label: 'Nominate', icon: Users }, - { id: 'unbond' as const, label: 'Unbond', icon: Unlock }, + { id: 'status' as const, label: t('staking.statusTab'), icon: TrendingUp }, + { id: 'bond' as const, label: t('staking.bondTab'), icon: Lock }, + { id: 'nominate' as const, label: t('staking.nominateTab'), icon: Users }, + { id: 'unbond' as const, label: t('staking.unbondTab'), icon: Unlock }, ].map(({ id, label, icon: Icon }) => (
)} @@ -442,19 +447,23 @@ export function HEZStakingModal({ isOpen, onClose }: HEZStakingModalProps) {
- Bakiyê Te + {t('staking.yourBalance')} {balance || '0'} HEZ
{stakingInfo && (
- Niha Staked + + {t('staking.currentlyStaked')} + {formatHEZ(stakingInfo.active)} HEZ
)}
- +
-

- ⚠️ Stake kirinê paşê 28 roj li bendê ye ji bo vekişandinê. -

+

{t('staking.bondWarning')}

)} @@ -499,14 +510,12 @@ export function HEZStakingModal({ isOpen, onClose }: HEZStakingModalProps) { {!stakingInfo ? (
-

- Pêşî HEZ bond bike, paşê nominate bike -

+

{t('staking.bondFirst')}

) : ( <>
- Validator hilbijêre (max 16): {selectedValidators.length}/16 + {t('staking.selectValidators', { count: selectedValidators.length })}
@@ -525,7 +534,7 @@ export function HEZStakingModal({ isOpen, onClose }: HEZStakingModalProps) { {v.address.slice(0, 16)}...{v.address.slice(-8)}
- Komîsyon: {v.commission.toFixed(2)}% + {t('staking.commission')} {v.commission.toFixed(2)}%
))} @@ -541,7 +550,7 @@ export function HEZStakingModal({ isOpen, onClose }: HEZStakingModalProps) { ) : ( )} - {isProcessing ? 'Tê nominate kirin...' : 'Nominate Bike'} + {isProcessing ? t('staking.nominating') : t('staking.nominateButton')} )} @@ -554,13 +563,13 @@ export function HEZStakingModal({ isOpen, onClose }: HEZStakingModalProps) { {!stakingInfo ? (
-

Tu hîn stake nekiriye

+

{t('staking.notStakedUnbond')}

) : ( <>
- Aktîf Stake + {t('staking.activeStake')} {formatHEZ(stakingInfo.active)} HEZ @@ -569,7 +578,7 @@ export function HEZStakingModal({ isOpen, onClose }: HEZStakingModalProps) {
-

- ⚠️ Unbond kirin 28 roj digire. Paşê dikare vekişîne. -

+

{t('staking.unbondWarning')}

)} diff --git a/src/components/wallet/LPStakingModal.tsx b/src/components/wallet/LPStakingModal.tsx index 3c7897c..d036c88 100644 --- a/src/components/wallet/LPStakingModal.tsx +++ b/src/components/wallet/LPStakingModal.tsx @@ -7,6 +7,7 @@ import { useState, useEffect } from 'react'; import { X, Lock, Unlock, Gift, AlertCircle, Loader2 } from 'lucide-react'; import { useWallet } from '@/contexts/WalletContext'; import { useTelegram } from '@/hooks/useTelegram'; +import { useTranslation } from '@/i18n'; import { cn } from '@/lib/utils'; interface StakingPool { @@ -56,6 +57,7 @@ function formatAssetLocation(assetId: number): object { export function LPStakingModal({ isOpen, onClose }: LPStakingModalProps) { const { assetHubApi, keypair, address } = useWallet(); const { hapticImpact, hapticNotification, showAlert } = useTelegram(); + const { t } = useTranslation(); const [pools, setPools] = useState([]); const [isLoading, setIsLoading] = useState(true); @@ -76,7 +78,7 @@ export function LPStakingModal({ isOpen, onClose }: LPStakingModalProps) { const poolEntries = await (assetHubApi.query.assetRewards as any)?.pools?.entries(); if (!poolEntries) { - setError('Staking palleti amade nîne'); + setError(t('lpStaking.palletNotReady')); setIsLoading(false); return; } @@ -170,7 +172,7 @@ export function LPStakingModal({ isOpen, onClose }: LPStakingModalProps) { } } catch (err) { console.error('Error fetching staking pools:', err); - setError('Staking pools bar nekirin'); + setError(t('lpStaking.poolsNotLoaded')); } finally { setIsLoading(false); } @@ -212,7 +214,7 @@ export function LPStakingModal({ isOpen, onClose }: LPStakingModalProps) { }) => { if (status.isFinalized) { if (dispatchError) { - let errorMsg = 'Stake neserketî'; + let errorMsg = t('lpStaking.stakeFailed'); if (dispatchError.isModule) { const decoded = assetHubApi.registry.findMetaError(dispatchError.asModule); errorMsg = `${decoded.section}.${decoded.name}`; @@ -227,14 +229,14 @@ export function LPStakingModal({ isOpen, onClose }: LPStakingModalProps) { }); hapticNotification('success'); - showAlert('Stake serket!'); + showAlert(t('lpStaking.stakeSuccess')); setStakeAmount(''); setTimeout(() => { onClose(); }, 1500); } catch (err) { - setError(err instanceof Error ? err.message : 'Stake neserketî'); + setError(err instanceof Error ? err.message : t('lpStaking.stakeFailed')); hapticNotification('error'); } finally { setIsProcessing(false); @@ -266,7 +268,7 @@ export function LPStakingModal({ isOpen, onClose }: LPStakingModalProps) { }) => { if (status.isFinalized) { if (dispatchError) { - let errorMsg = 'Unstake neserketî'; + let errorMsg = t('lpStaking.unstakeFailed'); if (dispatchError.isModule) { const decoded = assetHubApi.registry.findMetaError(dispatchError.asModule); errorMsg = `${decoded.section}.${decoded.name}`; @@ -281,14 +283,14 @@ export function LPStakingModal({ isOpen, onClose }: LPStakingModalProps) { }); hapticNotification('success'); - showAlert('Unstake serket!'); + showAlert(t('lpStaking.unstakeSuccess')); setUnstakeAmount(''); setTimeout(() => { onClose(); }, 1500); } catch (err) { - setError(err instanceof Error ? err.message : 'Unstake neserketî'); + setError(err instanceof Error ? err.message : t('lpStaking.unstakeFailed')); hapticNotification('error'); } finally { setIsProcessing(false); @@ -318,7 +320,7 @@ export function LPStakingModal({ isOpen, onClose }: LPStakingModalProps) { }) => { if (status.isFinalized) { if (dispatchError) { - let errorMsg = 'Xelat stendin neserketî'; + let errorMsg = t('lpStaking.claimFailed'); if (dispatchError.isModule) { const decoded = assetHubApi.registry.findMetaError(dispatchError.asModule); errorMsg = `${decoded.section}.${decoded.name}`; @@ -333,13 +335,13 @@ export function LPStakingModal({ isOpen, onClose }: LPStakingModalProps) { }); hapticNotification('success'); - showAlert('Xelat hat stendin!'); + showAlert(t('lpStaking.claimSuccess')); setTimeout(() => { onClose(); }, 1500); } catch (err) { - setError(err instanceof Error ? err.message : 'Xelat stendin neserketî'); + setError(err instanceof Error ? err.message : t('lpStaking.claimFailed')); hapticNotification('error'); } finally { setIsProcessing(false); @@ -370,13 +372,15 @@ export function LPStakingModal({ isOpen, onClose }: LPStakingModalProps) { ) : pools.length === 0 ? (
-

Hêj staking pool tune ne

+

{t('lpStaking.noPoolsYet')}

) : ( <> {/* Pool Selector */}
- +
{pools.map((pool) => (
)} @@ -505,7 +509,7 @@ export function LPStakingModal({ isOpen, onClose }: LPStakingModalProps) {
- Staked: {formatAmount(currentPool.userStaked)} + {t('lpStaking.stakedLabel')} {formatAmount(currentPool.userStaked)}
)} @@ -549,7 +553,9 @@ export function LPStakingModal({ isOpen, onClose }: LPStakingModalProps) {
{formatAmount(currentPool.pendingRewards)} PEZ
-
Xelatên li bendê
+
+ {t('lpStaking.pendingRewards')} +
)} diff --git a/src/components/wallet/PoolsModal.tsx b/src/components/wallet/PoolsModal.tsx index 38c917a..90c649a 100644 --- a/src/components/wallet/PoolsModal.tsx +++ b/src/components/wallet/PoolsModal.tsx @@ -8,6 +8,7 @@ import { X, Droplets, Plus, Minus, AlertCircle, Check } from 'lucide-react'; import { useWallet } from '@/contexts/WalletContext'; import { useTelegram } from '@/hooks/useTelegram'; import { KurdistanSun } from '@/components/KurdistanSun'; +import { useTranslation } from '@/i18n'; interface PoolsModalProps { isOpen: boolean; @@ -52,6 +53,7 @@ const formatAssetLocation = (id: number) => { export function PoolsModal({ isOpen, onClose }: PoolsModalProps) { const { assetHubApi, keypair } = useWallet(); const { hapticImpact, hapticNotification } = useTelegram(); + const { t } = useTranslation(); const [pools, setPools] = useState([]); const [isLoading, setIsLoading] = useState(false); @@ -267,7 +269,7 @@ export function PoolsModal({ isOpen, onClose }: PoolsModalProps) { } catch (err) { console.error('Failed to fetch pools:', err); if (!isCancelled) { - setError('Bağlantı hatası - tekrar deneyin'); + setError(t('pools.connectionError')); } } finally { if (!isCancelled) { @@ -331,7 +333,7 @@ export function PoolsModal({ isOpen, onClose }: PoolsModalProps) { ({ status, dispatchError }: { status: any; dispatchError: any }) => { if (status.isFinalized) { if (dispatchError) { - let errorMsg = 'Zêdekirin neserketî'; + let errorMsg = t('pools.addFailed'); if (dispatchError.isModule) { const decoded = assetHubApi.registry.findMetaError(dispatchError.asModule); errorMsg = `${decoded.section}.${decoded.name}: ${decoded.docs.join(' ')}`; @@ -349,7 +351,12 @@ export function PoolsModal({ isOpen, onClose }: PoolsModalProps) { }); setSuccessMessage( - `${amount0} ${selectedPool.asset0Symbol} + ${amount1} ${selectedPool.asset1Symbol} hate zêdekirin` + t('pools.addedLiquidity', { + amount0, + token0: selectedPool.asset0Symbol, + amount1, + token1: selectedPool.asset1Symbol, + }) ); setSuccess(true); hapticNotification('success'); @@ -363,7 +370,7 @@ export function PoolsModal({ isOpen, onClose }: PoolsModalProps) { }, 2000); } catch (err) { console.error('Add liquidity failed:', err); - setError(err instanceof Error ? err.message : 'Zêdekirin neserketî'); + setError(err instanceof Error ? err.message : t('pools.addFailed')); hapticNotification('error'); } finally { setIsSubmitting(false); @@ -376,7 +383,7 @@ export function PoolsModal({ isOpen, onClose }: PoolsModalProps) { const lpAmount = parseFloat(lpAmountToRemove); if (lpAmount <= 0 || lpAmount > (selectedPool.userLpBalance || 0)) { - setError('Mîqdara LP ne derbasdar e'); + setError(t('pools.invalidLpAmount')); hapticNotification('error'); return; } @@ -420,7 +427,7 @@ export function PoolsModal({ isOpen, onClose }: PoolsModalProps) { ({ status, dispatchError }: { status: any; dispatchError: any }) => { if (status.isFinalized) { if (dispatchError) { - let errorMsg = 'Derxistin neserketî'; + let errorMsg = t('pools.removeFailed'); if (dispatchError.isModule) { const decoded = assetHubApi.registry.findMetaError(dispatchError.asModule); errorMsg = `${decoded.section}.${decoded.name}: ${decoded.docs.join(' ')}`; @@ -437,7 +444,7 @@ export function PoolsModal({ isOpen, onClose }: PoolsModalProps) { ).catch(reject); }); - setSuccessMessage(`${lpAmountToRemove} LP token hate vegerandin`); + setSuccessMessage(t('pools.removedLiquidity', { amount: lpAmountToRemove })); setSuccess(true); hapticNotification('success'); @@ -449,7 +456,7 @@ export function PoolsModal({ isOpen, onClose }: PoolsModalProps) { }, 2000); } catch (err) { console.error('Remove liquidity failed:', err); - setError(err instanceof Error ? err.message : 'Derxistin neserketî'); + setError(err instanceof Error ? err.message : t('pools.removeFailed')); hapticNotification('error'); } finally { setIsSubmitting(false); @@ -466,7 +473,7 @@ export function PoolsModal({ isOpen, onClose }: PoolsModalProps) {
-

Serketî!

+

{t('pools.success')}

{successMessage}

@@ -489,9 +496,9 @@ export function PoolsModal({ isOpen, onClose }: PoolsModalProps) { }} className="text-muted-foreground" > - ← Paş + {t('pools.back')} -

Liquidity Zêde Bike

+

{t('pools.addLiquidity')}

@@ -515,7 +522,7 @@ export function PoolsModal({ isOpen, onClose }: PoolsModalProps) {
{selectedPool.asset0Symbol} Mîqdar - Bakiye: {balances[selectedPool.asset0Symbol]} + {t('swap.balanceLabel')} {balances[selectedPool.asset0Symbol]}
@@ -543,10 +550,10 @@ export function PoolsModal({ isOpen, onClose }: PoolsModalProps) {
- {selectedPool.asset1Symbol} Mîqdar (otomatîk) + {t('pools.amountAuto', { token: selectedPool.asset1Symbol })} - Bakiye: {balances[selectedPool.asset1Symbol]} + {t('swap.balanceLabel')} {balances[selectedPool.asset1Symbol]}
-

Tê zêdekirin...

+

{t('pools.adding')}

) : ( )}
@@ -603,9 +610,9 @@ export function PoolsModal({ isOpen, onClose }: PoolsModalProps) { }} className="text-muted-foreground" > - ← Paş + {t('pools.back')} -

Liquidity Derxe

+

{t('pools.removeLiquidity')}

@@ -617,7 +624,7 @@ export function PoolsModal({ isOpen, onClose }: PoolsModalProps) {

- LP Bakiye: {selectedPool.userLpBalance?.toFixed(4) || '0'} LP + {t('pools.lpBalance')} {selectedPool.userLpBalance?.toFixed(4) || '0'} LP

@@ -626,7 +633,7 @@ export function PoolsModal({ isOpen, onClose }: PoolsModalProps) { {/* LP Amount */}
- LP Token Mîqdar + {t('pools.lpTokenAmount')} Max: {selectedPool.userLpBalance?.toFixed(4) || '0'} @@ -651,7 +658,7 @@ export function PoolsModal({ isOpen, onClose }: PoolsModalProps) { {/* Estimated Returns */} {lpAmountToRemove && parseFloat(lpAmountToRemove) > 0 && (
-

Texmînî vegerandin:

+

{t('pools.estimatedReturn')}

{selectedPool.asset0Symbol} @@ -691,7 +698,7 @@ export function PoolsModal({ isOpen, onClose }: PoolsModalProps) { {isSubmitting ? (
-

Tê derxistin...

+

{t('pools.removing')}

) : ( )}
@@ -715,7 +722,7 @@ export function PoolsModal({ isOpen, onClose }: PoolsModalProps) {
{/* Header */}
-

Liquidity Pools

+

{t('pools.title')}

@@ -726,12 +733,12 @@ export function PoolsModal({ isOpen, onClose }: PoolsModalProps) { {isLoading ? (
-

Tê barkirin...

+

{t('pools.loadingPools')}

) : pools.length === 0 ? (
-

Pool tune

+

{t('pools.noPools')}

) : ( pools.map((pool) => ( @@ -760,13 +767,17 @@ export function PoolsModal({ isOpen, onClose }: PoolsModalProps) { {/* Pool Stats */}
- Rezerv {pool.asset0Symbol} + + {t('pools.reserve')} {pool.asset0Symbol} +

{pool.reserve0.toLocaleString('en-US', { maximumFractionDigits: 0 })}

- Rezerv {pool.asset1Symbol} + + {t('pools.reserve')} {pool.asset1Symbol} +

{pool.reserve1.toLocaleString('en-US', { maximumFractionDigits: 0 })}

@@ -777,7 +788,7 @@ export function PoolsModal({ isOpen, onClose }: PoolsModalProps) { {pool.userLpBalance && pool.userLpBalance > 0 && (
- Pozîsyona Te + {t('pools.yourPosition')} {pool.userShare?.toFixed(2)}% @@ -799,7 +810,7 @@ export function PoolsModal({ isOpen, onClose }: PoolsModalProps) { className="flex-1 py-2 bg-gradient-to-r from-green-600/20 to-blue-600/20 border border-green-500/30 text-green-400 font-medium rounded-lg flex items-center justify-center gap-1 text-sm" > - Zêde Bike + {t('pools.addButton')} {pool.userLpBalance && pool.userLpBalance > 0 && ( )}
diff --git a/src/components/wallet/SwapModal.tsx b/src/components/wallet/SwapModal.tsx index efb0bac..66e5bc3 100644 --- a/src/components/wallet/SwapModal.tsx +++ b/src/components/wallet/SwapModal.tsx @@ -8,6 +8,7 @@ import { X, ArrowDownUp, RefreshCw, AlertCircle, Check } from 'lucide-react'; import { useWallet } from '@/contexts/WalletContext'; import { useTelegram } from '@/hooks/useTelegram'; import { KurdistanSun } from '@/components/KurdistanSun'; +import { useTranslation } from '@/i18n'; interface SwapModalProps { isOpen: boolean; @@ -36,6 +37,7 @@ const formatAssetLocation = (id: number) => { export function SwapModal({ isOpen, onClose }: SwapModalProps) { const { assetHubApi, keypair } = useWallet(); const { hapticImpact, hapticNotification } = useTelegram(); + const { t } = useTranslation(); const [fromToken, setFromToken] = useState(TOKENS[0]); // HEZ const [toToken, setToToken] = useState(TOKENS[1]); // PEZ @@ -218,7 +220,7 @@ export function SwapModal({ isOpen, onClose }: SwapModalProps) { const swapAmount = parseFloat(fromAmount); if (swapAmount > fromBalance) { - setError('Bakiye têrê nake'); + setError(t('swap.insufficientBalance')); hapticNotification('error'); return; } @@ -262,7 +264,7 @@ export function SwapModal({ isOpen, onClose }: SwapModalProps) { ({ status, dispatchError }: { status: any; dispatchError: any }) => { if (status.isFinalized) { if (dispatchError) { - let errorMsg = 'Swap neserketî'; + let errorMsg = t('swap.swapFailed'); if (dispatchError.isModule) { const decoded = assetHubApi.registry.findMetaError(dispatchError.asModule); errorMsg = `${decoded.section}.${decoded.name}: ${decoded.docs.join(' ')}`; @@ -291,7 +293,7 @@ export function SwapModal({ isOpen, onClose }: SwapModalProps) { }, 2000); } catch (err) { console.error('Swap failed:', err); - setError(err instanceof Error ? err.message : 'Swap neserketî'); + setError(err instanceof Error ? err.message : t('swap.swapFailed')); hapticNotification('error'); } finally { setIsSwapping(false); @@ -307,7 +309,7 @@ export function SwapModal({ isOpen, onClose }: SwapModalProps) {
-

Swap Serketî!

+

{t('swap.swapSuccess')}

{fromAmount} {fromToken.symbol} → {toAmount} {toToken.symbol}

@@ -321,7 +323,7 @@ export function SwapModal({ isOpen, onClose }: SwapModalProps) {
{/* Header */}
-

Token Swap

+

{t('swap.title')}

@@ -332,7 +334,7 @@ export function SwapModal({ isOpen, onClose }: SwapModalProps) { {/* From Token */}
- Ji (From) + {t('swap.fromLabel')} { @@ -416,7 +418,7 @@ export function SwapModal({ isOpen, onClose }: SwapModalProps) { />
- Bakiye: {balances[toToken.symbol]} {toToken.symbol} + {t('swap.balanceLabel')} {balances[toToken.symbol]} {toToken.symbol}
@@ -424,14 +426,14 @@ export function SwapModal({ isOpen, onClose }: SwapModalProps) { {/* Exchange Rate */}
- Rêjeya Guherandinê + {t('swap.exchangeRate')} {isLoadingRate ? ( ) : exchangeRate ? ( `1 ${fromToken.symbol} = ${exchangeRate.toFixed(4)} ${toToken.symbol}` ) : ( - Pool tune + {t('swap.noPool')} )} )}
diff --git a/src/components/wallet/TokensCard.tsx b/src/components/wallet/TokensCard.tsx index f5dac61..ebbb6b4 100644 --- a/src/components/wallet/TokensCard.tsx +++ b/src/components/wallet/TokensCard.tsx @@ -23,6 +23,7 @@ import { } from 'lucide-react'; import { useWallet } from '@/contexts/WalletContext'; import { useTelegram } from '@/hooks/useTelegram'; +import { useTranslation } from '@/i18n'; import { subscribeToConnection, getLastError, @@ -189,6 +190,7 @@ interface Props { export function TokensCard({ onSendToken }: Props) { const { address, balance: hezBalance } = useWallet(); const { hapticImpact } = useTelegram(); + const { t } = useTranslation(); const [rpcConnected, setRpcConnected] = useState(false); const [endpointName, setEndpointName] = useState(null); @@ -615,7 +617,7 @@ export function TokensCard({ onSendToken }: Props) { type="text" value={searchQuery} onChange={(e) => setSearchQuery(e.target.value)} - placeholder="Token bigere..." + placeholder={t('tokens.searchPlaceholder')} className="w-full pl-9 pr-4 py-2 bg-background rounded-lg text-sm" />
@@ -629,7 +631,7 @@ export function TokensCard({ onSendToken }: Props) { className="w-full py-2 border border-dashed border-border rounded-lg text-sm text-muted-foreground hover:text-white hover:border-cyan-500/50 flex items-center justify-center gap-2" > - Token Zêde Bike + {t('tokens.addToken')} )} @@ -639,7 +641,7 @@ export function TokensCard({ onSendToken }: Props) { type="number" value={newAssetId} onChange={(e) => setNewAssetId(e.target.value)} - placeholder="Asset ID binivîse (mînak: 3)" + placeholder={t('tokens.assetIdPlaceholder')} className="w-full px-3 py-2 bg-muted rounded-lg text-sm" min="0" /> @@ -648,14 +650,14 @@ export function TokensCard({ onSendToken }: Props) { onClick={() => setShowAddToken(false)} className="flex-1 py-2 bg-muted rounded-lg text-sm" > - Betal + {t('tokens.cancel')}
@@ -667,7 +669,9 @@ export function TokensCard({ onSendToken }: Props) {
-

Pezkuwichain Girêdayî

+

+ {t('tokens.blockchainConnected')} +

{endpointName &&

{endpointName}

}
@@ -675,9 +679,11 @@ export function TokensCard({ onSendToken }: Props) {
-

Girêdana Blockchain...

+

+ {t('tokens.connectingBlockchain')} +

- {getLastError() || 'RPC serverê tê girêdan...'} + {getLastError() || t('tokens.connectingRpc')}

@@ -688,7 +694,7 @@ export function TokensCard({ onSendToken }: Props) { {filteredTokens.length === 0 ? (
-

Token nehat dîtin

+

{t('tokens.tokenNotFound')}

) : ( filteredTokens.map((token) => @@ -793,7 +799,7 @@ export function TokensCard({ onSendToken }: Props) { {/* Total Value */} {token.valueUsd !== undefined && token.balance !== '--' && (
- Toplam + {t('tokens.total')} ≈ $ {( @@ -879,7 +885,9 @@ export function TokensCard({ onSendToken }: Props) { {token.balance}

{token.balance === '--' ? ( -

Tê barkirin...

+

+ {t('tokens.loadingBalance')} +

) : token.valueUsd !== undefined ? (

≈ ${token.valueUsd.toFixed(2)} diff --git a/src/components/wallet/WalletDashboard.tsx b/src/components/wallet/WalletDashboard.tsx index 29088c0..fcd2e89 100644 --- a/src/components/wallet/WalletDashboard.tsx +++ b/src/components/wallet/WalletDashboard.tsx @@ -29,6 +29,7 @@ import { HEZStakingModal } from './HEZStakingModal'; import { DepositUSDTModal } from './DepositUSDTModal'; import { useWallet } from '@/contexts/WalletContext'; import { useTelegram } from '@/hooks/useTelegram'; +import { useTranslation } from '@/i18n'; import { formatAddress } from '@/lib/wallet-service'; interface Props { @@ -51,6 +52,7 @@ interface Transaction { export function WalletDashboard({ onDisconnect }: Props) { const { address, balance, api, assetHubApi, disconnect, isLoading } = useWallet(); const { hapticImpact, hapticNotification, showAlert } = useTelegram(); + const { t } = useTranslation(); const [copied, setCopied] = useState(false); const [activeTab, setActiveTab] = useState<'main' | 'send' | 'receive' | 'history'>('main'); @@ -583,7 +585,7 @@ export function WalletDashboard({ onDisconnect }: Props) { )}

-

Girêdayî

+

{t('dashboard.connected')}

- Bişîne + {t('dashboard.send')}
- Werbigire + {t('dashboard.receive')}
-
USDT Zêde Bike
-
- TON, Polkadot an TRC20 ji zincîrên din -
+
{t('dashboard.depositUsdt')}
+
{t('dashboard.depositUsdtDesc')}
@@ -739,7 +739,7 @@ export function WalletDashboard({ onDisconnect }: Props) {
-

Çalakiya Dawî

+

{t('dashboard.recentActivity')}

@@ -755,7 +755,7 @@ export function WalletDashboard({ onDisconnect }: Props) { onClick={handleRefresh} disabled={isLoadingTxs} className="text-gray-400 hover:text-white p-1" - title="Nûkirin" + title={t('dashboard.refreshTx')} > @@ -765,13 +765,13 @@ export function WalletDashboard({ onDisconnect }: Props) { {isLoadingTxs ? (
-

Tê barkirin...

+

{t('dashboard.loadingTx')}

) : recentTxs.length === 0 ? (
-

Transaksiyona dawî tune

-

Dîroka te dê li vir xuya bibe

+

{t('dashboard.noRecentTx')}

+

{t('dashboard.historyAppears')}

) : (
@@ -792,7 +792,7 @@ export function WalletDashboard({ onDisconnect }: Props) {
- {tx.direction === 'sent' ? 'Şandin' : 'Wergirtin'} + {tx.direction === 'sent' ? t('dashboard.sent') : t('dashboard.received')}
Block #{tx.blockNumber}
@@ -852,7 +852,9 @@ export function WalletDashboard({ onDisconnect }: Props) { {isStakingSelectorOpen && (
-

Staking Hilbijêre

+

+ {t('dashboard.selectStaking')} +

HEZ Staking
-
Validator nominate bike
-
Trust Score +
+
+ {t('dashboard.validatorNominate')} +
+
{t('dashboard.trustScorePlus')}
LP Staking
-
LP token stake bike
-
PEZ Xelat +
+
+ {t('dashboard.lpStakeDesc')} +
+
{t('dashboard.pezRewardPlus')}
@@ -889,7 +895,7 @@ export function WalletDashboard({ onDisconnect }: Props) { onClick={() => setIsStakingSelectorOpen(false)} className="w-full mt-4 py-3 bg-secondary text-muted-foreground rounded-xl" > - Paşve + {t('dashboard.goBack')}
@@ -948,6 +954,7 @@ const SEND_TOKENS: TokenOption[] = [ function SendTab({ onBack }: { onBack: () => void }) { const { balance, api, assetHubApi, keypair } = useWallet(); const { hapticNotification, hapticImpact } = useTelegram(); + const { t } = useTranslation(); const [selectedToken, setSelectedToken] = useState(null); const [toAddress, setToAddress] = useState(''); @@ -1013,11 +1020,11 @@ function SendTab({ onBack }: { onBack: () => void }) { const tg = window.Telegram?.WebApp; if (!tg?.showScanQrPopup) { - setError('QR okuyucu vê platformê de amade nîne'); + setError(t('send.qrNotAvailable')); return; } - tg.showScanQrPopup({ text: 'Navnîşana cîzdanê bişoxîne' }, (scannedText: string) => { + tg.showScanQrPopup({ text: t('send.scanQrText') }, (scannedText: string) => { if (scannedText) { // Extract address - might be raw address or URI format let address = scannedText; @@ -1035,7 +1042,7 @@ function SendTab({ onBack }: { onBack: () => void }) { tg.closeScanQrPopup?.(); return true; // Close popup } else { - setError('Navnîşana derbasdar nîne'); + setError(t('send.invalidAddress')); hapticNotification('error'); } } @@ -1045,17 +1052,17 @@ function SendTab({ onBack }: { onBack: () => void }) { const handleSend = async () => { if (!keypair) { - setError('Cîzdan amade nîne'); + setError(t('send.walletNotReady')); return; } if (!selectedToken) { - setError('Token hilbijêre'); + setError(t('send.selectTokenFirst')); return; } if (!toAddress || !amount) { - setError('Navnîşan û mîqdar binivîse'); + setError(t('send.fillAddressAndAmount')); return; } @@ -1063,20 +1070,20 @@ function SendTab({ onBack }: { onBack: () => void }) { const sendAmount = parseFloat(amount); if (sendAmount > currentBalance) { - setError('Bakiye têrê nake'); + setError(t('send.insufficientBalance')); return; } // Check if appropriate API is available if (selectedToken === 'HEZ' && !api) { - setError('Mainnet API amade nîne'); + setError(t('send.mainnetApiNotReady')); return; } if ( (selectedToken === 'PEZ' || selectedToken === 'USDT' || selectedToken === 'DOT') && !assetHubApi ) { - setError('Asset Hub API amade nîne'); + setError(t('send.assetHubApiNotReady')); return; } @@ -1106,7 +1113,7 @@ function SendTab({ onBack }: { onBack: () => void }) { setSuccess(true); hapticNotification('success'); } catch (err) { - setError(err instanceof Error ? err.message : 'Transfer neserketî'); + setError(err instanceof Error ? err.message : t('send.transferFailed')); hapticNotification('error'); } finally { setIsLoading(false); @@ -1119,13 +1126,13 @@ function SendTab({ onBack }: { onBack: () => void }) {
-

Token Hilbijêre

+

{t('send.selectToken')}

-

Kîjan token bişîne?

+

{t('send.whichToken')}

{SEND_TOKENS.map((token) => { @@ -1170,7 +1177,7 @@ function SendTab({ onBack }: { onBack: () => void }) {
{(!api || !assetHubApi) && ( -

⚠️ Hinek chain girêdayî nîne

+

{t('send.someChainNotConnected')}

)}
); @@ -1183,9 +1190,9 @@ function SendTab({ onBack }: { onBack: () => void }) {
-

Transfer Serketî!

+

{t('send.transferSuccess')}

- {amount} {selectedToken} hat şandin + {t('send.wasSent', { amount, token: selectedToken || '' })}

{txHash && ( @@ -1198,7 +1205,7 @@ function SendTab({ onBack }: { onBack: () => void }) { onClick={onBack} className="w-full py-3 bg-primary text-primary-foreground rounded-xl font-semibold" > - Temam + {t('send.done')}
); @@ -1210,9 +1217,11 @@ function SendTab({ onBack }: { onBack: () => void }) {
-

Bişîne {selectedToken}

+

+ {t('send.sendToken', { token: selectedToken || '' })} +

@@ -1231,13 +1240,13 @@ function SendTab({ onBack }: { onBack: () => void }) { onClick={() => setSelectedToken(null)} className="text-xs text-primary hover:underline" > - Biguhere + {t('send.changeToken')}
- +
void }) { @@ -1258,9 +1267,9 @@ function SendTab({ onBack }: { onBack: () => void }) {
- + - Bakiye: {getCurrentBalance()} {selectedToken} + {t('send.balanceLabel')} {getCurrentBalance()} {selectedToken}
void }) { {isLoading ? ( <> - Tê şandin... + {t('send.sending')} ) : ( <> - Bişîne + {t('send.sendButton')} )} @@ -1307,6 +1316,7 @@ function ReceiveTab({ address, onBack }: { address: string | null; onBack: () => const [qrCodeUrl, setQrCodeUrl] = useState(null); const [qrError, setQrError] = useState(false); const { hapticNotification } = useTelegram(); + const { t } = useTranslation(); // Generate QR code when address changes useEffect(() => { @@ -1344,9 +1354,9 @@ function ReceiveTab({ address, onBack }: { address: string | null; onBack: () =>
-

Werbigire

+

{t('receive.title')}

@@ -1358,16 +1368,14 @@ function ReceiveTab({ address, onBack }: { address: string | null; onBack: () => ) : qrError ? (
-

QR çênebû

+

{t('receive.qrFailed')}

) : (
)}
-

- Ev navnîşana te ye. Ji bo wergirtina token vê navnîşanê parve bike. -

+

{t('receive.shareAddress')}

{address}

@@ -1380,12 +1388,12 @@ function ReceiveTab({ address, onBack }: { address: string | null; onBack: () => {copied ? ( <> - Hat kopîkirin! + {t('receive.addressCopied')} ) : ( <> - Navnîşanê Kopî Bike + {t('receive.copyAddress')} )} @@ -1407,6 +1415,7 @@ function HistoryTab({ onBack: () => void; }) { const { hapticImpact } = useTelegram(); + const { t } = useTranslation(); const getDecimalsForAsset = (section: string, assetId?: string): number => { if (section === 'balances') return 12; // HEZ @@ -1433,9 +1442,9 @@ function HistoryTab({
-

Dîroka Transaksiyonan

+

{t('history.title')}