mirror of
https://github.com/pezkuwichain/pwap.git
synced 2026-04-22 18:17:58 +00:00
feat: complete i18n support for all components (6 languages)
Add full internationalization across 127+ components and pages. 790+ translation keys in en, tr, kmr, ckb, ar, fa locales. Remove duplicate keys and delete unused .json locale files.
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
import { useState } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { supabase } from '@/lib/supabase';
|
||||
import { useAuth } from '@/contexts/AuthContext';
|
||||
import { Button } from '@/components/ui/button';
|
||||
@@ -11,6 +12,7 @@ import { useToast } from '@/hooks/use-toast';
|
||||
export function TwoFactorSetup() {
|
||||
const { user } = useAuth();
|
||||
const { toast } = useToast();
|
||||
const { t } = useTranslation();
|
||||
const [isEnabled, setIsEnabled] = useState(false);
|
||||
const [secret, setSecret] = useState('');
|
||||
const [backupCodes, setBackupCodes] = useState<string[]>([]);
|
||||
@@ -33,12 +35,12 @@ export function TwoFactorSetup() {
|
||||
setShowSetup(true);
|
||||
|
||||
toast({
|
||||
title: '2FA Setup Started',
|
||||
description: 'Scan the QR code with your authenticator app',
|
||||
title: t('twoFactor.setupStarted'),
|
||||
description: t('twoFactor.scanQrDesc'),
|
||||
});
|
||||
} catch (error) {
|
||||
toast({
|
||||
title: 'Setup Failed',
|
||||
title: t('twoFactor.setupFailed'),
|
||||
description: error.message,
|
||||
variant: 'destructive',
|
||||
});
|
||||
@@ -50,8 +52,8 @@ export function TwoFactorSetup() {
|
||||
const handleEnable = async () => {
|
||||
if (!verificationCode) {
|
||||
toast({
|
||||
title: 'Error',
|
||||
description: 'Please enter verification code',
|
||||
title: t('common.error'),
|
||||
description: t('twoFactor.enterVerification'),
|
||||
variant: 'destructive',
|
||||
});
|
||||
return;
|
||||
@@ -73,12 +75,12 @@ export function TwoFactorSetup() {
|
||||
setShowSetup(false);
|
||||
|
||||
toast({
|
||||
title: '2FA Enabled',
|
||||
description: 'Your account is now protected with two-factor authentication',
|
||||
title: t('twoFactor.enabled'),
|
||||
description: t('twoFactor.enabledDesc'),
|
||||
});
|
||||
} catch (error) {
|
||||
toast({
|
||||
title: 'Verification Failed',
|
||||
title: t('twoFactor.verificationFailed'),
|
||||
description: error.message,
|
||||
variant: 'destructive',
|
||||
});
|
||||
@@ -101,12 +103,12 @@ export function TwoFactorSetup() {
|
||||
setBackupCodes([]);
|
||||
|
||||
toast({
|
||||
title: '2FA Disabled',
|
||||
description: 'Two-factor authentication has been disabled',
|
||||
title: t('twoFactor.disabled'),
|
||||
description: t('twoFactor.disabledDesc'),
|
||||
});
|
||||
} catch (error) {
|
||||
toast({
|
||||
title: 'Error',
|
||||
title: t('common.error'),
|
||||
description: error.message,
|
||||
variant: 'destructive',
|
||||
});
|
||||
@@ -126,10 +128,10 @@ export function TwoFactorSetup() {
|
||||
<CardHeader>
|
||||
<CardTitle className="flex items-center gap-2">
|
||||
<Shield className="h-5 w-5" />
|
||||
Two-Factor Authentication
|
||||
{t('twoFactor.title')}
|
||||
</CardTitle>
|
||||
<CardDescription>
|
||||
Add an extra layer of security to your account
|
||||
{t('twoFactor.description')}
|
||||
</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent className="space-y-4">
|
||||
@@ -138,11 +140,11 @@ export function TwoFactorSetup() {
|
||||
<Alert>
|
||||
<AlertCircle className="h-4 w-4" />
|
||||
<AlertDescription>
|
||||
Two-factor authentication adds an extra layer of security by requiring a code from your authenticator app
|
||||
{t('twoFactor.infoAlert')}
|
||||
</AlertDescription>
|
||||
</Alert>
|
||||
<Button onClick={handleSetup} disabled={isLoading}>
|
||||
Set Up Two-Factor Authentication
|
||||
{t('twoFactor.setupBtn')}
|
||||
</Button>
|
||||
</div>
|
||||
)}
|
||||
@@ -150,9 +152,9 @@ export function TwoFactorSetup() {
|
||||
{showSetup && (
|
||||
<div className="space-y-4">
|
||||
<div className="p-4 border rounded-lg">
|
||||
<p className="text-sm font-medium mb-2">1. Scan QR Code</p>
|
||||
<p className="text-sm font-medium mb-2">{t('twoFactor.scanQrTitle')}</p>
|
||||
<p className="text-xs text-muted-foreground mb-4">
|
||||
Use your authenticator app to scan this QR code or enter the secret manually
|
||||
{t('twoFactor.scanQrHint')}
|
||||
</p>
|
||||
<div className="bg-muted p-2 rounded font-mono text-xs break-all">
|
||||
{secret}
|
||||
@@ -160,9 +162,9 @@ export function TwoFactorSetup() {
|
||||
</div>
|
||||
|
||||
<div className="p-4 border rounded-lg">
|
||||
<p className="text-sm font-medium mb-2">2. Save Backup Codes</p>
|
||||
<p className="text-sm font-medium mb-2">{t('twoFactor.saveBackup')}</p>
|
||||
<p className="text-xs text-muted-foreground mb-4">
|
||||
Store these codes in a safe place. You can use them to access your account if you lose your device.
|
||||
{t('twoFactor.saveBackupHint')}
|
||||
</p>
|
||||
<div className="bg-muted p-3 rounded space-y-1">
|
||||
{backupCodes.map((code, i) => (
|
||||
@@ -176,14 +178,14 @@ export function TwoFactorSetup() {
|
||||
onClick={copyBackupCodes}
|
||||
>
|
||||
{copiedCodes ? <Check className="h-4 w-4 mr-2" /> : <Copy className="h-4 w-4 mr-2" />}
|
||||
{copiedCodes ? 'Copied!' : 'Copy Codes'}
|
||||
{copiedCodes ? t('twoFactor.copied') : t('twoFactor.copyCodes')}
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
<div className="p-4 border rounded-lg">
|
||||
<p className="text-sm font-medium mb-2">3. Verify Setup</p>
|
||||
<p className="text-sm font-medium mb-2">{t('twoFactor.verifySetup')}</p>
|
||||
<p className="text-xs text-muted-foreground mb-4">
|
||||
Enter the 6-digit code from your authenticator app
|
||||
{t('twoFactor.enterCode')}
|
||||
</p>
|
||||
<div className="flex gap-2">
|
||||
<Input
|
||||
@@ -193,7 +195,7 @@ export function TwoFactorSetup() {
|
||||
maxLength={6}
|
||||
/>
|
||||
<Button onClick={handleEnable} disabled={isLoading}>
|
||||
Enable 2FA
|
||||
{t('twoFactor.enableBtn')}
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
@@ -205,11 +207,11 @@ export function TwoFactorSetup() {
|
||||
<Alert className="border-green-200 bg-green-50">
|
||||
<Check className="h-4 w-4 text-green-600" />
|
||||
<AlertDescription className="text-green-800">
|
||||
Two-factor authentication is enabled for your account
|
||||
{t('twoFactor.enabledAlert')}
|
||||
</AlertDescription>
|
||||
</Alert>
|
||||
<Button variant="destructive" onClick={handleDisable} disabled={isLoading}>
|
||||
Disable Two-Factor Authentication
|
||||
{t('twoFactor.disableBtn')}
|
||||
</Button>
|
||||
</div>
|
||||
)}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { useState } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { supabase } from '@/lib/supabase';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { Input } from '@/components/ui/input';
|
||||
@@ -16,6 +17,7 @@ interface TwoFactorVerifyProps {
|
||||
|
||||
export function TwoFactorVerify({ userId, onSuccess, onCancel }: TwoFactorVerifyProps) {
|
||||
const { toast } = useToast();
|
||||
const { t } = useTranslation();
|
||||
const [verificationCode, setVerificationCode] = useState('');
|
||||
const [backupCode, setBackupCode] = useState('');
|
||||
const [isLoading, setIsLoading] = useState(false);
|
||||
@@ -25,8 +27,8 @@ export function TwoFactorVerify({ userId, onSuccess, onCancel }: TwoFactorVerify
|
||||
|
||||
if (!code) {
|
||||
toast({
|
||||
title: 'Error',
|
||||
description: 'Please enter a code',
|
||||
title: t('common.error'),
|
||||
description: t('twoFactor.pleaseEnterCode'),
|
||||
variant: 'destructive',
|
||||
});
|
||||
return;
|
||||
@@ -47,8 +49,8 @@ export function TwoFactorVerify({ userId, onSuccess, onCancel }: TwoFactorVerify
|
||||
|
||||
if (data.success) {
|
||||
toast({
|
||||
title: 'Verification Successful',
|
||||
description: 'You have been authenticated',
|
||||
title: t('twoFactor.verifySuccess'),
|
||||
description: t('twoFactor.authenticated'),
|
||||
});
|
||||
onSuccess();
|
||||
} else {
|
||||
@@ -56,7 +58,7 @@ export function TwoFactorVerify({ userId, onSuccess, onCancel }: TwoFactorVerify
|
||||
}
|
||||
} catch (error) {
|
||||
toast({
|
||||
title: 'Verification Failed',
|
||||
title: t('twoFactor.verificationFailed'),
|
||||
description: error.message,
|
||||
variant: 'destructive',
|
||||
});
|
||||
@@ -70,23 +72,23 @@ export function TwoFactorVerify({ userId, onSuccess, onCancel }: TwoFactorVerify
|
||||
<CardHeader>
|
||||
<CardTitle className="flex items-center gap-2">
|
||||
<Shield className="h-5 w-5" />
|
||||
Two-Factor Authentication
|
||||
{t('twoFactor.title')}
|
||||
</CardTitle>
|
||||
<CardDescription>
|
||||
Enter your authentication code to continue
|
||||
{t('twoFactor.enterAuthCode')}
|
||||
</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<Tabs defaultValue="authenticator" className="w-full">
|
||||
<TabsList className="grid w-full grid-cols-2">
|
||||
<TabsTrigger value="authenticator">Authenticator App</TabsTrigger>
|
||||
<TabsTrigger value="backup">Backup Code</TabsTrigger>
|
||||
<TabsTrigger value="authenticator">{t('twoFactor.authenticatorTab')}</TabsTrigger>
|
||||
<TabsTrigger value="backup">{t('twoFactor.backupTab')}</TabsTrigger>
|
||||
</TabsList>
|
||||
|
||||
<TabsContent value="authenticator" className="space-y-4">
|
||||
<Alert>
|
||||
<AlertDescription>
|
||||
Enter the 6-digit code from your authenticator app
|
||||
{t('twoFactor.enterCode')}
|
||||
</AlertDescription>
|
||||
</Alert>
|
||||
<Input
|
||||
@@ -99,15 +101,15 @@ export function TwoFactorVerify({ userId, onSuccess, onCancel }: TwoFactorVerify
|
||||
<div className="flex gap-2">
|
||||
<Button
|
||||
className="flex-1"
|
||||
onClick={() => handleVerify(false)}
|
||||
onClick={() => handleVerify(false)}
|
||||
disabled={isLoading}
|
||||
>
|
||||
{isLoading && <Loader2 className="mr-2 h-4 w-4 animate-spin" />}
|
||||
Verify
|
||||
{t('twoFactor.verify')}
|
||||
</Button>
|
||||
{onCancel && (
|
||||
<Button variant="outline" onClick={onCancel} disabled={isLoading}>
|
||||
Cancel
|
||||
{t('common.cancel')}
|
||||
</Button>
|
||||
)}
|
||||
</div>
|
||||
@@ -116,7 +118,7 @@ export function TwoFactorVerify({ userId, onSuccess, onCancel }: TwoFactorVerify
|
||||
<TabsContent value="backup" className="space-y-4">
|
||||
<Alert>
|
||||
<AlertDescription>
|
||||
Enter one of your backup codes
|
||||
{t('twoFactor.enterBackupCode')}
|
||||
</AlertDescription>
|
||||
</Alert>
|
||||
<Input
|
||||
@@ -128,15 +130,15 @@ export function TwoFactorVerify({ userId, onSuccess, onCancel }: TwoFactorVerify
|
||||
<div className="flex gap-2">
|
||||
<Button
|
||||
className="flex-1"
|
||||
onClick={() => handleVerify(true)}
|
||||
onClick={() => handleVerify(true)}
|
||||
disabled={isLoading}
|
||||
>
|
||||
{isLoading && <Loader2 className="mr-2 h-4 w-4 animate-spin" />}
|
||||
Verify
|
||||
{t('twoFactor.verify')}
|
||||
</Button>
|
||||
{onCancel && (
|
||||
<Button variant="outline" onClick={onCancel} disabled={isLoading}>
|
||||
Cancel
|
||||
{t('common.cancel')}
|
||||
</Button>
|
||||
)}
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user