-
Proxy Account
+
{t('commission.setup.proxyAccount')}
{COMMISSIONS.KYC.proxyAccount}
@@ -337,11 +337,11 @@ export function CommissionSetupTab() {
- Commission Members ({commissionMembers.length})
+ {t('commission.setup.membersLabel')} ({commissionMembers.length})
{commissionMembers.length === 0 ? (
- No members yet
+ {t('commission.setup.noMembers')}
) : (
@@ -352,7 +352,7 @@ export function CommissionSetupTab() {
>
{member}
{member === COMMISSIONS.KYC.proxyAccount && (
-
KYC Proxy
+
{t('commission.setup.kycProxy')}
)}
))}
@@ -364,34 +364,33 @@ export function CommissionSetupTab() {
- Required: Initialize the commission before members can join.
- This requires sudo privileges.
+ {t('commission.setup.initRequired')}
)}
{setupComplete && (
-
Add Members
+
{t('commission.setup.addMembersTitle')}
{
// Get wallet addresses from Pezkuwi.js extension
// For now, show instruction
toast({
- title: 'Get Addresses',
- description: 'Copy addresses from Pezkuwi.js and paste below',
+ title: t('commission.setup.getAddresses'),
+ description: t('commission.setup.getAddressesToast'),
});
}}
variant="outline"
size="sm"
>
- How to get addresses
+ {t('commission.setup.howToGetAddresses')}
@@ -421,17 +420,17 @@ export function CommissionSetupTab() {
{processing ? (
<>
- Initializing...
+ {t('commission.setup.initializing')}
>
) : setupComplete ? (
<>
- Already Initialized
+ {t('commission.setup.alreadyInitialized')}
>
) : (
<>
- Initialize Commission
+ {t('commission.setup.initializeBtn')}
>
)}
@@ -441,7 +440,7 @@ export function CommissionSetupTab() {
variant="outline"
disabled={loading}
>
- Refresh
+ {t('commission.setup.refresh')}
>
@@ -452,22 +451,13 @@ export function CommissionSetupTab() {
{/* Instructions */}
- Setup Instructions
+ {t('commission.setup.instructionsTitle')}
-
- Initialize Commission - Add proxy to
- DynamicCommissionCollective (requires sudo)
-
-
- Join Commission - Members add proxy rights
- via Commission Voting tab
-
-
- Start Voting - Create proposals and vote on
- KYC applications
-
+ {t('commission.setup.step1')}
+ {t('commission.setup.step2')}
+ {t('commission.setup.step3')}
diff --git a/web/src/components/admin/CommissionVotingTab.tsx b/web/src/components/admin/CommissionVotingTab.tsx
index 6d66d5a8..63da1ef2 100644
--- a/web/src/components/admin/CommissionVotingTab.tsx
+++ b/web/src/components/admin/CommissionVotingTab.tsx
@@ -1,4 +1,5 @@
import { useState, useEffect } from 'react';
+import { useTranslation } from 'react-i18next';
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
import { Button } from '@/components/ui/button';
import { Badge } from '@/components/ui/badge';
@@ -26,6 +27,7 @@ interface Proposal {
}
export function CommissionVotingTab() {
+ const { t } = useTranslation();
const { api, isApiReady, selectedAccount } = usePezkuwi();
const { toast } = useToast();
@@ -120,8 +122,7 @@ export function CommissionVotingTab() {
} catch (error) {
if (import.meta.env.DEV) console.error('Error loading proposals:', error);
toast({
- title: 'Error',
- description: 'Failed to load proposals',
+ title: t('commission.voting.loadFailed'),
variant: 'destructive',
});
} finally {
@@ -132,8 +133,8 @@ export function CommissionVotingTab() {
const handleVote = async (proposal: Proposal, approve: boolean) => {
if (!api || !selectedAccount) {
toast({
- title: 'Wallet Not Connected',
- description: 'Please connect your wallet first',
+ title: t('commission.voting.walletNotConnected'),
+ description: t('commission.voting.connectFirst'),
variant: 'destructive',
});
return;
@@ -141,8 +142,7 @@ export function CommissionVotingTab() {
if (!isCommissionMember) {
toast({
- title: 'Not a Commission Member',
- description: 'You are not a member of the KYC Approval Commission',
+ title: t('commission.voting.notMemberTitle'),
variant: 'destructive',
});
return;
@@ -182,7 +182,7 @@ export function CommissionVotingTab() {
if (import.meta.env.DEV) console.error('Vote error:', errorMessage);
toast({
- title: 'Vote Failed',
+ title: t('commission.voting.voteFailed'),
description: errorMessage,
variant: 'destructive',
});
@@ -203,14 +203,14 @@ export function CommissionVotingTab() {
if (executedEvent) {
if (import.meta.env.DEV) console.log('✅ Proposal executed (threshold reached)');
toast({
- title: 'Success',
- description: 'Proposal passed and executed! KYC approved.',
+ title: t('commission.voting.proposalPassed'),
+ description: t('commission.voting.kycApproved'),
});
} else if (votedEvent) {
if (import.meta.env.DEV) console.log('✅ Vote recorded');
toast({
- title: 'Vote Recorded',
- description: `Your ${approve ? 'AYE' : 'NAY'} vote has been recorded`,
+ title: t('commission.voting.voteRecorded'),
+ description: approve ? t('commission.voting.ayeRecorded') : t('commission.voting.nayRecorded'),
});
}
@@ -220,8 +220,8 @@ export function CommissionVotingTab() {
).catch((error) => {
if (import.meta.env.DEV) console.error('Failed to sign and send:', error);
toast({
- title: 'Transaction Error',
- description: error instanceof Error ? error.message : 'Failed to submit transaction',
+ title: t('commission.voting.submitFailed'),
+ description: error instanceof Error ? error.message : t('commission.voting.submitFailed'),
variant: 'destructive',
});
reject(error);
@@ -236,8 +236,8 @@ export function CommissionVotingTab() {
} catch (error) {
if (import.meta.env.DEV) console.error('Error voting:', error);
toast({
- title: 'Error',
- description: error instanceof Error ? error.message : 'Failed to vote',
+ title: t('commission.voting.voteFailed'),
+ description: error instanceof Error ? error.message : t('commission.voting.voteFailed'),
variant: 'destructive',
});
} finally {
@@ -248,8 +248,8 @@ export function CommissionVotingTab() {
const handleExecute = async (proposal: Proposal) => {
if (!api || !selectedAccount) {
toast({
- title: 'Wallet Not Connected',
- description: 'Please connect your wallet first',
+ title: t('commission.voting.walletNotConnected'),
+ description: t('commission.voting.connectFirst'),
variant: 'destructive',
});
return;
@@ -297,7 +297,7 @@ export function CommissionVotingTab() {
if (import.meta.env.DEV) console.error('Execute error:', errorMessage);
toast({
- title: 'Execute Failed',
+ title: t('commission.voting.executeFailed'),
description: errorMessage,
variant: 'destructive',
});
@@ -324,21 +324,21 @@ export function CommissionVotingTab() {
if (result && typeof result === 'object' && 'Err' in result) {
if (import.meta.env.DEV) console.error('Execution failed:', result.Err);
toast({
- title: 'Execution Failed',
- description: `Proposal closed but execution failed: ${JSON.stringify(result.Err)}`,
+ title: t('commission.voting.executeFailed'),
+ description: JSON.stringify(result.Err),
variant: 'destructive',
});
} else {
toast({
- title: 'Proposal Executed!',
- description: 'KYC approved and NFT minted successfully!',
+ title: t('commission.voting.executeSuccess'),
+ description: t('commission.voting.kycApproved'),
});
}
} else if (closedEvent) {
if (import.meta.env.DEV) console.log('Proposal closed');
toast({
- title: 'Proposal Closed',
- description: 'Proposal has been closed',
+ title: t('commission.voting.proposalClosed'),
+ description: t('commission.voting.proposalClosedDesc'),
});
}
@@ -348,8 +348,8 @@ export function CommissionVotingTab() {
).catch((error) => {
if (import.meta.env.DEV) console.error('Failed to sign and send:', error);
toast({
- title: 'Transaction Error',
- description: error instanceof Error ? error.message : 'Failed to submit transaction',
+ title: t('commission.voting.submitFailed'),
+ description: error instanceof Error ? error.message : t('commission.voting.submitFailed'),
variant: 'destructive',
});
reject(error);
@@ -363,8 +363,8 @@ export function CommissionVotingTab() {
} catch (error) {
if (import.meta.env.DEV) console.error('Error executing:', error);
toast({
- title: 'Error',
- description: error instanceof Error ? error.message : 'Failed to execute proposal',
+ title: t('commission.voting.executeFailed'),
+ description: error instanceof Error ? error.message : t('commission.voting.executeFailed'),
variant: 'destructive',
});
} finally {
@@ -373,19 +373,19 @@ export function CommissionVotingTab() {
};
const getProposalDescription = (call: Record
): string => {
- if (!call) return 'Unknown proposal';
+ if (!call) return t('commission.voting.unknownProposal');
try {
const callStr = JSON.stringify(call);
if (callStr.includes('approveKyc')) {
- return 'KYC Approval';
+ return t('commission.voting.kycApproval');
}
if (callStr.includes('rejectKyc')) {
- return 'KYC Rejection';
+ return t('commission.voting.kycRejection');
}
- return 'Commission Action';
+ return t('commission.voting.commissionAction');
} catch {
- return 'Unknown proposal';
+ return t('commission.voting.unknownProposal');
}
};
@@ -393,12 +393,12 @@ export function CommissionVotingTab() {
const progress = (proposal.ayes.length / proposal.threshold) * 100;
if (proposal.ayes.length >= proposal.threshold) {
- return PASSED ;
+ return {t('commission.voting.statusPassed')} ;
}
if (progress >= 50) {
- return VOTING ({progress.toFixed(0)}%) ;
+ return {t('commission.voting.statusVoting', { progress: progress.toFixed(0) })} ;
}
- return VOTING ({progress.toFixed(0)}%) ;
+ return {t('commission.voting.statusVoting', { progress: progress.toFixed(0) })} ;
};
if (!isApiReady) {
@@ -407,7 +407,7 @@ export function CommissionVotingTab() {
- Connecting to blockchain...
+ {t('commission.voting.connecting')}
@@ -419,7 +419,7 @@ export function CommissionVotingTab() {
-
Please connect your wallet to view commission proposals
+
{t('commission.voting.noWallet')}
@@ -461,20 +461,19 @@ export function CommissionVotingTab() {
({ status, dispatchError }) => {
if (status.isInBlock || status.isFinalized) {
if (dispatchError) {
- let errorMessage = 'Failed to join commission';
+ let errorMessage = t('commission.voting.joinFailed');
if (dispatchError.isModule) {
const decoded = api.registry.findMetaError(dispatchError.asModule);
errorMessage = `${decoded.section}.${decoded.name}`;
}
toast({
- title: 'Error',
+ title: t('commission.voting.joinFailed'),
description: errorMessage,
variant: 'destructive',
});
} else {
toast({
- title: 'Success',
- description: 'You have joined the KYC Commission!',
+ title: t('commission.voting.joinSuccess'),
});
setTimeout(() => checkMembership(), 2000);
}
@@ -483,8 +482,8 @@ export function CommissionVotingTab() {
);
} catch (error) {
toast({
- title: 'Error',
- description: error instanceof Error ? error.message : 'Failed to join commission',
+ title: t('commission.voting.joinFailed'),
+ description: error instanceof Error ? error.message : t('commission.voting.joinFailed'),
variant: 'destructive',
});
}
@@ -494,13 +493,13 @@ export function CommissionVotingTab() {
-
You are not a member of the KYC Approval Commission
-
Only commission members can view and vote on proposals
+
{t('commission.voting.notMember')}
+
{t('commission.voting.onlyMembers')}
- Join Commission
+ {t('commission.voting.joinBtn')}
@@ -512,9 +511,9 @@ export function CommissionVotingTab() {
-
Commission Proposals
+
{t('commission.voting.title')}
- Active voting proposals for {COMMISSIONS.KYC.name}
+ {t('commission.voting.subtitle', { name: COMMISSIONS.KYC.name })}
- Refresh
+ {t('commission.voting.refresh')}
@@ -532,7 +531,7 @@ export function CommissionVotingTab() {
- Loading proposals...
+ {t('commission.voting.loading')}
@@ -541,25 +540,25 @@ export function CommissionVotingTab() {
-
No active proposals
-
Proposals will appear here when commission members create them
+
{t('commission.voting.noProposals')}
+
{t('commission.voting.noProposalsHelp')}
) : (
- Active Proposals ({proposals.length})
+ {t('commission.voting.activeProposals', { count: proposals.length })}
- Proposal
- Type
- Status
- Votes
- Actions
+ {t('commission.voting.tableProposal')}
+ {t('commission.voting.tableType')}
+ {t('commission.voting.tableStatus')}
+ {t('commission.voting.tableVotes')}
+ {t('commission.voting.tableActions')}
@@ -602,7 +601,7 @@ export function CommissionVotingTab() {
{voting === proposal.hash ? (
) : (
- <>Execute Proposal>
+ <>{t('commission.voting.execute')}>
)}
) : (
@@ -619,7 +618,7 @@ export function CommissionVotingTab() {
) : (
<>
- Aye
+ {t('commission.voting.aye')}
>
)}
@@ -634,7 +633,7 @@ export function CommissionVotingTab() {
) : (
<>
- Nay
+ {t('commission.voting.nay')}
>
)}
diff --git a/web/src/components/admin/DisputeResolutionPanel.tsx b/web/src/components/admin/DisputeResolutionPanel.tsx
index bf7e2b25..d6e5bdc6 100644
--- a/web/src/components/admin/DisputeResolutionPanel.tsx
+++ b/web/src/components/admin/DisputeResolutionPanel.tsx
@@ -1,4 +1,5 @@
import { useState, useEffect } from 'react';
+import { useTranslation } from 'react-i18next';
import { supabase } from '@/lib/supabase';
import { Card, CardContent } from '@/components/ui/card';
import { Button } from '@/components/ui/button';
@@ -82,12 +83,12 @@ interface Evidence {
review_notes?: string;
}
-// Decision options
-const DECISION_OPTIONS = [
- { value: 'release_to_buyer', label: 'Release to Buyer', description: 'Release escrowed crypto to the buyer' },
- { value: 'refund_to_seller', label: 'Refund to Seller', description: 'Return escrowed crypto to the seller' },
- { value: 'split', label: 'Split 50/50', description: 'Split the escrowed amount between both parties' },
- { value: 'escalate', label: 'Escalate', description: 'Escalate to higher authority for complex cases' }
+// Decision option values - labels are translated via t() in the component
+const DECISION_OPTION_KEYS = [
+ { value: 'release_to_buyer', labelKey: 'dispute.releaseToBuyer' },
+ { value: 'refund_to_seller', labelKey: 'dispute.refundToSeller' },
+ { value: 'split', labelKey: 'dispute.split' },
+ { value: 'escalate', labelKey: 'dispute.escalate' },
];
// Status badge colors
@@ -99,18 +100,19 @@ const STATUS_COLORS: Record = {
closed: 'bg-gray-500/20 text-gray-400 border-gray-500/30'
};
-// Category labels
-const CATEGORY_LABELS: Record = {
- payment_not_received: 'Payment Not Received',
- wrong_amount: 'Wrong Amount',
- fake_payment_proof: 'Fake Payment Proof',
- seller_not_responding: 'Seller Not Responding',
- buyer_not_responding: 'Buyer Not Responding',
- fraudulent_behavior: 'Fraudulent Behavior',
- other: 'Other'
+// Category translation keys
+const CATEGORY_KEYS: Record = {
+ payment_not_received: 'dispute.categoryPaymentNotReceived',
+ wrong_amount: 'dispute.categoryWrongAmount',
+ fake_payment_proof: 'dispute.categoryFakePaymentProof',
+ seller_not_responding: 'dispute.categorySellerNotResponding',
+ buyer_not_responding: 'dispute.categoryBuyerNotResponding',
+ fraudulent_behavior: 'dispute.categoryFraudulentBehavior',
+ other: 'dispute.categoryOther'
};
export function DisputeResolutionPanel() {
+ const { t } = useTranslation();
const [disputes, setDisputes] = useState([]);
const [loading, setLoading] = useState(true);
const [selectedDispute, setSelectedDispute] = useState(null);
@@ -164,7 +166,7 @@ export function DisputeResolutionPanel() {
setDisputes(disputesWithEvidence);
} catch (error) {
console.error('Error fetching disputes:', error);
- toast.error('Failed to load disputes');
+ toast.error(t('dispute.loadFailed'));
} finally {
setLoading(false);
}
@@ -216,18 +218,18 @@ export function DisputeResolutionPanel() {
if (error) throw error;
- toast.success('Dispute claimed for review');
+ toast.success(t('dispute.claimedToast'));
fetchDisputes();
} catch (error) {
console.error('Error claiming dispute:', error);
- toast.error('Failed to claim dispute');
+ toast.error(t('dispute.claimFailed'));
}
};
// Resolve dispute
const resolveDispute = async () => {
if (!selectedDispute || !decision || !reasoning) {
- toast.error('Please select a decision and provide reasoning');
+ toast.error(t('dispute.noDecision'));
return;
}
@@ -265,7 +267,7 @@ export function DisputeResolutionPanel() {
p_user_id: selectedDispute.trade.seller_id,
p_type: 'dispute_resolved',
p_title: 'Dispute Resolved',
- p_message: `The dispute has been resolved: ${DECISION_OPTIONS.find(o => o.value === decision)?.label}`,
+ p_message: `The dispute has been resolved: ${t(DECISION_OPTION_KEYS.find(o => o.value === decision)?.labelKey || '')}`,
p_reference_type: 'dispute',
p_reference_id: selectedDispute.id
}),
@@ -273,7 +275,7 @@ export function DisputeResolutionPanel() {
p_user_id: selectedDispute.trade.buyer_id,
p_type: 'dispute_resolved',
p_title: 'Dispute Resolved',
- p_message: `The dispute has been resolved: ${DECISION_OPTIONS.find(o => o.value === decision)?.label}`,
+ p_message: `The dispute has been resolved: ${t(DECISION_OPTION_KEYS.find(o => o.value === decision)?.labelKey || '')}`,
p_reference_type: 'dispute',
p_reference_id: selectedDispute.id
})
@@ -281,7 +283,7 @@ export function DisputeResolutionPanel() {
await Promise.all(notificationPromises);
}
- toast.success('Dispute resolved successfully');
+ toast.success(t('dispute.resolvedToast'));
setResolveOpen(false);
setSelectedDispute(null);
setDecision('');
@@ -289,7 +291,7 @@ export function DisputeResolutionPanel() {
fetchDisputes();
} catch (error) {
console.error('Error resolving dispute:', error);
- toast.error('Failed to resolve dispute');
+ toast.error(t('dispute.resolveFailed'));
} finally {
setSubmitting(false);
}
@@ -322,15 +324,15 @@ export function DisputeResolutionPanel() {
- Dispute Resolution
+ {t('dispute.title')}
- Review and resolve P2P trading disputes
+ {t('dispute.subtitle')}
- Refresh
+ {t('dispute.refresh')}
@@ -340,7 +342,7 @@ export function DisputeResolutionPanel() {
-
Open
+
{t('dispute.statsOpen')}
{stats.open}
@@ -352,7 +354,7 @@ export function DisputeResolutionPanel() {
-
Under Review
+
{t('dispute.statsUnderReview')}
{stats.under_review}
@@ -364,7 +366,7 @@ export function DisputeResolutionPanel() {
-
Resolved
+
{t('dispute.statsResolved')}
{stats.resolved}
@@ -376,7 +378,7 @@ export function DisputeResolutionPanel() {
-
Escalated
+
{t('dispute.statsEscalated')}
{stats.escalated}
@@ -389,16 +391,16 @@ export function DisputeResolutionPanel() {
- Open
+ {t('dispute.statsOpen')}
{stats.open > 0 && (
{stats.open}
)}
- In Review
- Resolved
- Escalated
+ {t('dispute.tabInReview')}
+ {t('dispute.statsResolved')}
+ {t('dispute.statsEscalated')}
@@ -412,7 +414,7 @@ export function DisputeResolutionPanel() {
- No disputes in this category
+ {t('dispute.empty')}
) : (
@@ -427,12 +429,12 @@ export function DisputeResolutionPanel() {
{dispute.status.replace('_', ' ').toUpperCase()}
- {CATEGORY_LABELS[dispute.category] || dispute.category}
+ {t(CATEGORY_KEYS[dispute.category] || dispute.category)}
{dispute.evidence && dispute.evidence.length > 0 && (
- {dispute.evidence.length} evidence
+ {t('dispute.evidence', { count: dispute.evidence.length })}
)}
@@ -466,7 +468,7 @@ export function DisputeResolutionPanel() {
onClick={() => openDetails(dispute)}
>
- View
+ {t('dispute.view')}
{dispute.status === 'open' && (
@@ -474,7 +476,7 @@ export function DisputeResolutionPanel() {
size="sm"
onClick={() => claimDispute(dispute.id)}
>
- Claim
+ {t('dispute.claim')}
)}
@@ -485,7 +487,7 @@ export function DisputeResolutionPanel() {
onClick={() => openResolve(dispute)}
>
- Resolve
+ {t('dispute.resolve')}
)}
@@ -504,10 +506,10 @@ export function DisputeResolutionPanel() {
- Dispute Details
+ {t('dispute.detailsTitle')}
- Review all information related to this dispute
+ {t('dispute.detailsDesc')}
@@ -520,13 +522,13 @@ export function DisputeResolutionPanel() {
{selectedDispute.status.replace('_', ' ').toUpperCase()}
- {CATEGORY_LABELS[selectedDispute.category] || selectedDispute.category}
+ {t(CATEGORY_KEYS[selectedDispute.category] || selectedDispute.category)}
{/* Reason */}
-
Reason
+
{t('dispute.reason')}
{selectedDispute.reason}
@@ -535,22 +537,22 @@ export function DisputeResolutionPanel() {
{/* Trade Info */}
{selectedDispute.trade && (
-
Trade Information
+
{t('dispute.tradeInfo')}
- Trade ID:
+ {t('dispute.tradeId')}:
{formatAddress(selectedDispute.trade_id)}
- Amount:
+ {t('dispute.amount')}:
{selectedDispute.trade.crypto_amount} crypto
- Fiat:
+ {t('dispute.fiat')}:
{selectedDispute.trade.fiat_amount}
- Trade Status:
+ {t('dispute.tradeStatus')}:
{selectedDispute.trade.status}
@@ -560,12 +562,12 @@ export function DisputeResolutionPanel() {
{/* Parties */}
{selectedDispute.trade && (
-
Parties
+
{t('dispute.parties')}
- Seller
+ {t('dispute.seller')}
{formatAddress(selectedDispute.trade.seller_id)}
@@ -574,7 +576,7 @@ export function DisputeResolutionPanel() {
- Buyer
+ {t('dispute.buyer')}
{formatAddress(selectedDispute.trade.buyer_id)}
@@ -587,7 +589,7 @@ export function DisputeResolutionPanel() {
{/* Evidence */}
- Evidence ({selectedDispute.evidence?.length || 0})
+ {t('dispute.evidence', { count: selectedDispute.evidence?.length || 0 })}
{selectedDispute.evidence && selectedDispute.evidence.length > 0 ? (
@@ -624,30 +626,30 @@ export function DisputeResolutionPanel() {
))}
) : (
-
No evidence uploaded
+
{t('dispute.noEvidence')}
)}
{/* Timeline */}
-
Timeline
+
{t('dispute.timeline')}
-
Opened:
+
{t('dispute.opened')}:
{formatDate(selectedDispute.created_at)}
{selectedDispute.assigned_at && (
-
Claimed:
+
{t('dispute.claimed')}:
{formatDate(selectedDispute.assigned_at)}
)}
{selectedDispute.resolved_at && (
-
Resolved:
+
{t('dispute.resolved')}:
{formatDate(selectedDispute.resolved_at)}
)}
@@ -657,10 +659,10 @@ export function DisputeResolutionPanel() {
{/* Resolution (if resolved) */}
{selectedDispute.decision && (
-
Resolution
+
{t('dispute.resolution')}
- {DECISION_OPTIONS.find(o => o.value === selectedDispute.decision)?.label}
+ {t(DECISION_OPTION_KEYS.find(o => o.value === selectedDispute.decision)?.labelKey || '')}
{selectedDispute.decision_reasoning && (
@@ -676,7 +678,7 @@ export function DisputeResolutionPanel() {
setDetailsOpen(false)}>
- Close
+ {t('dispute.close')}
{selectedDispute?.status === 'under_review' && (
- Resolve Dispute
+ {t('dispute.resolve')}
)}
@@ -700,29 +702,26 @@ export function DisputeResolutionPanel() {
- Resolve Dispute
+ {t('dispute.resolveTitle')}
- Make a final decision on this dispute. This action cannot be undone.
+ {t('dispute.resolveDesc')}
{/* Decision */}
-
Decision
+
{t('dispute.decision')}
-
+
- {DECISION_OPTIONS.map((option) => (
+ {DECISION_OPTION_KEYS.map((option) => (
- {option.label}
-
- {option.description}
-
+ {t(option.labelKey)}
))}
@@ -733,16 +732,16 @@ export function DisputeResolutionPanel() {
{/* Reasoning */}
- Reasoning (required)
+ {t('dispute.reasoning')} ({t('dispute.required')})
@@ -750,10 +749,9 @@ export function DisputeResolutionPanel() {
-
Important
+
{t('dispute.warningTitle')}
- Your decision will trigger automatic actions on the escrowed funds.
- Make sure you have reviewed all evidence carefully.
+ {t('dispute.warningText')}
@@ -765,7 +763,7 @@ export function DisputeResolutionPanel() {
onClick={() => setResolveOpen(false)}
disabled={submitting}
>
- Cancel
+ {t('dispute.cancel')}
)}
- Confirm Resolution
+ {t('dispute.confirmResolution')}
diff --git a/web/src/components/admin/KycApprovalTab.tsx b/web/src/components/admin/KycApprovalTab.tsx
index 390a5815..6d47cf8e 100644
--- a/web/src/components/admin/KycApprovalTab.tsx
+++ b/web/src/components/admin/KycApprovalTab.tsx
@@ -1,4 +1,5 @@
import { useState, useEffect } from 'react';
+import { useTranslation } from 'react-i18next';
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
import { Button } from '@/components/ui/button';
import { Badge } from '@/components/ui/badge';
@@ -18,6 +19,7 @@ import { approveReferral, getPendingApprovalsForReferrer } from '@pezkuwi/lib/ci
import type { PendingApproval } from '@pezkuwi/lib/citizenship-workflow';
export function KycApprovalTab() {
+ const { t } = useTranslation();
// identityKyc pallet is on People Chain - use peopleApi
const { peopleApi, isPeopleReady, selectedAccount, connectWallet } = usePezkuwi();
const { toast } = useToast();
@@ -52,8 +54,8 @@ export function KycApprovalTab() {
} catch (error) {
if (import.meta.env.DEV) console.error('Error loading pending applications:', error);
toast({
- title: 'Error',
- description: 'Failed to load pending applications',
+ title: t('kyc.approval.failed'),
+ description: t('kyc.approval.failedDesc'),
variant: 'destructive',
});
} finally {
@@ -64,8 +66,8 @@ export function KycApprovalTab() {
const handleApproveReferral = async (applicantAddress: string) => {
if (!peopleApi || !selectedAccount) {
toast({
- title: 'Wallet Not Connected',
- description: 'Please connect your wallet first',
+ title: t('kyc.approval.walletNotConnected'),
+ description: t('kyc.approval.connectFirst'),
variant: 'destructive',
});
return;
@@ -77,16 +79,16 @@ export function KycApprovalTab() {
if (!result.success) {
toast({
- title: 'Approval Failed',
- description: result.error || 'Failed to approve referral',
+ title: t('kyc.approval.failed'),
+ description: result.error || t('kyc.approval.failedDesc'),
variant: 'destructive',
});
return;
}
toast({
- title: 'Referral Approved',
- description: `Successfully vouched for ${applicantAddress.slice(0, 8)}...${applicantAddress.slice(-4)}`,
+ title: t('kyc.approval.success'),
+ description: t('kyc.approval.successDesc', { address: `${applicantAddress.slice(0, 8)}...${applicantAddress.slice(-4)}` }),
});
// Reload after approval
@@ -94,8 +96,8 @@ export function KycApprovalTab() {
} catch (error) {
if (import.meta.env.DEV) console.error('Error approving referral:', error);
toast({
- title: 'Error',
- description: error instanceof Error ? error.message : 'Failed to approve referral',
+ title: t('kyc.approval.failed'),
+ description: error instanceof Error ? error.message : t('kyc.approval.failedDesc'),
variant: 'destructive',
});
} finally {
@@ -109,7 +111,7 @@ export function KycApprovalTab() {
- Connecting to People Chain...
+ {t('kyc.approval.connecting')}
@@ -123,9 +125,9 @@ export function KycApprovalTab() {
- Please connect your wallet to view referral approvals.
+ {t('kyc.approval.noWallet')}
- Connect Wallet
+ {t('kyc.approval.connectWallet')}
@@ -137,9 +139,9 @@ export function KycApprovalTab() {
return (
- Pending Referral Approvals
+ {t('kyc.approval.title')}
- {loading ? : 'Refresh'}
+ {loading ? : t('kyc.approval.refresh')}
@@ -150,21 +152,21 @@ export function KycApprovalTab() {
) : pendingApps.length === 0 ? (
-
No pending approvals
-
No one is waiting for your referral approval
+
{t('kyc.approval.noApprovals')}
+
{t('kyc.approval.noApprovalsHelp')}
) : (
<>
- These users listed you as their referrer. Approve to vouch for their identity.
+ {t('kyc.approval.helpText')}
- Applicant
- Identity Hash
- Status
- Actions
+ {t('kyc.approval.tableApplicant')}
+ {t('kyc.approval.tableIdentityHash')}
+ {t('kyc.approval.tableStatus')}
+ {t('kyc.approval.tableActions')}
@@ -186,7 +188,7 @@ export function KycApprovalTab() {
- Pending Referral
+ {t('kyc.approval.statusPending')}
@@ -201,7 +203,7 @@ export function KycApprovalTab() {
) : (
)}
- Approve
+ {t('kyc.approval.approve')}
diff --git a/web/src/components/admin/XCMConfigurationWizard.tsx b/web/src/components/admin/XCMConfigurationWizard.tsx
index 4548709f..b97d5921 100644
--- a/web/src/components/admin/XCMConfigurationWizard.tsx
+++ b/web/src/components/admin/XCMConfigurationWizard.tsx
@@ -11,6 +11,7 @@
*/
import React, { useState, useEffect } from 'react';
+import { useTranslation } from 'react-i18next';
import { usePezkuwi } from '@/contexts/PezkuwiContext';
import { useWallet } from '@/contexts/WalletContext';
import {
@@ -65,6 +66,7 @@ export const XCMConfigurationWizard: React.FC = ({
onClose,
onSuccess,
}) => {
+ const { t } = useTranslation();
// Use Asset Hub API for asset registration (Step 5) and XCM testing (Step 6)
// Steps 1-4 connect to relay chain directly via xcm-wizard functions
const { assetHubApi, isAssetHubReady } = usePezkuwi();
@@ -138,8 +140,8 @@ export const XCMConfigurationWizard: React.FC = ({
const handleReserveParaId = async () => {
if (!account || !signer) {
toast({
- title: 'Wallet not connected',
- description: 'Please connect your wallet first',
+ title: t('xcmWizard.walletNotConnected'),
+ description: t('xcmWizard.connectFirst'),
variant: 'destructive',
});
return;
@@ -163,8 +165,7 @@ export const XCMConfigurationWizard: React.FC = ({
}));
toast({
- title: 'ParaId Reserved!',
- description: `Successfully reserved ParaId ${paraId} on ${relayChain}`,
+ title: t('xcmWizard.reserveSuccess', { paraId, chain: relayChain }),
});
// Auto-advance to next step
@@ -178,8 +179,8 @@ export const XCMConfigurationWizard: React.FC = ({
1: { completed: false, error: error instanceof Error ? error.message : 'Unknown error' },
}));
toast({
- title: 'Reservation Failed',
- description: error instanceof Error ? error.message : 'Failed to reserve ParaId',
+ title: t('xcmWizard.reserveFailed'),
+ description: error instanceof Error ? error.message : t('xcmWizard.reserveFailed'),
variant: 'destructive',
});
} finally {
@@ -205,8 +206,7 @@ export const XCMConfigurationWizard: React.FC = ({
}));
toast({
- title: 'Artifacts Generated!',
- description: 'Genesis state and runtime WASM are ready for download',
+ title: t('xcmWizard.artifactsReady'),
});
setCurrentStep(3);
@@ -217,8 +217,7 @@ export const XCMConfigurationWizard: React.FC = ({
2: { completed: false, error: error instanceof Error ? error.message : 'Unknown error' },
}));
toast({
- title: 'Generation Failed',
- description: 'Failed to generate chain artifacts',
+ title: t('xcmWizard.artifactsFailed'),
variant: 'destructive',
});
} finally {
@@ -232,8 +231,7 @@ export const XCMConfigurationWizard: React.FC