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:
2026-02-22 04:48:20 +03:00
parent df22c9ba10
commit d282f609aa
129 changed files with 22442 additions and 4186 deletions
+27 -25
View File
@@ -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>
)}
+19 -17
View File
@@ -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>