mirror of
https://github.com/pezkuwichain/pezkuwi-telegram-miniapp.git
synced 2026-06-09 20:21:05 +00:00
feat: add i18n support with 6 languages (en, tr, krd, ar, fa, ckb)
- Add translation system with useTranslation hook and LanguageProvider - Auto-detect language from Telegram user settings - Update all components and sections to use translation keys - Support English, Turkish, Kurdish, Arabic, Persian, Sorani
This commit is contained in:
+1
-1
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "pezkuwi-telegram-miniapp",
|
||||
"version": "1.0.185",
|
||||
"version": "1.0.186",
|
||||
"type": "module",
|
||||
"description": "Pezkuwichain Telegram Mini App - Forum, Announcements, Rewards",
|
||||
"author": "Pezkuwichain Team",
|
||||
|
||||
+9
-7
@@ -5,6 +5,7 @@ import { UpdateNotification } from '@/components/UpdateNotification';
|
||||
import { P2PModal } from '@/components/P2PModal';
|
||||
import { useAuth } from '@/contexts/AuthContext';
|
||||
import { useWallet } from '@/contexts/WalletContext';
|
||||
import { useTranslation } from '@/i18n';
|
||||
|
||||
// Lazy load sections for code splitting
|
||||
const AnnouncementsSection = lazy(() =>
|
||||
@@ -35,16 +36,16 @@ type NavId = Section | 'p2p';
|
||||
interface NavItem {
|
||||
id: NavId;
|
||||
icon: typeof Megaphone;
|
||||
label: string;
|
||||
labelKey: string;
|
||||
isExternal?: boolean;
|
||||
}
|
||||
|
||||
const NAV_ITEMS: NavItem[] = [
|
||||
{ id: 'announcements', icon: Megaphone, label: 'Ragihandin' },
|
||||
{ id: 'forum', icon: MessageCircle, label: 'Forum' },
|
||||
{ id: 'rewards', icon: Gift, label: 'Xelat' },
|
||||
{ id: 'p2p', icon: ArrowLeftRight, label: 'P2P', isExternal: true },
|
||||
{ id: 'wallet', icon: Wallet, label: 'Berîk' },
|
||||
{ id: 'announcements', icon: Megaphone, labelKey: 'nav.announcements' },
|
||||
{ id: 'forum', icon: MessageCircle, labelKey: 'nav.forum' },
|
||||
{ id: 'rewards', icon: Gift, labelKey: 'nav.rewards' },
|
||||
{ id: 'p2p', icon: ArrowLeftRight, labelKey: 'nav.p2p', isExternal: true },
|
||||
{ id: 'wallet', icon: Wallet, labelKey: 'nav.wallet' },
|
||||
];
|
||||
|
||||
// P2P Web App URL - Mobile-optimized P2P
|
||||
@@ -55,6 +56,7 @@ export default function App() {
|
||||
const [showP2PModal, setShowP2PModal] = useState(false);
|
||||
const { sessionToken } = useAuth();
|
||||
const { address } = useWallet();
|
||||
const { t } = useTranslation();
|
||||
|
||||
// Open P2P in popup with auth params
|
||||
const openP2P = useCallback(() => {
|
||||
@@ -127,7 +129,7 @@ export default function App() {
|
||||
)}
|
||||
>
|
||||
<Icon className={cn('w-5 h-5', isActive && 'scale-110')} />
|
||||
<span className="text-[10px] font-medium">{item.label}</span>
|
||||
<span className="text-[10px] font-medium">{t(item.labelKey)}</span>
|
||||
</button>
|
||||
);
|
||||
})}
|
||||
|
||||
@@ -1,6 +1,21 @@
|
||||
import { Component, ErrorInfo, ReactNode } from 'react';
|
||||
import { AlertTriangle, RefreshCw } from 'lucide-react';
|
||||
import { trackError } from '@/lib/error-tracking';
|
||||
import krd from '@/i18n/translations/krd';
|
||||
import en from '@/i18n/translations/en';
|
||||
import tr from '@/i18n/translations/tr';
|
||||
import ckb from '@/i18n/translations/ckb';
|
||||
import fa from '@/i18n/translations/fa';
|
||||
import ar from '@/i18n/translations/ar';
|
||||
import type { Translations, LanguageCode } from '@/i18n/types';
|
||||
|
||||
const translations: Record<LanguageCode, Translations> = { krd, en, tr, ckb, fa, ar };
|
||||
|
||||
function detectLang(): LanguageCode {
|
||||
const seg = window.location.pathname.split('/').filter(Boolean)[0];
|
||||
if (seg && seg in translations) return seg as LanguageCode;
|
||||
return 'krd';
|
||||
}
|
||||
|
||||
interface Props {
|
||||
children: ReactNode;
|
||||
@@ -52,16 +67,18 @@ export class ErrorBoundary extends Component<Props, State> {
|
||||
<div className="w-16 h-16 rounded-full bg-red-500/20 flex items-center justify-center mb-4">
|
||||
<AlertTriangle className="w-8 h-8 text-red-400" />
|
||||
</div>
|
||||
<h1 className="text-xl font-semibold mb-2">Tiştek çewt çêbû</h1>
|
||||
<h1 className="text-xl font-semibold mb-2">
|
||||
{translations[detectLang()].errorBoundary.title}
|
||||
</h1>
|
||||
<p className="text-sm text-muted-foreground text-center mb-6 max-w-xs">
|
||||
Bibore, pirsgirêkek teknîkî derket. Ji kerema xwe dîsa biceribîne.
|
||||
{translations[detectLang()].errorBoundary.description}
|
||||
</p>
|
||||
<button
|
||||
onClick={this.handleRetry}
|
||||
className="flex items-center gap-2 px-4 py-2 bg-primary rounded-lg text-primary-foreground font-medium"
|
||||
>
|
||||
<RefreshCw className="w-4 h-4" />
|
||||
Dîsa biceribîne
|
||||
{translations[detectLang()].errorBoundary.retry}
|
||||
</button>
|
||||
{import.meta.env.DEV && this.state.error && (
|
||||
<div className="mt-6 w-full max-w-lg">
|
||||
|
||||
@@ -1,10 +1,13 @@
|
||||
import { Loader2 } from 'lucide-react';
|
||||
import { useTranslation } from '@/i18n';
|
||||
|
||||
interface LoadingScreenProps {
|
||||
message?: string;
|
||||
}
|
||||
|
||||
export function LoadingScreen({ message = 'Tê barkirin...' }: LoadingScreenProps) {
|
||||
export function LoadingScreen({ message }: LoadingScreenProps) {
|
||||
const { t } = useTranslation();
|
||||
const displayMessage = message ?? t('loadingScreen.loading');
|
||||
return (
|
||||
<div className="flex flex-col items-center justify-center min-h-screen bg-background">
|
||||
<div className="relative">
|
||||
@@ -12,7 +15,7 @@ export function LoadingScreen({ message = 'Tê barkirin...' }: LoadingScreenProp
|
||||
<Loader2 className="w-8 h-8 text-primary animate-spin" />
|
||||
</div>
|
||||
</div>
|
||||
<p className="mt-4 text-sm text-muted-foreground">{message}</p>
|
||||
<p className="mt-4 text-sm text-muted-foreground">{displayMessage}</p>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
+16
-102
@@ -1,6 +1,6 @@
|
||||
import { useState } from 'react';
|
||||
import { X, ExternalLink, Info } from 'lucide-react';
|
||||
import { cn } from '@/lib/utils';
|
||||
import { useTranslation } from '@/i18n';
|
||||
|
||||
interface P2PModalProps {
|
||||
isOpen: boolean;
|
||||
@@ -8,84 +8,8 @@ interface P2PModalProps {
|
||||
onOpenP2P: () => void;
|
||||
}
|
||||
|
||||
type Language = 'en' | 'ckb' | 'ku' | 'tr';
|
||||
|
||||
const LANGUAGES: { code: Language; label: string }[] = [
|
||||
{ code: 'en', label: 'EN' },
|
||||
{ code: 'ckb', label: 'سۆرانی' },
|
||||
{ code: 'ku', label: 'Kurmancî' },
|
||||
{ code: 'tr', label: 'TR' },
|
||||
];
|
||||
|
||||
const CONTENT: Record<
|
||||
Language,
|
||||
{
|
||||
title: string;
|
||||
subtitle: string;
|
||||
firstTime: string;
|
||||
steps: string[];
|
||||
note: string;
|
||||
button: string;
|
||||
}
|
||||
> = {
|
||||
en: {
|
||||
title: 'P2P Exchange',
|
||||
subtitle: 'Trade crypto peer-to-peer',
|
||||
firstTime: 'First time using P2P?',
|
||||
steps: [
|
||||
'Click the button below to open the web app',
|
||||
'Create an account or log in',
|
||||
'Complete the P2P setup process',
|
||||
'After setup, you can access P2P directly',
|
||||
],
|
||||
note: 'The web app will open in a new window. Complete the registration process there.',
|
||||
button: 'Open P2P Platform',
|
||||
},
|
||||
ckb: {
|
||||
title: 'P2P ئاڵۆگۆڕ',
|
||||
subtitle: 'ئاڵۆگۆڕی کریپتۆ لە نێوان کەسەکاندا',
|
||||
firstTime: 'یەکەم جار P2P بەکاردەهێنیت؟',
|
||||
steps: [
|
||||
'کلیک لە دوگمەی خوارەوە بکە بۆ کردنەوەی ماڵپەڕ',
|
||||
'هەژمارێک دروست بکە یان بچۆ ژوورەوە',
|
||||
'پرۆسەی دامەزراندنی P2P تەواو بکە',
|
||||
'دوای دامەزراندن، دەتوانیت ڕاستەوخۆ بچیتە P2P',
|
||||
],
|
||||
note: 'ماڵپەڕ لە پەنجەرەیەکی نوێ دەکرێتەوە. پرۆسەی تۆمارکردن لەوێ تەواو بکە.',
|
||||
button: 'کردنەوەی P2P',
|
||||
},
|
||||
ku: {
|
||||
title: 'P2P Danûstandin',
|
||||
subtitle: 'Danûstandina krîpto di navbera kesan de',
|
||||
firstTime: 'Cara yekem P2P bikar tînin?',
|
||||
steps: [
|
||||
'Li bişkoja jêrîn bikirtînin da ku malpera webê vebike',
|
||||
'Hesabek çêbikin an têkevin',
|
||||
'Pêvajoya sazkirina P2P temam bikin',
|
||||
'Piştî sazkirinê, hûn dikarin rasterast bigihîjin P2P',
|
||||
],
|
||||
note: 'Malpera webê di pencereyek nû de vedibe. Pêvajoya qeydkirinê li wir temam bikin.',
|
||||
button: 'P2P Veke',
|
||||
},
|
||||
tr: {
|
||||
title: 'P2P Borsa',
|
||||
subtitle: 'Kullanıcılar arası kripto alım satım',
|
||||
firstTime: "P2P'yi ilk kez mi kullanıyorsunuz?",
|
||||
steps: [
|
||||
'Web uygulamasını açmak için aşağıdaki butona tıklayın',
|
||||
'Hesap oluşturun veya giriş yapın',
|
||||
'P2P kurulum sürecini tamamlayın',
|
||||
"Kurulumdan sonra P2P'ye doğrudan erişebilirsiniz",
|
||||
],
|
||||
note: 'Web uygulaması yeni bir pencerede açılacak. Kayıt işlemini orada tamamlayın.',
|
||||
button: 'P2P Platformunu Aç',
|
||||
},
|
||||
};
|
||||
|
||||
export function P2PModal({ isOpen, onClose, onOpenP2P }: P2PModalProps) {
|
||||
const [lang, setLang] = useState<Language>('en');
|
||||
const content = CONTENT[lang];
|
||||
const isRTL = lang === 'ckb';
|
||||
const { t, isRTL } = useTranslation();
|
||||
|
||||
if (!isOpen) return null;
|
||||
|
||||
@@ -94,6 +18,14 @@ export function P2PModal({ isOpen, onClose, onOpenP2P }: P2PModalProps) {
|
||||
onClose();
|
||||
};
|
||||
|
||||
// Access steps array directly - t() only works for string values
|
||||
// We need to get the steps from the translation as individual indexed items
|
||||
const steps: string[] = [];
|
||||
for (let i = 0; i < 4; i++) {
|
||||
const step = t(`p2p.steps.${i}`);
|
||||
if (step !== `p2p.steps.${i}`) steps.push(step);
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="fixed inset-0 z-50 flex items-center justify-center p-4 bg-black/70 backdrop-blur-sm">
|
||||
<div
|
||||
@@ -105,42 +37,24 @@ export function P2PModal({ isOpen, onClose, onOpenP2P }: P2PModalProps) {
|
||||
>
|
||||
{/* Header */}
|
||||
<div className="flex items-center justify-between p-4 border-b border-border">
|
||||
<h2 className="text-lg font-semibold text-foreground">{content.title}</h2>
|
||||
<h2 className="text-lg font-semibold text-foreground">{t('p2p.title')}</h2>
|
||||
<button onClick={onClose} className="p-2 rounded-full hover:bg-muted transition-colors">
|
||||
<X className="w-5 h-5 text-muted-foreground" />
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{/* Language Selector */}
|
||||
<div className="flex gap-2 p-4 pb-0">
|
||||
{LANGUAGES.map((l) => (
|
||||
<button
|
||||
key={l.code}
|
||||
onClick={() => setLang(l.code)}
|
||||
className={cn(
|
||||
'px-3 py-1.5 rounded-full text-xs font-medium transition-colors',
|
||||
lang === l.code
|
||||
? 'bg-primary text-primary-foreground'
|
||||
: 'bg-muted text-muted-foreground hover:bg-muted/80'
|
||||
)}
|
||||
>
|
||||
{l.label}
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
|
||||
{/* Content */}
|
||||
<div className="p-4 space-y-4">
|
||||
<p className="text-sm text-muted-foreground">{content.subtitle}</p>
|
||||
<p className="text-sm text-muted-foreground">{t('p2p.subtitle')}</p>
|
||||
|
||||
{/* First Time Info */}
|
||||
<div className="bg-amber-500/10 border border-amber-500/30 rounded-xl p-4">
|
||||
<div className="flex items-start gap-3">
|
||||
<Info className="w-5 h-5 text-amber-400 flex-shrink-0 mt-0.5" />
|
||||
<div className="space-y-2">
|
||||
<p className="text-sm font-medium text-amber-400">{content.firstTime}</p>
|
||||
<p className="text-sm font-medium text-amber-400">{t('p2p.firstTime')}</p>
|
||||
<ol className="space-y-1.5">
|
||||
{content.steps.map((step, i) => (
|
||||
{steps.map((step, i) => (
|
||||
<li key={i} className="text-xs text-amber-200/80 flex gap-2">
|
||||
<span className="font-semibold text-amber-400">{i + 1}.</span>
|
||||
<span>{step}</span>
|
||||
@@ -152,7 +66,7 @@ export function P2PModal({ isOpen, onClose, onOpenP2P }: P2PModalProps) {
|
||||
</div>
|
||||
|
||||
{/* Note */}
|
||||
<p className="text-xs text-muted-foreground">{content.note}</p>
|
||||
<p className="text-xs text-muted-foreground">{t('p2p.note')}</p>
|
||||
</div>
|
||||
|
||||
{/* Action Button */}
|
||||
@@ -162,7 +76,7 @@ export function P2PModal({ isOpen, onClose, onOpenP2P }: P2PModalProps) {
|
||||
className="w-full flex items-center justify-center gap-2 py-3 px-4 bg-cyan-500 hover:bg-cyan-600 text-white font-medium rounded-xl transition-colors"
|
||||
>
|
||||
<ExternalLink className="w-5 h-5" />
|
||||
{content.button}
|
||||
{t('p2p.button')}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
import { ExternalLink } from 'lucide-react';
|
||||
import { useTelegram } from '@/hooks/useTelegram';
|
||||
import { useTranslation } from '@/i18n';
|
||||
|
||||
interface SocialLink {
|
||||
name: string;
|
||||
url: string;
|
||||
icon: string;
|
||||
color: string;
|
||||
description: string;
|
||||
descriptionKey: string;
|
||||
}
|
||||
|
||||
const SOCIAL_LINKS: SocialLink[] = [
|
||||
@@ -15,61 +16,62 @@ const SOCIAL_LINKS: SocialLink[] = [
|
||||
url: 'https://www.instagram.com/pezkuwichain',
|
||||
icon: '📸',
|
||||
color: 'from-pink-500 to-purple-600',
|
||||
description: 'Wêne û Story',
|
||||
descriptionKey: 'social.instagram',
|
||||
},
|
||||
{
|
||||
name: 'TikTok',
|
||||
url: 'https://www.tiktok.com/@pezkuwi.chain',
|
||||
icon: '🎵',
|
||||
color: 'from-gray-800 to-gray-900',
|
||||
description: 'Vîdyoyên kurt',
|
||||
descriptionKey: 'social.tiktok',
|
||||
},
|
||||
{
|
||||
name: 'Snapchat',
|
||||
url: 'https://www.snapchat.com/add/pezkuwichain',
|
||||
icon: '👻',
|
||||
color: 'from-yellow-400 to-yellow-500',
|
||||
description: 'Snap bike!',
|
||||
descriptionKey: 'social.snapchat',
|
||||
},
|
||||
{
|
||||
name: 'Telegram',
|
||||
url: 'https://t.me/pezkuwichain',
|
||||
icon: '📢',
|
||||
color: 'from-blue-400 to-blue-600',
|
||||
description: 'Kanala fermî',
|
||||
descriptionKey: 'social.telegram',
|
||||
},
|
||||
{
|
||||
name: 'X (Twitter)',
|
||||
url: 'https://x.com/pezkuwichain',
|
||||
icon: '𝕏',
|
||||
color: 'from-gray-700 to-gray-900',
|
||||
description: 'Nûçeyên rojane',
|
||||
descriptionKey: 'social.twitter',
|
||||
},
|
||||
{
|
||||
name: 'YouTube',
|
||||
url: 'https://www.youtube.com/@SatoshiQazi',
|
||||
icon: '▶️',
|
||||
color: 'from-red-500 to-red-700',
|
||||
description: 'Vîdyoyên me',
|
||||
descriptionKey: 'social.youtube',
|
||||
},
|
||||
{
|
||||
name: 'Facebook',
|
||||
url: 'https://www.facebook.com/people/Pezkuwi-Chain/61587122224932/',
|
||||
icon: '📘',
|
||||
color: 'from-blue-600 to-blue-800',
|
||||
description: 'Rûpela fermî',
|
||||
descriptionKey: 'social.facebook',
|
||||
},
|
||||
{
|
||||
name: 'Discord',
|
||||
url: 'https://discord.gg/Y3VyEC6h8W',
|
||||
icon: '💬',
|
||||
color: 'from-indigo-500 to-purple-600',
|
||||
description: 'Civaka me',
|
||||
descriptionKey: 'social.discord',
|
||||
},
|
||||
];
|
||||
|
||||
export function SocialLinks() {
|
||||
const { openLink, hapticImpact } = useTelegram();
|
||||
const { t } = useTranslation();
|
||||
|
||||
const handleClick = (url: string) => {
|
||||
hapticImpact('light');
|
||||
@@ -80,11 +82,9 @@ export function SocialLinks() {
|
||||
<div className="bg-secondary/30 rounded-xl p-4 border border-border/50">
|
||||
<h3 className="font-medium text-foreground mb-3 flex items-center gap-2">
|
||||
<ExternalLink className="w-4 h-4 text-primary" />
|
||||
Me bişopîne
|
||||
{t('social.followUs')}
|
||||
</h3>
|
||||
<p className="text-sm text-muted-foreground mb-4">
|
||||
Bi me re têkiliyê ragire û nûçeyên herî dawî bistîne!
|
||||
</p>
|
||||
<p className="text-sm text-muted-foreground mb-4">{t('social.stayConnected')}</p>
|
||||
<div className="grid grid-cols-2 gap-2">
|
||||
{SOCIAL_LINKS.map((link) => (
|
||||
<button
|
||||
@@ -100,7 +100,7 @@ export function SocialLinks() {
|
||||
<span className="text-2xl">{link.icon}</span>
|
||||
<div className="text-left">
|
||||
<p className="text-sm font-medium text-white">{link.name}</p>
|
||||
<p className="text-xs text-white/70">{link.description}</p>
|
||||
<p className="text-xs text-white/70">{t(link.descriptionKey)}</p>
|
||||
</div>
|
||||
</button>
|
||||
))}
|
||||
|
||||
@@ -6,10 +6,12 @@
|
||||
import { RefreshCw, X } from 'lucide-react';
|
||||
import { useVersion } from '@/hooks/useVersion';
|
||||
import { useTelegram } from '@/hooks/useTelegram';
|
||||
import { useTranslation } from '@/i18n';
|
||||
|
||||
export function UpdateNotification() {
|
||||
const { hasUpdate, forceUpdate, dismissUpdate, currentVersion } = useVersion();
|
||||
const { hapticImpact } = useTelegram();
|
||||
const { t } = useTranslation();
|
||||
|
||||
if (!hasUpdate) return null;
|
||||
|
||||
@@ -31,10 +33,8 @@ export function UpdateNotification() {
|
||||
<RefreshCw className="w-5 h-5" />
|
||||
</div>
|
||||
<div className="flex-1 min-w-0">
|
||||
<h4 className="font-semibold text-sm">Guhertoya nû heye!</h4>
|
||||
<p className="text-xs opacity-90 mt-0.5">
|
||||
Ji bo taybetmendiyên nû û rastkirinên ewlehiyê nûve bike.
|
||||
</p>
|
||||
<h4 className="font-semibold text-sm">{t('update.newVersion')}</h4>
|
||||
<p className="text-xs opacity-90 mt-0.5">{t('update.description')}</p>
|
||||
<p className="text-[10px] opacity-70 mt-1">v{currentVersion}</p>
|
||||
</div>
|
||||
<button
|
||||
@@ -50,14 +50,14 @@ export function UpdateNotification() {
|
||||
onClick={handleDismiss}
|
||||
className="flex-1 py-2 px-3 rounded-lg bg-white/10 hover:bg-white/20 text-sm font-medium transition-colors"
|
||||
>
|
||||
Paşê
|
||||
{t('update.later')}
|
||||
</button>
|
||||
<button
|
||||
onClick={handleUpdate}
|
||||
className="flex-1 py-2 px-3 rounded-lg bg-white text-primary text-sm font-medium hover:bg-white/90 transition-colors flex items-center justify-center gap-2"
|
||||
>
|
||||
<RefreshCw className="w-4 h-4" />
|
||||
Nûve bike
|
||||
{t('update.updateNow')}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -18,6 +18,7 @@ import {
|
||||
import { useTelegram } from '@/hooks/useTelegram';
|
||||
import { useWallet } from '@/contexts/WalletContext';
|
||||
import { supabase } from '@/lib/supabase';
|
||||
import { useTranslation } from '@/i18n';
|
||||
|
||||
type Network = 'ton' | 'polkadot' | 'trc20';
|
||||
|
||||
@@ -28,7 +29,7 @@ interface NetworkInfo {
|
||||
icon: string;
|
||||
recommended: boolean;
|
||||
fee: number;
|
||||
feeWarning?: string;
|
||||
feeWarning?: boolean;
|
||||
explorer: string;
|
||||
minDeposit: number;
|
||||
}
|
||||
@@ -61,7 +62,7 @@ const NETWORKS: NetworkInfo[] = [
|
||||
icon: '🔴',
|
||||
recommended: false,
|
||||
fee: 3,
|
||||
feeWarning: 'Mesrefa tora TRC20 bi qasî $3 ye. Em tora TON an Polkadot pêşniyar dikin.',
|
||||
feeWarning: true,
|
||||
explorer: 'https://tronscan.org/#/transaction/',
|
||||
minDeposit: 10,
|
||||
},
|
||||
@@ -84,6 +85,7 @@ interface Props {
|
||||
export function DepositUSDTModal({ isOpen, onClose }: Props) {
|
||||
const { hapticImpact, showAlert } = useTelegram();
|
||||
const { address: localWalletAddress } = useWallet();
|
||||
const { t } = useTranslation();
|
||||
|
||||
const [selectedNetwork, setSelectedNetwork] = useState<Network>('ton');
|
||||
const [depositCode, setDepositCode] = useState<string>('');
|
||||
@@ -184,7 +186,7 @@ export function DepositUSDTModal({ isOpen, onClose }: Props) {
|
||||
hapticImpact('light');
|
||||
setTimeout(() => setCopied(null), 2000);
|
||||
} catch {
|
||||
showAlert('Kopî nekir');
|
||||
showAlert(t('deposit.copyFailed'));
|
||||
}
|
||||
};
|
||||
|
||||
@@ -204,15 +206,15 @@ export function DepositUSDTModal({ isOpen, onClose }: Props) {
|
||||
const getStatusText = (status: string) => {
|
||||
switch (status) {
|
||||
case 'pending':
|
||||
return 'Li benda';
|
||||
return t('deposit.statusPending');
|
||||
case 'confirming':
|
||||
return 'Tê pejirandin';
|
||||
return t('deposit.statusConfirming');
|
||||
case 'completed':
|
||||
return 'Qediya';
|
||||
return t('deposit.statusCompleted');
|
||||
case 'failed':
|
||||
return 'Neserketî';
|
||||
return t('deposit.statusFailed');
|
||||
case 'expired':
|
||||
return 'Dema wê derbas bû';
|
||||
return t('deposit.statusExpired');
|
||||
default:
|
||||
return status;
|
||||
}
|
||||
@@ -233,8 +235,8 @@ export function DepositUSDTModal({ isOpen, onClose }: Props) {
|
||||
<Plus className="w-5 h-5 text-green-400" />
|
||||
</div>
|
||||
<div>
|
||||
<h2 className="text-lg font-semibold">USDT Depo Bike</h2>
|
||||
<p className="text-xs text-muted-foreground">Bo wUSDT li Asset Hub</p>
|
||||
<h2 className="text-lg font-semibold">{t('deposit.title')}</h2>
|
||||
<p className="text-xs text-muted-foreground">{t('deposit.subtitle')}</p>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex gap-2">
|
||||
@@ -256,9 +258,11 @@ export function DepositUSDTModal({ isOpen, onClose }: Props) {
|
||||
{showHistory ? (
|
||||
/* Deposit History */
|
||||
<div className="space-y-3">
|
||||
<h3 className="text-sm font-medium text-muted-foreground">Dîroka Depoyan</h3>
|
||||
<h3 className="text-sm font-medium text-muted-foreground">
|
||||
{t('deposit.depositHistory')}
|
||||
</h3>
|
||||
{deposits.length === 0 ? (
|
||||
<p className="text-center text-muted-foreground py-8">Hîn depo tune</p>
|
||||
<p className="text-center text-muted-foreground py-8">{t('deposit.noDeposits')}</p>
|
||||
) : (
|
||||
deposits.map((deposit) => (
|
||||
<div key={deposit.id} className="bg-muted/50 rounded-xl p-3">
|
||||
@@ -290,7 +294,7 @@ export function DepositUSDTModal({ isOpen, onClose }: Props) {
|
||||
className="text-xs text-blue-400 flex items-center gap-1 mt-2"
|
||||
>
|
||||
<ExternalLink className="w-3 h-3" />
|
||||
TX bibîne
|
||||
{t('deposit.viewTx')}
|
||||
</a>
|
||||
)}
|
||||
</div>
|
||||
@@ -300,14 +304,16 @@ export function DepositUSDTModal({ isOpen, onClose }: Props) {
|
||||
onClick={() => setShowHistory(false)}
|
||||
className="w-full py-3 bg-muted rounded-xl text-center"
|
||||
>
|
||||
Vegere
|
||||
{t('deposit.goBack')}
|
||||
</button>
|
||||
</div>
|
||||
) : (
|
||||
<div className="space-y-4">
|
||||
{/* Network Selection */}
|
||||
<div>
|
||||
<label className="text-sm text-muted-foreground mb-2 block">Torê Hilbijêre</label>
|
||||
<label className="text-sm text-muted-foreground mb-2 block">
|
||||
{t('deposit.selectNetwork')}
|
||||
</label>
|
||||
<div className="grid grid-cols-3 gap-2">
|
||||
{NETWORKS.map((net) => (
|
||||
<button
|
||||
@@ -327,7 +333,7 @@ export function DepositUSDTModal({ isOpen, onClose }: Props) {
|
||||
>
|
||||
{net.recommended && (
|
||||
<span className="absolute -top-2 left-1/2 -translate-x-1/2 text-[10px] bg-green-500 text-white px-1.5 py-0.5 rounded">
|
||||
Pêşniyar
|
||||
{t('deposit.recommended')}
|
||||
</span>
|
||||
)}
|
||||
<div className="text-xl mb-1">{net.icon}</div>
|
||||
@@ -349,11 +355,13 @@ export function DepositUSDTModal({ isOpen, onClose }: Props) {
|
||||
<div className="flex gap-3">
|
||||
<AlertTriangle className="w-6 h-6 text-yellow-400 flex-shrink-0" />
|
||||
<div>
|
||||
<p className="text-sm text-yellow-400 font-medium mb-2">Dikkkat!</p>
|
||||
<p className="text-xs text-yellow-400/80 mb-3">{network.feeWarning}</p>
|
||||
<p className="text-xs text-yellow-400/80 mb-3">
|
||||
Mînak: 10 USDT bişîne → 7 wUSDT werbigire ($3 masraf)
|
||||
<p className="text-sm text-yellow-400 font-medium mb-2">
|
||||
{t('deposit.warning')}
|
||||
</p>
|
||||
<p className="text-xs text-yellow-400/80 mb-3">
|
||||
{t('deposit.trc20FeeWarning')}
|
||||
</p>
|
||||
<p className="text-xs text-yellow-400/80 mb-3">{t('deposit.example')}</p>
|
||||
<button
|
||||
onClick={() => {
|
||||
setTrc20Accepted(true);
|
||||
@@ -361,7 +369,7 @@ export function DepositUSDTModal({ isOpen, onClose }: Props) {
|
||||
}}
|
||||
className="w-full py-2 bg-yellow-500/20 border border-yellow-500/50 rounded-lg text-yellow-400 text-sm font-medium"
|
||||
>
|
||||
Qebûl dikim, bi TRC20 bişîne
|
||||
{t('deposit.acceptTrc20')}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
@@ -376,19 +384,13 @@ export function DepositUSDTModal({ isOpen, onClose }: Props) {
|
||||
<div className="flex gap-2">
|
||||
<AlertCircle className="w-5 h-5 text-blue-400 flex-shrink-0" />
|
||||
<div className="text-sm text-blue-400">
|
||||
<p className="font-medium">Girîng!</p>
|
||||
<p className="font-medium">{t('deposit.important')}</p>
|
||||
<ul className="list-disc list-inside text-xs mt-1 space-y-1">
|
||||
<li>
|
||||
Kêmtirîn: <strong>{network.minDeposit} USDT</strong>
|
||||
</li>
|
||||
{selectedNetwork !== 'trc20' && (
|
||||
<li>Memo/Comment qada de koda xwe binivîse</li>
|
||||
)}
|
||||
<li>Tenê USDT bişîne, tokenên din winda dibin</li>
|
||||
<li>{t('deposit.minimum', { amount: network.minDeposit })}</li>
|
||||
{selectedNetwork !== 'trc20' && <li>{t('deposit.memoRequired')}</li>}
|
||||
<li>{t('deposit.onlyUsdt')}</li>
|
||||
{selectedNetwork === 'trc20' && (
|
||||
<li className="text-yellow-400">
|
||||
$3 masraf dê ji mîqdara we bê kêmkirin
|
||||
</li>
|
||||
<li className="text-yellow-400">{t('deposit.trc20Fee')}</li>
|
||||
)}
|
||||
</ul>
|
||||
</div>
|
||||
@@ -399,7 +401,9 @@ export function DepositUSDTModal({ isOpen, onClose }: Props) {
|
||||
<div className="bg-muted/50 rounded-xl p-4 space-y-4">
|
||||
{/* Address */}
|
||||
<div>
|
||||
<label className="text-xs text-muted-foreground">Navnîşana Depoyê</label>
|
||||
<label className="text-xs text-muted-foreground">
|
||||
{t('deposit.depositAddress')}
|
||||
</label>
|
||||
<div className="flex items-center gap-2 mt-1">
|
||||
{isLoading && selectedNetwork === 'trc20' ? (
|
||||
<div className="flex-1 p-2 bg-background rounded-lg flex justify-center">
|
||||
@@ -407,7 +411,7 @@ export function DepositUSDTModal({ isOpen, onClose }: Props) {
|
||||
</div>
|
||||
) : (
|
||||
<code className="flex-1 text-xs font-mono bg-background p-2 rounded-lg break-all">
|
||||
{currentAddress || 'Amade nîne'}
|
||||
{currentAddress || t('deposit.notAvailable')}
|
||||
</code>
|
||||
)}
|
||||
<button
|
||||
@@ -428,7 +432,7 @@ export function DepositUSDTModal({ isOpen, onClose }: Props) {
|
||||
{selectedNetwork !== 'trc20' && (
|
||||
<div>
|
||||
<label className="text-xs text-muted-foreground">
|
||||
Memo / Comment (PÊWÎST)
|
||||
{t('deposit.memoLabel')}
|
||||
</label>
|
||||
<div className="flex items-center gap-2 mt-1">
|
||||
{isLoading ? (
|
||||
@@ -452,31 +456,27 @@ export function DepositUSDTModal({ isOpen, onClose }: Props) {
|
||||
)}
|
||||
</button>
|
||||
</div>
|
||||
<p className="text-xs text-red-400 mt-1">
|
||||
⚠️ Vê kodê di memo de binivîse, wekî din depoya te nayê nas kirin!
|
||||
</p>
|
||||
<p className="text-xs text-red-400 mt-1">{t('deposit.memoWarning')}</p>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{selectedNetwork === 'trc20' && (
|
||||
<p className="text-xs text-green-400">
|
||||
✅ Ev navnîşan tenê ya te ye. Memo ne pêwîst e.
|
||||
</p>
|
||||
<p className="text-xs text-green-400">{t('deposit.uniqueAddress')}</p>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* Steps */}
|
||||
<div className="bg-muted/30 rounded-xl p-4">
|
||||
<h4 className="text-sm font-medium mb-3">Çawa Depo Bikim?</h4>
|
||||
<h4 className="text-sm font-medium mb-3">{t('deposit.howToDeposit')}</h4>
|
||||
<ol className="text-xs text-muted-foreground space-y-2">
|
||||
<li className="flex gap-2">
|
||||
<span className="text-green-400 font-bold">1.</span>
|
||||
<span>Navnîşan kopî bike</span>
|
||||
<span>{t('deposit.stepCopyAddress')}</span>
|
||||
</li>
|
||||
{selectedNetwork !== 'trc20' && (
|
||||
<li className="flex gap-2">
|
||||
<span className="text-green-400 font-bold">2.</span>
|
||||
<span>Memo kodê kopî bike</span>
|
||||
<span>{t('deposit.stepCopyMemo')}</span>
|
||||
</li>
|
||||
)}
|
||||
<li className="flex gap-2">
|
||||
@@ -485,30 +485,30 @@ export function DepositUSDTModal({ isOpen, onClose }: Props) {
|
||||
</span>
|
||||
<span>
|
||||
{selectedNetwork === 'ton'
|
||||
? 'Telegram Wallet an cîzdana xwe veke'
|
||||
? t('deposit.stepOpenTon')
|
||||
: selectedNetwork === 'polkadot'
|
||||
? 'Polkadot cîzdana xwe veke'
|
||||
: 'TronLink an cîzdana xwe veke'}
|
||||
? t('deposit.stepOpenPolkadot')
|
||||
: t('deposit.stepOpenTrc20')}
|
||||
</span>
|
||||
</li>
|
||||
<li className="flex gap-2">
|
||||
<span className="text-green-400 font-bold">
|
||||
{selectedNetwork === 'trc20' ? '3' : '4'}.
|
||||
</span>
|
||||
<span>USDT bişîne navnîşana jorîn</span>
|
||||
<span>{t('deposit.stepSendUsdt')}</span>
|
||||
</li>
|
||||
<li className="flex gap-2">
|
||||
<span className="text-green-400 font-bold">
|
||||
{selectedNetwork === 'trc20' ? '4' : '5'}.
|
||||
</span>
|
||||
<span>wUSDT dê di nav çend hûrdeman de li hesabê te be</span>
|
||||
<span>{t('deposit.stepReceive')}</span>
|
||||
</li>
|
||||
</ol>
|
||||
</div>
|
||||
|
||||
{/* Processing Time */}
|
||||
<p className="text-center text-xs text-muted-foreground">
|
||||
Dema pêvajoyê: ~1-5 hûrdem
|
||||
{t('deposit.processingTime')}
|
||||
</p>
|
||||
</>
|
||||
)}
|
||||
|
||||
@@ -8,6 +8,7 @@ import { Eye, EyeOff, Wallet, Unlock, Trash2 } from 'lucide-react';
|
||||
import { useWallet } from '@/contexts/WalletContext';
|
||||
import { useTelegram } from '@/hooks/useTelegram';
|
||||
import { formatAddress } from '@/lib/wallet-service';
|
||||
import { useTranslation } from '@/i18n';
|
||||
|
||||
interface Props {
|
||||
onConnected: () => void;
|
||||
@@ -17,6 +18,7 @@ interface Props {
|
||||
export function WalletConnect({ onConnected, onDelete }: Props) {
|
||||
const { address, connect, error: walletError } = useWallet();
|
||||
const { hapticImpact, hapticNotification } = useTelegram();
|
||||
const { t } = useTranslation();
|
||||
|
||||
const [password, setPassword] = useState('');
|
||||
const [showPassword, setShowPassword] = useState(false);
|
||||
@@ -26,7 +28,7 @@ export function WalletConnect({ onConnected, onDelete }: Props) {
|
||||
|
||||
const handleConnect = async () => {
|
||||
if (!password) {
|
||||
setError('Şîfre (password) binivîse');
|
||||
setError(t('walletConnect.enterPassword'));
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -39,7 +41,7 @@ export function WalletConnect({ onConnected, onDelete }: Props) {
|
||||
hapticNotification('success');
|
||||
onConnected();
|
||||
} catch (err) {
|
||||
setError(err instanceof Error ? err.message : 'Şîfre (password) çewt e');
|
||||
setError(err instanceof Error ? err.message : t('walletConnect.wrongPassword'));
|
||||
hapticNotification('error');
|
||||
} finally {
|
||||
setIsLoading(false);
|
||||
@@ -58,11 +60,8 @@ export function WalletConnect({ onConnected, onDelete }: Props) {
|
||||
<div className="w-16 h-16 mx-auto bg-red-500/20 rounded-full flex items-center justify-center mb-4">
|
||||
<Trash2 className="w-8 h-8 text-red-500" />
|
||||
</div>
|
||||
<h2 className="text-xl font-semibold mb-2">Wallet Jê Bibe?</h2>
|
||||
<p className="text-muted-foreground text-sm">
|
||||
Ev çalakî nayê paşvekişandin. Eger seed phrase'ê te tune be, tu nikarî gihîştina
|
||||
wallet'ê xwe bistînî.
|
||||
</p>
|
||||
<h2 className="text-xl font-semibold mb-2">{t('walletConnect.deleteTitle')}</h2>
|
||||
<p className="text-muted-foreground text-sm">{t('walletConnect.deleteDescription')}</p>
|
||||
</div>
|
||||
|
||||
<div className="flex gap-3">
|
||||
@@ -70,13 +69,13 @@ export function WalletConnect({ onConnected, onDelete }: Props) {
|
||||
onClick={() => setShowDeleteConfirm(false)}
|
||||
className="flex-1 py-3 bg-muted rounded-xl font-semibold"
|
||||
>
|
||||
Betal
|
||||
{t('common.cancel')}
|
||||
</button>
|
||||
<button
|
||||
onClick={handleDelete}
|
||||
className="flex-1 py-3 bg-red-500 text-white rounded-xl font-semibold"
|
||||
>
|
||||
Jê Bibe
|
||||
{t('walletConnect.deleteButton')}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
@@ -89,7 +88,7 @@ export function WalletConnect({ onConnected, onDelete }: Props) {
|
||||
<div className="w-16 h-16 mx-auto bg-primary/20 rounded-full flex items-center justify-center mb-4">
|
||||
<Wallet className="w-8 h-8 text-primary" />
|
||||
</div>
|
||||
<h2 className="text-xl font-semibold mb-2">Wallet Veke</h2>
|
||||
<h2 className="text-xl font-semibold mb-2">{t('walletConnect.openWallet')}</h2>
|
||||
{address && (
|
||||
<p className="text-muted-foreground text-sm font-mono">{formatAddress(address)}</p>
|
||||
)}
|
||||
@@ -97,7 +96,9 @@ export function WalletConnect({ onConnected, onDelete }: Props) {
|
||||
|
||||
<div className="space-y-4">
|
||||
<div className="space-y-2">
|
||||
<label className="text-sm text-muted-foreground">Şîfre (Password)</label>
|
||||
<label className="text-sm text-muted-foreground">
|
||||
{t('walletConnect.passwordLabel')}
|
||||
</label>
|
||||
<div className="relative">
|
||||
<input
|
||||
type={showPassword ? 'text' : 'password'}
|
||||
@@ -105,7 +106,7 @@ export function WalletConnect({ onConnected, onDelete }: Props) {
|
||||
onChange={(e) => setPassword(e.target.value)}
|
||||
onKeyDown={(e) => e.key === 'Enter' && handleConnect()}
|
||||
className="w-full px-4 py-3 bg-muted rounded-xl pr-12"
|
||||
placeholder="Şîfre (password) binivîse"
|
||||
placeholder={t('walletConnect.passwordPlaceholder')}
|
||||
autoFocus
|
||||
/>
|
||||
<button
|
||||
@@ -130,11 +131,11 @@ export function WalletConnect({ onConnected, onDelete }: Props) {
|
||||
className="w-full py-3 bg-primary text-primary-foreground rounded-xl font-semibold disabled:opacity-50 flex items-center justify-center gap-2"
|
||||
>
|
||||
{isLoading ? (
|
||||
'Tê vekirin...'
|
||||
t('walletConnect.connecting')
|
||||
) : (
|
||||
<>
|
||||
<Unlock className="w-4 h-4" />
|
||||
Connect
|
||||
{t('walletConnect.connect')}
|
||||
</>
|
||||
)}
|
||||
</button>
|
||||
@@ -143,7 +144,7 @@ export function WalletConnect({ onConnected, onDelete }: Props) {
|
||||
onClick={() => setShowDeleteConfirm(true)}
|
||||
className="w-full py-3 text-red-400 text-sm"
|
||||
>
|
||||
Wallet jê bibe
|
||||
{t('walletConnect.deleteWalletLink')}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -17,6 +17,7 @@ import {
|
||||
} from 'lucide-react';
|
||||
import { useWallet } from '@/contexts/WalletContext';
|
||||
import { useTelegram } from '@/hooks/useTelegram';
|
||||
import { useTranslation } from '@/i18n';
|
||||
|
||||
type Step = 'password' | 'backup' | 'verify' | 'complete';
|
||||
|
||||
@@ -34,6 +35,7 @@ interface Props {
|
||||
export function WalletCreate({ onComplete, onBack }: Props) {
|
||||
const { generateNewWallet, confirmWallet, isInitialized } = useWallet();
|
||||
const { hapticImpact, hapticNotification } = useTelegram();
|
||||
const { t } = useTranslation();
|
||||
|
||||
const [step, setStep] = useState<Step>('password');
|
||||
const [password, setPassword] = useState('');
|
||||
@@ -84,12 +86,12 @@ export function WalletCreate({ onComplete, onBack }: Props) {
|
||||
setError('');
|
||||
|
||||
if (!isInitialized) {
|
||||
setError('Wallet service amade nîne. Ji kerema xwe bisekinin.');
|
||||
setError(t('walletCreate.walletServiceNotReady'));
|
||||
return;
|
||||
}
|
||||
|
||||
if (!allPasswordRulesPass) {
|
||||
setError('Ji kerema xwe hemû şertên şîfre (password) bicîh bînin');
|
||||
setError(t('walletCreate.passwordRequirementsNotMet'));
|
||||
hapticNotification('error');
|
||||
return;
|
||||
}
|
||||
@@ -104,9 +106,7 @@ export function WalletCreate({ onComplete, onBack }: Props) {
|
||||
setStep('backup');
|
||||
} catch (err) {
|
||||
console.error('Wallet generation error:', err);
|
||||
setError(
|
||||
err instanceof Error ? err.message : 'Wallet çênebû. Ji kerema xwe dîsa biceribînin'
|
||||
);
|
||||
setError(err instanceof Error ? err.message : t('walletCreate.walletCreationFailed'));
|
||||
hapticNotification('error');
|
||||
}
|
||||
};
|
||||
@@ -122,7 +122,7 @@ export function WalletCreate({ onComplete, onBack }: Props) {
|
||||
// Step 2: Backup - Proceed to verify (only if all conditions checked)
|
||||
const handleBackupContinue = () => {
|
||||
if (!allConditionsChecked) {
|
||||
setError('Ji kerema xwe hemû şertan bipejirînin');
|
||||
setError(t('walletCreate.acceptAllConditions'));
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -183,7 +183,7 @@ export function WalletCreate({ onComplete, onBack }: Props) {
|
||||
originalWords.every((word, idx) => word === enteredWords[idx]);
|
||||
|
||||
if (!isCorrect) {
|
||||
setError('Rêza peyvan ne rast e. Ji kerema xwe dîsa biceribînin');
|
||||
setError(t('walletCreate.wrongOrder'));
|
||||
hapticNotification('error');
|
||||
return;
|
||||
}
|
||||
@@ -197,7 +197,7 @@ export function WalletCreate({ onComplete, onBack }: Props) {
|
||||
hapticNotification('success');
|
||||
setStep('complete');
|
||||
} catch (err) {
|
||||
setError(err instanceof Error ? err.message : 'Wallet çênebû');
|
||||
setError(err instanceof Error ? err.message : t('walletCreate.walletCreationFailed'));
|
||||
hapticNotification('error');
|
||||
} finally {
|
||||
setIsLoading(false);
|
||||
@@ -213,26 +213,26 @@ export function WalletCreate({ onComplete, onBack }: Props) {
|
||||
<div className="p-4 space-y-6">
|
||||
<button onClick={onBack} className="flex items-center gap-2 text-muted-foreground">
|
||||
<ArrowLeft className="w-4 h-4" />
|
||||
<span>Paş</span>
|
||||
<span>{t('common.back')}</span>
|
||||
</button>
|
||||
|
||||
<div className="text-center">
|
||||
<h2 className="text-xl font-semibold mb-2">Şîfre (Password) Diyar Bike</h2>
|
||||
<p className="text-muted-foreground text-sm">
|
||||
Ev şîfre (password) dê ji bo vekirina wallet'ê were bikaranîn
|
||||
</p>
|
||||
<h2 className="text-xl font-semibold mb-2">{t('walletCreate.setPassword')}</h2>
|
||||
<p className="text-muted-foreground text-sm">{t('walletCreate.passwordDescription')}</p>
|
||||
</div>
|
||||
|
||||
<div className="space-y-4">
|
||||
<div className="space-y-2">
|
||||
<label className="text-sm text-muted-foreground">Şîfre (Password)</label>
|
||||
<label className="text-sm text-muted-foreground">
|
||||
{t('walletCreate.passwordLabel')}
|
||||
</label>
|
||||
<div className="relative">
|
||||
<input
|
||||
type={showPassword ? 'text' : 'password'}
|
||||
value={password}
|
||||
onChange={(e) => setPassword(e.target.value)}
|
||||
className="w-full px-4 py-3 bg-muted rounded-xl pr-12"
|
||||
placeholder="Herî kêm 12 tîp (min 12 characters)"
|
||||
placeholder={t('walletCreate.passwordPlaceholder')}
|
||||
/>
|
||||
<button
|
||||
type="button"
|
||||
@@ -245,20 +245,24 @@ export function WalletCreate({ onComplete, onBack }: Props) {
|
||||
</div>
|
||||
|
||||
<div className="space-y-2">
|
||||
<label className="text-sm text-muted-foreground">Şîfre Dubare (Confirm Password)</label>
|
||||
<label className="text-sm text-muted-foreground">
|
||||
{t('walletCreate.confirmPasswordLabel')}
|
||||
</label>
|
||||
<input
|
||||
type={showPassword ? 'text' : 'password'}
|
||||
value={confirmPassword}
|
||||
onChange={(e) => setConfirmPassword(e.target.value)}
|
||||
className="w-full px-4 py-3 bg-muted rounded-xl"
|
||||
placeholder="Şîfre dubare binivîse (confirm password)"
|
||||
placeholder={t('walletCreate.confirmPasswordPlaceholder')}
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* Real-time password strength indicator */}
|
||||
{password.length > 0 && (
|
||||
<div className="p-3 bg-muted/50 rounded-xl space-y-2">
|
||||
<p className="text-xs text-muted-foreground font-medium">Şertên Şîfre (Password):</p>
|
||||
<p className="text-xs text-muted-foreground font-medium">
|
||||
{t('walletCreate.passwordRequirements')}
|
||||
</p>
|
||||
<div className="grid grid-cols-1 gap-1.5 text-xs">
|
||||
<div
|
||||
className={`flex items-center gap-2 ${passwordRules.minLength ? 'text-green-400' : 'text-red-400'}`}
|
||||
@@ -268,7 +272,7 @@ export function WalletCreate({ onComplete, onBack }: Props) {
|
||||
) : (
|
||||
<AlertTriangle className="w-3 h-3" />
|
||||
)}
|
||||
<span>Herî kêm 12 tîp (min 12 characters)</span>
|
||||
<span>{t('walletCreate.ruleMinLength')}</span>
|
||||
</div>
|
||||
<div
|
||||
className={`flex items-center gap-2 ${passwordRules.hasLowercase ? 'text-green-400' : 'text-red-400'}`}
|
||||
@@ -278,7 +282,7 @@ export function WalletCreate({ onComplete, onBack }: Props) {
|
||||
) : (
|
||||
<AlertTriangle className="w-3 h-3" />
|
||||
)}
|
||||
<span>Herî kêm 1 tîpa biçûk (a-z)</span>
|
||||
<span>{t('walletCreate.ruleLowercase')}</span>
|
||||
</div>
|
||||
<div
|
||||
className={`flex items-center gap-2 ${passwordRules.hasUppercase ? 'text-green-400' : 'text-red-400'}`}
|
||||
@@ -288,7 +292,7 @@ export function WalletCreate({ onComplete, onBack }: Props) {
|
||||
) : (
|
||||
<AlertTriangle className="w-3 h-3" />
|
||||
)}
|
||||
<span>Herî kêm 1 tîpa mezin (A-Z)</span>
|
||||
<span>{t('walletCreate.ruleUppercase')}</span>
|
||||
</div>
|
||||
<div
|
||||
className={`flex items-center gap-2 ${passwordRules.hasNumber ? 'text-green-400' : 'text-red-400'}`}
|
||||
@@ -298,7 +302,7 @@ export function WalletCreate({ onComplete, onBack }: Props) {
|
||||
) : (
|
||||
<AlertTriangle className="w-3 h-3" />
|
||||
)}
|
||||
<span>Herî kêm 1 hejmar (0-9)</span>
|
||||
<span>{t('walletCreate.ruleNumber')}</span>
|
||||
</div>
|
||||
<div
|
||||
className={`flex items-center gap-2 ${passwordRules.hasSpecialChar ? 'text-green-400' : 'text-red-400'}`}
|
||||
@@ -308,7 +312,7 @@ export function WalletCreate({ onComplete, onBack }: Props) {
|
||||
) : (
|
||||
<AlertTriangle className="w-3 h-3" />
|
||||
)}
|
||||
<span>Herî kêm 1 sembola taybetî (!@#$%...)</span>
|
||||
<span>{t('walletCreate.ruleSpecialChar')}</span>
|
||||
</div>
|
||||
{confirmPassword.length > 0 && (
|
||||
<div
|
||||
@@ -319,7 +323,7 @@ export function WalletCreate({ onComplete, onBack }: Props) {
|
||||
) : (
|
||||
<AlertTriangle className="w-3 h-3" />
|
||||
)}
|
||||
<span>Şîfre (password) hev digirin</span>
|
||||
<span>{t('walletCreate.rulePasswordsMatch')}</span>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
@@ -338,12 +342,12 @@ export function WalletCreate({ onComplete, onBack }: Props) {
|
||||
className="w-full py-3 bg-primary text-primary-foreground rounded-xl font-semibold disabled:opacity-50 flex items-center justify-center gap-2"
|
||||
>
|
||||
{!isInitialized
|
||||
? 'Tê amadekirin...'
|
||||
? t('walletCreate.preparing')
|
||||
: isLoading
|
||||
? 'Tê çêkirin...'
|
||||
? t('walletCreate.creating')
|
||||
: allPasswordRulesPass
|
||||
? 'Berdewam'
|
||||
: 'Şertên şîfre (password) bicîh bînin'}
|
||||
? t('common.continue')
|
||||
: t('walletCreate.meetPasswordRequirements')}
|
||||
{!isLoading && allPasswordRulesPass && isInitialized && (
|
||||
<ArrowRight className="w-4 h-4" />
|
||||
)}
|
||||
@@ -359,18 +363,13 @@ export function WalletCreate({ onComplete, onBack }: Props) {
|
||||
return (
|
||||
<div className="p-4 space-y-6">
|
||||
<div className="text-center">
|
||||
<h2 className="text-xl font-semibold mb-2">Seed Phrase Paşguh Bike</h2>
|
||||
<p className="text-muted-foreground text-sm">
|
||||
Ev 12 peyv wallet'ê te ne. Wan li cihekî ewle binivîse!
|
||||
</p>
|
||||
<h2 className="text-xl font-semibold mb-2">{t('walletCreate.backupTitle')}</h2>
|
||||
<p className="text-muted-foreground text-sm">{t('walletCreate.backupDescription')}</p>
|
||||
</div>
|
||||
|
||||
<div className="p-4 bg-yellow-500/10 border border-yellow-500/30 rounded-xl flex items-start gap-3">
|
||||
<AlertTriangle className="w-5 h-5 text-yellow-500 shrink-0 mt-0.5" />
|
||||
<p className="text-sm text-yellow-200">
|
||||
<strong>Girîng:</strong> Ev peyvan tenê yek car têne xuyang kirin. Eger te ev peyv winda
|
||||
bikin, tu nikarî gihîştina wallet'ê xwe bistînî.
|
||||
</p>
|
||||
<p className="text-sm text-yellow-200">{t('walletCreate.backupWarning')}</p>
|
||||
</div>
|
||||
|
||||
<div className="grid grid-cols-3 gap-2">
|
||||
@@ -389,12 +388,12 @@ export function WalletCreate({ onComplete, onBack }: Props) {
|
||||
{copied ? (
|
||||
<>
|
||||
<Check className="w-4 h-4 text-green-400" />
|
||||
<span className="text-green-400">Hat kopîkirin!</span>
|
||||
<span className="text-green-400">{t('walletCreate.copiedMnemonic')}</span>
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<Copy className="w-4 h-4" />
|
||||
<span>Kopî Bike</span>
|
||||
<span>{t('walletCreate.copyMnemonic')}</span>
|
||||
</>
|
||||
)}
|
||||
</button>
|
||||
@@ -410,7 +409,7 @@ export function WalletCreate({ onComplete, onBack }: Props) {
|
||||
}
|
||||
className="mt-1 w-5 h-5 accent-primary"
|
||||
/>
|
||||
<span className="text-sm">Min ev 12 peyv li cihekî ewle nivîsandine</span>
|
||||
<span className="text-sm">{t('walletCreate.conditionWrittenDown')}</span>
|
||||
</label>
|
||||
|
||||
<label className="flex items-start gap-3 p-3 bg-muted rounded-xl cursor-pointer">
|
||||
@@ -420,9 +419,7 @@ export function WalletCreate({ onComplete, onBack }: Props) {
|
||||
onChange={(e) => setConditions((prev) => ({ ...prev, neverShare: e.target.checked }))}
|
||||
className="mt-1 w-5 h-5 accent-primary"
|
||||
/>
|
||||
<span className="text-sm">
|
||||
Ez fêm dikim ku ez nikarim ev peyvan bi kesî re parve bikim
|
||||
</span>
|
||||
<span className="text-sm">{t('walletCreate.conditionNeverShare')}</span>
|
||||
</label>
|
||||
|
||||
<label className="flex items-start gap-3 p-3 bg-muted rounded-xl cursor-pointer">
|
||||
@@ -432,10 +429,7 @@ export function WalletCreate({ onComplete, onBack }: Props) {
|
||||
onChange={(e) => setConditions((prev) => ({ ...prev, lossRisk: e.target.checked }))}
|
||||
className="mt-1 w-5 h-5 accent-primary"
|
||||
/>
|
||||
<span className="text-sm">
|
||||
Ez fêm dikim ku eger van peyvan winda bikim ez nikarim gihîştina wallet'ê xwe
|
||||
bistînim
|
||||
</span>
|
||||
<span className="text-sm">{t('walletCreate.conditionLossRisk')}</span>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
@@ -450,7 +444,7 @@ export function WalletCreate({ onComplete, onBack }: Props) {
|
||||
disabled={!allConditionsChecked}
|
||||
className="w-full py-3 bg-primary text-primary-foreground rounded-xl font-semibold disabled:opacity-50 flex items-center justify-center gap-2"
|
||||
>
|
||||
{allConditionsChecked ? 'Berdewam' : 'Hemû şertan bipejirînin'}
|
||||
{allConditionsChecked ? t('common.continue') : t('walletCreate.acceptAllConditions')}
|
||||
{allConditionsChecked && <ArrowRight className="w-4 h-4" />}
|
||||
</button>
|
||||
</div>
|
||||
@@ -461,24 +455,26 @@ export function WalletCreate({ onComplete, onBack }: Props) {
|
||||
return (
|
||||
<div className="p-4 space-y-6">
|
||||
<div className="flex items-center justify-between">
|
||||
<h2 className="text-lg font-semibold">Peyvan Verast Bike</h2>
|
||||
<h2 className="text-lg font-semibold">{t('walletCreate.verifyWords')}</h2>
|
||||
<button
|
||||
onClick={handleReset}
|
||||
className="flex items-center gap-1 text-sm text-muted-foreground"
|
||||
>
|
||||
<RotateCcw className="w-4 h-4" />
|
||||
<span>Reset</span>
|
||||
<span>{t('walletCreate.reset')}</span>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<p className="text-muted-foreground text-sm text-center">
|
||||
Ji kerema xwe peyvan bi rêza rast bixin nav qutîkê
|
||||
{t('walletCreate.verifyDescription')}
|
||||
</p>
|
||||
|
||||
{/* Destination area - where user builds the correct order */}
|
||||
<div className="min-h-[120px] p-4 bg-muted/50 border-2 border-dashed border-border rounded-xl">
|
||||
{destinationWords.length === 0 ? (
|
||||
<p className="text-center text-muted-foreground text-sm">Peyvan li vir bixin...</p>
|
||||
<p className="text-center text-muted-foreground text-sm">
|
||||
{t('walletCreate.dropWordsHere')}
|
||||
</p>
|
||||
) : (
|
||||
<div className="flex flex-wrap gap-2">
|
||||
{destinationWords.map((word, idx) => (
|
||||
@@ -525,10 +521,10 @@ export function WalletCreate({ onComplete, onBack }: Props) {
|
||||
className="w-full py-3 bg-primary text-primary-foreground rounded-xl font-semibold disabled:opacity-50"
|
||||
>
|
||||
{isLoading
|
||||
? 'Tê tomarkirin...'
|
||||
? t('walletCreate.saving')
|
||||
: canVerify
|
||||
? 'Verast Bike'
|
||||
: `${destinationWords.length}/12 peyv`}
|
||||
? t('walletCreate.verify')
|
||||
: t('walletCreate.wordsCount', { count: destinationWords.length })}
|
||||
</button>
|
||||
</div>
|
||||
);
|
||||
@@ -542,12 +538,12 @@ export function WalletCreate({ onComplete, onBack }: Props) {
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<h2 className="text-xl font-semibold mb-2">Wallet Hat Çêkirin!</h2>
|
||||
<p className="text-muted-foreground text-sm">Wallet'ê te amade ye</p>
|
||||
<h2 className="text-xl font-semibold mb-2">{t('walletCreate.walletCreated')}</h2>
|
||||
<p className="text-muted-foreground text-sm">{t('walletCreate.walletReady')}</p>
|
||||
</div>
|
||||
|
||||
<div className="p-4 bg-muted rounded-xl">
|
||||
<p className="text-xs text-muted-foreground mb-1">Navnîşana te</p>
|
||||
<p className="text-xs text-muted-foreground mb-1">{t('walletCreate.yourAddress')}</p>
|
||||
<p className="font-mono text-sm break-all">{address}</p>
|
||||
</div>
|
||||
|
||||
@@ -555,7 +551,7 @@ export function WalletCreate({ onComplete, onBack }: Props) {
|
||||
onClick={onComplete}
|
||||
className="w-full py-3 bg-primary text-primary-foreground rounded-xl font-semibold"
|
||||
>
|
||||
Dest Pê Bike
|
||||
{t('walletCreate.getStarted')}
|
||||
</button>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -8,6 +8,7 @@ import { Eye, EyeOff, ArrowLeft, ArrowRight, Check, AlertTriangle } from 'lucide
|
||||
import { useWallet } from '@/contexts/WalletContext';
|
||||
import { useTelegram } from '@/hooks/useTelegram';
|
||||
import { validatePassword } from '@/lib/crypto';
|
||||
import { useTranslation } from '@/i18n';
|
||||
|
||||
interface Props {
|
||||
onComplete: () => void;
|
||||
@@ -17,6 +18,7 @@ interface Props {
|
||||
export function WalletImport({ onComplete, onBack }: Props) {
|
||||
const { importWallet } = useWallet();
|
||||
const { hapticImpact, hapticNotification } = useTelegram();
|
||||
const { t } = useTranslation();
|
||||
|
||||
const [mnemonic, setMnemonic] = useState('');
|
||||
const [password, setPassword] = useState('');
|
||||
@@ -49,18 +51,18 @@ export function WalletImport({ onComplete, onBack }: Props) {
|
||||
// Validate mnemonic
|
||||
const words = mnemonic.trim().split(/\s+/);
|
||||
if (words.length !== 12 && words.length !== 24) {
|
||||
setError('Seed phrase divê 12 an 24 peyv be');
|
||||
setError(t('walletImport.seedPhraseInvalid'));
|
||||
return;
|
||||
}
|
||||
|
||||
// Validate password using crypto.ts rules
|
||||
const passwordValidation = validatePassword(password);
|
||||
if (!passwordValidation.valid) {
|
||||
setError(passwordValidation.message || 'Şîfre (password) ne derbasdar e');
|
||||
setError(passwordValidation.message || t('walletImport.passwordInvalid'));
|
||||
return;
|
||||
}
|
||||
if (password !== confirmPassword) {
|
||||
setError('Şîfre (password) hev nagirin');
|
||||
setError(t('walletImport.passwordsMismatch'));
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -72,7 +74,7 @@ export function WalletImport({ onComplete, onBack }: Props) {
|
||||
hapticNotification('success');
|
||||
onComplete();
|
||||
} catch (err) {
|
||||
setError(err instanceof Error ? err.message : 'Import neserketî');
|
||||
setError(err instanceof Error ? err.message : t('walletImport.importFailed'));
|
||||
hapticNotification('error');
|
||||
} finally {
|
||||
setIsLoading(false);
|
||||
@@ -83,24 +85,24 @@ export function WalletImport({ onComplete, onBack }: Props) {
|
||||
<div className="p-4 space-y-6">
|
||||
<button onClick={onBack} className="flex items-center gap-2 text-muted-foreground">
|
||||
<ArrowLeft className="w-4 h-4" />
|
||||
<span>Paş</span>
|
||||
<span>{t('common.back')}</span>
|
||||
</button>
|
||||
|
||||
<div className="text-center">
|
||||
<h2 className="text-xl font-semibold mb-2">Wallet Import Bike</h2>
|
||||
<p className="text-muted-foreground text-sm">
|
||||
Seed phrase'ê wallet'ê xwe yê heyî binivîse
|
||||
</p>
|
||||
<h2 className="text-xl font-semibold mb-2">{t('walletImport.title')}</h2>
|
||||
<p className="text-muted-foreground text-sm">{t('walletImport.description')}</p>
|
||||
</div>
|
||||
|
||||
<div className="space-y-4">
|
||||
<div className="space-y-2">
|
||||
<label className="text-sm text-muted-foreground">Seed Phrase (12 an 24 peyv)</label>
|
||||
<label className="text-sm text-muted-foreground">
|
||||
{t('walletImport.seedPhraseLabel')}
|
||||
</label>
|
||||
<textarea
|
||||
value={mnemonic}
|
||||
onChange={(e) => setMnemonic(e.target.value)}
|
||||
className="w-full px-4 py-3 bg-muted rounded-xl resize-none h-28 font-mono text-sm"
|
||||
placeholder="Peyvên xwe bi valahî cuda binivîse..."
|
||||
placeholder={t('walletImport.seedPhrasePlaceholder')}
|
||||
/>
|
||||
<p className="text-xs text-muted-foreground">
|
||||
{mnemonic.trim().split(/\s+/).filter(Boolean).length} / 12 peyv
|
||||
@@ -108,14 +110,14 @@ export function WalletImport({ onComplete, onBack }: Props) {
|
||||
</div>
|
||||
|
||||
<div className="space-y-2">
|
||||
<label className="text-sm text-muted-foreground">Şîfreya Nû (New Password)</label>
|
||||
<label className="text-sm text-muted-foreground">{t('walletImport.newPassword')}</label>
|
||||
<div className="relative">
|
||||
<input
|
||||
type={showPassword ? 'text' : 'password'}
|
||||
value={password}
|
||||
onChange={(e) => setPassword(e.target.value)}
|
||||
className="w-full px-4 py-3 bg-muted rounded-xl pr-12"
|
||||
placeholder="Herî kêm 12 tîp (min 12 characters)"
|
||||
placeholder={t('walletCreate.passwordPlaceholder')}
|
||||
/>
|
||||
<button
|
||||
type="button"
|
||||
@@ -128,20 +130,24 @@ export function WalletImport({ onComplete, onBack }: Props) {
|
||||
</div>
|
||||
|
||||
<div className="space-y-2">
|
||||
<label className="text-sm text-muted-foreground">Şîfre Dubare (Confirm Password)</label>
|
||||
<label className="text-sm text-muted-foreground">
|
||||
{t('walletCreate.confirmPasswordLabel')}
|
||||
</label>
|
||||
<input
|
||||
type={showPassword ? 'text' : 'password'}
|
||||
value={confirmPassword}
|
||||
onChange={(e) => setConfirmPassword(e.target.value)}
|
||||
className="w-full px-4 py-3 bg-muted rounded-xl"
|
||||
placeholder="Şîfre dubare binivîse (confirm password)"
|
||||
placeholder={t('walletCreate.confirmPasswordPlaceholder')}
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* Real-time password strength indicator */}
|
||||
{password.length > 0 && (
|
||||
<div className="p-3 bg-muted/50 rounded-xl space-y-2">
|
||||
<p className="text-xs text-muted-foreground font-medium">Şertên Şîfre (Password):</p>
|
||||
<p className="text-xs text-muted-foreground font-medium">
|
||||
{t('walletCreate.passwordRequirements')}
|
||||
</p>
|
||||
<div className="grid grid-cols-1 gap-1.5 text-xs">
|
||||
<div
|
||||
className={`flex items-center gap-2 ${passwordRules.minLength ? 'text-green-400' : 'text-red-400'}`}
|
||||
@@ -151,7 +157,7 @@ export function WalletImport({ onComplete, onBack }: Props) {
|
||||
) : (
|
||||
<AlertTriangle className="w-3 h-3" />
|
||||
)}
|
||||
<span>Herî kêm 12 tîp (min 12 characters)</span>
|
||||
<span>{t('walletCreate.ruleMinLength')}</span>
|
||||
</div>
|
||||
<div
|
||||
className={`flex items-center gap-2 ${passwordRules.hasLowercase ? 'text-green-400' : 'text-red-400'}`}
|
||||
@@ -161,7 +167,7 @@ export function WalletImport({ onComplete, onBack }: Props) {
|
||||
) : (
|
||||
<AlertTriangle className="w-3 h-3" />
|
||||
)}
|
||||
<span>Herî kêm 1 tîpa biçûk (a-z)</span>
|
||||
<span>{t('walletCreate.ruleLowercase')}</span>
|
||||
</div>
|
||||
<div
|
||||
className={`flex items-center gap-2 ${passwordRules.hasUppercase ? 'text-green-400' : 'text-red-400'}`}
|
||||
@@ -171,7 +177,7 @@ export function WalletImport({ onComplete, onBack }: Props) {
|
||||
) : (
|
||||
<AlertTriangle className="w-3 h-3" />
|
||||
)}
|
||||
<span>Herî kêm 1 tîpa mezin (A-Z)</span>
|
||||
<span>{t('walletCreate.ruleUppercase')}</span>
|
||||
</div>
|
||||
<div
|
||||
className={`flex items-center gap-2 ${passwordRules.hasNumber ? 'text-green-400' : 'text-red-400'}`}
|
||||
@@ -181,7 +187,7 @@ export function WalletImport({ onComplete, onBack }: Props) {
|
||||
) : (
|
||||
<AlertTriangle className="w-3 h-3" />
|
||||
)}
|
||||
<span>Herî kêm 1 hejmar (0-9)</span>
|
||||
<span>{t('walletCreate.ruleNumber')}</span>
|
||||
</div>
|
||||
<div
|
||||
className={`flex items-center gap-2 ${passwordRules.hasSpecialChar ? 'text-green-400' : 'text-red-400'}`}
|
||||
@@ -191,7 +197,7 @@ export function WalletImport({ onComplete, onBack }: Props) {
|
||||
) : (
|
||||
<AlertTriangle className="w-3 h-3" />
|
||||
)}
|
||||
<span>Herî kêm 1 sembola taybetî (!@#$%...)</span>
|
||||
<span>{t('walletCreate.ruleSpecialChar')}</span>
|
||||
</div>
|
||||
{confirmPassword.length > 0 && (
|
||||
<div
|
||||
@@ -202,7 +208,7 @@ export function WalletImport({ onComplete, onBack }: Props) {
|
||||
) : (
|
||||
<AlertTriangle className="w-3 h-3" />
|
||||
)}
|
||||
<span>Şîfre (password) hev digirin</span>
|
||||
<span>{t('walletCreate.rulePasswordsMatch')}</span>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
@@ -221,10 +227,10 @@ export function WalletImport({ onComplete, onBack }: Props) {
|
||||
className="w-full py-3 bg-primary text-primary-foreground rounded-xl font-semibold disabled:opacity-50 flex items-center justify-center gap-2"
|
||||
>
|
||||
{isLoading
|
||||
? 'Tê import kirin...'
|
||||
? t('walletImport.importing')
|
||||
: allPasswordRulesPass
|
||||
? 'Import Bike'
|
||||
: 'Şertên şîfre (password) bicîh bînin'}
|
||||
? t('walletImport.importButton')
|
||||
: t('walletCreate.meetPasswordRequirements')}
|
||||
{!isLoading && allPasswordRulesPass && <ArrowRight className="w-4 h-4" />}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
*/
|
||||
|
||||
import { Wallet, Plus, Download } from 'lucide-react';
|
||||
import { useTranslation } from '@/i18n';
|
||||
|
||||
interface Props {
|
||||
onCreate: () => void;
|
||||
@@ -11,6 +12,8 @@ interface Props {
|
||||
}
|
||||
|
||||
export function WalletSetup({ onCreate, onImport }: Props) {
|
||||
const { t } = useTranslation();
|
||||
|
||||
return (
|
||||
<div className="p-4 space-y-8">
|
||||
<div className="text-center pt-8">
|
||||
@@ -18,7 +21,7 @@ export function WalletSetup({ onCreate, onImport }: Props) {
|
||||
<Wallet className="w-10 h-10 text-primary" />
|
||||
</div>
|
||||
<h1 className="text-2xl font-bold mb-2">Pezkuwi Wallet</h1>
|
||||
<p className="text-muted-foreground">Berîka fermî ya Pezkuwichain</p>
|
||||
<p className="text-muted-foreground">{t('walletSetup.officialWallet')}</p>
|
||||
</div>
|
||||
|
||||
<div className="space-y-3">
|
||||
@@ -30,8 +33,8 @@ export function WalletSetup({ onCreate, onImport }: Props) {
|
||||
<Plus className="w-6 h-6" />
|
||||
</div>
|
||||
<div className="text-left">
|
||||
<p className="font-semibold">Wallet Nû Çêbike</p>
|
||||
<p className="text-sm opacity-80">Wallet'ekî nû bi seed phrase çêbike</p>
|
||||
<p className="font-semibold">{t('walletSetup.createNew')}</p>
|
||||
<p className="text-sm opacity-80">{t('walletSetup.createNewDesc')}</p>
|
||||
</div>
|
||||
</button>
|
||||
|
||||
@@ -43,16 +46,14 @@ export function WalletSetup({ onCreate, onImport }: Props) {
|
||||
<Download className="w-6 h-6 text-primary" />
|
||||
</div>
|
||||
<div className="text-left">
|
||||
<p className="font-semibold">Wallet Import Bike</p>
|
||||
<p className="text-sm text-muted-foreground">
|
||||
Seed phrase'ê xwe yê heyî bi kar bîne
|
||||
</p>
|
||||
<p className="font-semibold">{t('walletSetup.importWallet')}</p>
|
||||
<p className="text-sm text-muted-foreground">{t('walletSetup.importWalletDesc')}</p>
|
||||
</div>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<p className="text-center text-xs text-muted-foreground px-4">
|
||||
Wallet'ê te bi ewlehî li cîhaza te tê hilanîn. Em tu carî gihîştina mifteyên te tune.
|
||||
{t('walletSetup.securityNote')}
|
||||
</p>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -0,0 +1,131 @@
|
||||
import { createContext, useContext, useState, useEffect, useCallback, type ReactNode } from 'react';
|
||||
import type { Translations, LanguageCode } from './types';
|
||||
import { RTL_LANGUAGES } from './types';
|
||||
import krd from './translations/krd';
|
||||
import en from './translations/en';
|
||||
import tr from './translations/tr';
|
||||
import ckb from './translations/ckb';
|
||||
import fa from './translations/fa';
|
||||
import ar from './translations/ar';
|
||||
|
||||
const translations: Record<LanguageCode, Translations> = {
|
||||
krd,
|
||||
en,
|
||||
tr,
|
||||
ckb,
|
||||
fa,
|
||||
ar,
|
||||
};
|
||||
|
||||
const VALID_LANGS: LanguageCode[] = ['krd', 'en', 'tr', 'ckb', 'fa', 'ar'];
|
||||
const DEFAULT_LANG: LanguageCode = 'krd';
|
||||
|
||||
/**
|
||||
* Detect language from URL path.
|
||||
* e.g. /krd/... -> krd, /en/... -> en, / -> krd (default)
|
||||
*/
|
||||
function detectLanguageFromURL(): LanguageCode {
|
||||
const path = window.location.pathname;
|
||||
const firstSegment = path.split('/').filter(Boolean)[0];
|
||||
if (firstSegment && VALID_LANGS.includes(firstSegment as LanguageCode)) {
|
||||
return firstSegment as LanguageCode;
|
||||
}
|
||||
return DEFAULT_LANG;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a nested value from an object using dot notation.
|
||||
* e.g. getNestedValue(obj, 'nav.forum') -> obj.nav.forum
|
||||
*/
|
||||
function getNestedValue(obj: Record<string, unknown>, path: string): string | undefined {
|
||||
const keys = path.split('.');
|
||||
let current: unknown = obj;
|
||||
for (const key of keys) {
|
||||
if (current == null || typeof current !== 'object') return undefined;
|
||||
current = (current as Record<string, unknown>)[key];
|
||||
}
|
||||
return typeof current === 'string' ? current : undefined;
|
||||
}
|
||||
|
||||
interface LanguageContextType {
|
||||
lang: LanguageCode;
|
||||
setLang: (lang: LanguageCode) => void;
|
||||
t: (key: string, params?: Record<string, string | number>) => string;
|
||||
isRTL: boolean;
|
||||
}
|
||||
|
||||
const LanguageContext = createContext<LanguageContextType | null>(null);
|
||||
|
||||
interface LanguageProviderProps {
|
||||
children: ReactNode;
|
||||
}
|
||||
|
||||
export function LanguageProvider({ children }: LanguageProviderProps) {
|
||||
const [lang, setLangState] = useState<LanguageCode>(detectLanguageFromURL);
|
||||
|
||||
const isRTL = RTL_LANGUAGES.includes(lang);
|
||||
|
||||
// Update document direction and lang attribute when language changes
|
||||
useEffect(() => {
|
||||
document.documentElement.lang = lang === 'krd' ? 'ku' : lang;
|
||||
document.documentElement.dir = isRTL ? 'rtl' : 'ltr';
|
||||
}, [lang, isRTL]);
|
||||
|
||||
const setLang = useCallback((newLang: LanguageCode) => {
|
||||
setLangState(newLang);
|
||||
// Update URL without reload
|
||||
const currentPath = window.location.pathname;
|
||||
const segments = currentPath.split('/').filter(Boolean);
|
||||
// Remove old lang prefix if present
|
||||
if (segments.length > 0 && VALID_LANGS.includes(segments[0] as LanguageCode)) {
|
||||
segments.shift();
|
||||
}
|
||||
const newPath = `/${newLang}${segments.length > 0 ? '/' + segments.join('/') : ''}`;
|
||||
window.history.replaceState(null, '', newPath);
|
||||
}, []);
|
||||
|
||||
const t = useCallback(
|
||||
(key: string, params?: Record<string, string | number>): string => {
|
||||
// Try current language first
|
||||
let value = getNestedValue(translations[lang] as unknown as Record<string, unknown>, key);
|
||||
// Fallback to Kurdish
|
||||
if (value === undefined && lang !== DEFAULT_LANG) {
|
||||
value = getNestedValue(
|
||||
translations[DEFAULT_LANG] as unknown as Record<string, unknown>,
|
||||
key
|
||||
);
|
||||
}
|
||||
// If still not found, return the key itself
|
||||
if (value === undefined) return key;
|
||||
|
||||
// Replace params like {time}, {count}, {amount}, {rating}
|
||||
if (params) {
|
||||
let result = value;
|
||||
for (const [paramKey, paramValue] of Object.entries(params)) {
|
||||
result = result.replace(`{${paramKey}}`, String(paramValue));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
return value;
|
||||
},
|
||||
[lang]
|
||||
);
|
||||
|
||||
return (
|
||||
<LanguageContext.Provider value={{ lang, setLang, t, isRTL }}>
|
||||
{children}
|
||||
</LanguageContext.Provider>
|
||||
);
|
||||
}
|
||||
|
||||
export function useTranslation() {
|
||||
const context = useContext(LanguageContext);
|
||||
if (!context) {
|
||||
throw new Error('useTranslation must be used within a LanguageProvider');
|
||||
}
|
||||
return context;
|
||||
}
|
||||
|
||||
export type { LanguageCode, Translations };
|
||||
export { VALID_LANGS, DEFAULT_LANG, RTL_LANGUAGES, LANGUAGE_NAMES } from './types';
|
||||
@@ -0,0 +1,304 @@
|
||||
import type { Translations } from '../types';
|
||||
|
||||
const ar: Translations = {
|
||||
nav: {
|
||||
announcements: 'الأخبار',
|
||||
forum: 'المنتدى',
|
||||
rewards: 'المكافآت',
|
||||
p2p: 'P2P',
|
||||
wallet: 'المحفظة',
|
||||
},
|
||||
|
||||
common: {
|
||||
back: 'رجوع',
|
||||
cancel: 'إلغاء',
|
||||
continue: 'متابعة',
|
||||
close: 'إغلاق',
|
||||
copy: 'نسخ',
|
||||
copied: 'تم النسخ!',
|
||||
share: 'مشاركة',
|
||||
refresh: 'تحديث',
|
||||
retry: 'حاول مجددًا',
|
||||
loading: 'جارٍ التحميل...',
|
||||
error: 'خطأ',
|
||||
anonymous: 'مجهول',
|
||||
pinned: 'مثبّت',
|
||||
locked: 'مقفل',
|
||||
trending: 'رائج',
|
||||
},
|
||||
|
||||
announcements: {
|
||||
title: 'الإعلانات',
|
||||
readMore: 'اقرأ المزيد',
|
||||
reactionAuthRequired: 'يجب أن تكون في تيليجرام للتصويت',
|
||||
},
|
||||
|
||||
forum: {
|
||||
title: 'المنتدى',
|
||||
newTopic: 'موضوع جديد',
|
||||
submitting: 'جارٍ الإرسال...',
|
||||
publish: 'نشر',
|
||||
category: 'الفئة',
|
||||
topicTitle: 'العنوان',
|
||||
topicTitlePlaceholder: 'عنوان الموضوع...',
|
||||
content: 'المحتوى',
|
||||
contentPlaceholder: 'اكتب محتوى الموضوع...',
|
||||
tagsLabel: 'الوسوم (افصل بينها بفاصلة)',
|
||||
tagsPlaceholder: 'blockchain, kurd, pez...',
|
||||
searchPlaceholder: 'ابحث في المواضيع...',
|
||||
sortRecent: 'جديد',
|
||||
sortPopular: 'شائع',
|
||||
sortReplies: 'الردود',
|
||||
sortViews: 'المشاهدات',
|
||||
all: 'الكل',
|
||||
replies: 'الردود',
|
||||
noRepliesYet: 'لا توجد ردود بعد',
|
||||
beFirstToReply: 'كن أول من يردّ!',
|
||||
replyPlaceholder: 'اكتب ردّك...',
|
||||
noTopicsFound: 'لم يتم العثور على مواضيع',
|
||||
changeFilters: 'غيّر عوامل التصفية',
|
||||
createNewTopic: 'إنشاء موضوع جديد',
|
||||
loginToVote: 'سجّل الدخول للتصويت',
|
||||
voteError: 'خطأ في التصويت',
|
||||
writeReply: 'يرجى كتابة ردّك',
|
||||
topicLocked: 'هذا الموضوع مقفل',
|
||||
replyError: 'خطأ في إرسال الرد',
|
||||
fillAllFields: 'يرجى ملء جميع الحقول',
|
||||
topicCreated: 'تم إنشاء الموضوع!',
|
||||
topicCreateError: 'خطأ في إنشاء الموضوع',
|
||||
},
|
||||
|
||||
rewards: {
|
||||
title: 'المكافآت',
|
||||
subtitle: 'المكافآت - نظام الإحالة',
|
||||
connectWalletFirst: 'لعرض إحالاتك ومكافآتك، قم بربط محفظتك أولاً.',
|
||||
overview: 'نظرة عامة',
|
||||
referral: 'الإحالة',
|
||||
scores: 'النقاط',
|
||||
referralScore: 'نقاط الإحالة',
|
||||
maxScore: 'الحد الأقصى: 500',
|
||||
referMoreTitle: 'أحِل أكثر، واكسب أكثر!',
|
||||
referMoreDescription:
|
||||
'مقابل كل شخص تدعوه، تحصل على HEZ و PEZ كمكافآت. المزيد من الإحالات = المزيد من المكافآت!',
|
||||
kycApproved: 'تم اعتماد KYC',
|
||||
referrer: 'المُحيل',
|
||||
none: 'لا يوجد',
|
||||
invitedMe: 'دعاني',
|
||||
pendingReferral: 'إحالة معلّقة',
|
||||
completeKyc: 'أكمل KYC للموافقة على الإحالة من',
|
||||
inviteFriends: 'ادعُ أصدقاءك',
|
||||
yourLink: 'رابطك',
|
||||
copySuccess: 'تم النسخ!',
|
||||
copyLink: 'نسخ',
|
||||
shareLink: 'مشاركة',
|
||||
scoreSystem: 'نظام النقاط',
|
||||
activeStatus: 'حالة النشاط',
|
||||
timeRemaining: 'الوقت: {time} متبقٍ',
|
||||
active: 'نشط',
|
||||
inactive: 'غير نشط',
|
||||
activeDescription: 'انقر مرة واحدة كل 24 ساعة لتبقى نشطًا وتكسب المزيد من المكافآت!',
|
||||
youAreActive: 'أنت نشط!',
|
||||
iAmActive: 'أنا نشط!',
|
||||
activatedAlert: 'أنت الآن نشط! انقر مجددًا بعد 24 ساعة.',
|
||||
shareText: 'Pezkuwichain - الدولة الرقمية لكردستان! انضم إلينا عبر رابطي:',
|
||||
copyAlert: 'تم النسخ',
|
||||
referralCount: '{count} إحالة (معتمدة KYC)',
|
||||
noReferrals: 'ليس لديك إحالات بعد',
|
||||
shareYourLink: 'شارك رابطك!',
|
||||
trustScore: 'نقاط الثقة',
|
||||
rank: 'الرتبة: {rating}',
|
||||
citizen: 'مواطن',
|
||||
staking: 'التخزين',
|
||||
stakingNotStarted: 'لم يبدأ بعد',
|
||||
stakingCountedInTrust: 'يُحتسب في نقاط الثقة',
|
||||
people: '{count} شخص',
|
||||
tiki: 'تيكي',
|
||||
nftRole: 'دور NFT',
|
||||
education: 'التعليم',
|
||||
reading: 'القراءة',
|
||||
stakingRewards: 'مكافآت التخزين',
|
||||
totalRewards: 'إجمالي المكافآت المستلمة',
|
||||
recentRewards: 'المكافآت الأخيرة',
|
||||
noRewardsYet: 'لا توجد مكافآت مسجّلة بعد',
|
||||
scoreFormula: 'معادلة النقاط',
|
||||
stakingZeroWarning: 'إذا كان التخزين 0، فنقاط الثقة أيضًا 0. قم بالتخزين أولاً!',
|
||||
refreshScores: 'تحديث النقاط',
|
||||
points: 'نقاط',
|
||||
},
|
||||
|
||||
wallet: {
|
||||
title: 'المحفظة',
|
||||
authFailed: 'فشل المصادقة',
|
||||
authDescription: 'يرجى التأكد من فتح هذا التطبيق داخل تيليجرام',
|
||||
retry: 'حاول مجددًا',
|
||||
},
|
||||
|
||||
walletSetup: {
|
||||
officialWallet: 'محفظة Pezkuwichain الرسمية',
|
||||
createNew: 'إنشاء محفظة جديدة',
|
||||
createNewDesc: 'إنشاء محفظة جديدة بعبارة الاسترداد',
|
||||
importWallet: 'استيراد محفظة',
|
||||
importWalletDesc: 'استخدم عبارة الاسترداد الموجودة لديك',
|
||||
securityNote: 'محفظتك مخزّنة بأمان على جهازك. لا نملك أبدًا إمكانية الوصول إلى مفاتيحك.',
|
||||
},
|
||||
|
||||
walletCreate: {
|
||||
setPassword: 'تعيين كلمة المرور',
|
||||
passwordDescription: 'ستُستخدم كلمة المرور هذه لفتح محفظتك',
|
||||
passwordLabel: 'كلمة المرور',
|
||||
passwordPlaceholder: '12 حرفًا على الأقل',
|
||||
confirmPasswordLabel: 'تأكيد كلمة المرور',
|
||||
confirmPasswordPlaceholder: 'أكّد كلمة المرور',
|
||||
passwordRequirements: 'متطلبات كلمة المرور:',
|
||||
ruleMinLength: '12 حرفًا على الأقل',
|
||||
ruleLowercase: 'حرف صغير واحد على الأقل (a-z)',
|
||||
ruleUppercase: 'حرف كبير واحد على الأقل (A-Z)',
|
||||
ruleNumber: 'رقم واحد على الأقل (0-9)',
|
||||
ruleSpecialChar: 'رمز خاص واحد على الأقل (!@#$%...)',
|
||||
rulePasswordsMatch: 'كلمتا المرور متطابقتان',
|
||||
walletServiceNotReady: 'خدمة المحفظة غير جاهزة. يرجى الانتظار.',
|
||||
passwordRequirementsNotMet: 'يرجى استيفاء جميع متطلبات كلمة المرور',
|
||||
walletCreationFailed: 'فشل إنشاء المحفظة. يرجى المحاولة مجددًا',
|
||||
preparing: 'جارٍ التحضير...',
|
||||
creating: 'جارٍ الإنشاء...',
|
||||
meetPasswordRequirements: 'استوفِ متطلبات كلمة المرور',
|
||||
backupTitle: 'نسخ عبارة الاسترداد احتياطيًا',
|
||||
backupDescription: 'هذه الكلمات الـ 12 هي محفظتك. اكتبها في مكان آمن!',
|
||||
backupWarning:
|
||||
'مهم: تُعرض هذه الكلمات مرة واحدة فقط. إذا فقدتها، لن تتمكن من الوصول إلى محفظتك.',
|
||||
copiedMnemonic: 'تم النسخ!',
|
||||
copyMnemonic: 'نسخ',
|
||||
conditionWrittenDown: 'لقد كتبت هذه الكلمات الـ 12 في مكان آمن',
|
||||
conditionNeverShare: 'أفهم أنه يجب ألّا أشارك هذه الكلمات مع أي شخص',
|
||||
conditionLossRisk: 'أفهم أنه إذا فقدت هذه الكلمات فلن أتمكن من الوصول إلى محفظتي',
|
||||
acceptAllConditions: 'قبول جميع الشروط',
|
||||
verifyWords: 'التحقق من الكلمات',
|
||||
reset: 'إعادة تعيين',
|
||||
verifyDescription: 'يرجى ترتيب الكلمات بالترتيب الصحيح',
|
||||
dropWordsHere: 'ضع الكلمات هنا...',
|
||||
wrongOrder: 'ترتيب الكلمات خاطئ. يرجى المحاولة مجددًا',
|
||||
saving: 'جارٍ الحفظ...',
|
||||
verify: 'تحقّق',
|
||||
wordsCount: '{count}/12 كلمة',
|
||||
walletCreated: 'تم إنشاء المحفظة!',
|
||||
walletReady: 'محفظتك جاهزة',
|
||||
yourAddress: 'عنوانك',
|
||||
getStarted: 'ابدأ الآن',
|
||||
},
|
||||
|
||||
walletImport: {
|
||||
title: 'استيراد محفظة',
|
||||
description: 'أدخل عبارة الاسترداد الخاصة بمحفظتك الحالية',
|
||||
seedPhraseLabel: 'عبارة الاسترداد (12 أو 24 كلمة)',
|
||||
seedPhrasePlaceholder: 'أدخل كلماتك مفصولة بمسافات...',
|
||||
wordsCount: '{count} / 12 كلمة',
|
||||
newPassword: 'كلمة مرور جديدة',
|
||||
seedPhraseInvalid: 'يجب أن تكون عبارة الاسترداد 12 أو 24 كلمة',
|
||||
passwordInvalid: 'كلمة المرور غير صالحة',
|
||||
passwordsMismatch: 'كلمتا المرور غير متطابقتين',
|
||||
importFailed: 'فشل الاستيراد',
|
||||
importing: 'جارٍ الاستيراد...',
|
||||
importButton: 'استيراد',
|
||||
},
|
||||
|
||||
walletConnect: {
|
||||
deleteTitle: 'حذف المحفظة؟',
|
||||
deleteDescription:
|
||||
'لا يمكن التراجع عن هذا الإجراء. إذا لم تكن لديك عبارة الاسترداد، فلن تتمكن من الوصول إلى محفظتك.',
|
||||
deleteButton: 'حذف',
|
||||
openWallet: 'فتح المحفظة',
|
||||
passwordLabel: 'كلمة المرور',
|
||||
passwordPlaceholder: 'أدخل كلمة المرور',
|
||||
enterPassword: 'أدخل كلمة المرور',
|
||||
wrongPassword: 'كلمة مرور خاطئة',
|
||||
connecting: 'جارٍ الفتح...',
|
||||
connect: 'اتصال',
|
||||
deleteWalletLink: 'حذف المحفظة',
|
||||
},
|
||||
|
||||
deposit: {
|
||||
title: 'إيداع USDT',
|
||||
subtitle: 'لـ wUSDT على Asset Hub',
|
||||
depositHistory: 'سجل الإيداعات',
|
||||
noDeposits: 'لا توجد إيداعات بعد',
|
||||
goBack: 'رجوع',
|
||||
selectNetwork: 'اختر الشبكة',
|
||||
recommended: 'موصى به',
|
||||
warning: 'تحذير!',
|
||||
example: 'مثال: أرسل 10 USDT \u2192 تستلم 7 wUSDT (رسوم $3)',
|
||||
acceptTrc20: 'أوافق، أرسل عبر TRC20',
|
||||
important: 'مهم!',
|
||||
minimum: 'الحد الأدنى: {amount} USDT',
|
||||
memoRequired: 'اكتب الرمز الخاص بك في حقل المذكرة/التعليق',
|
||||
onlyUsdt: 'أرسل USDT فقط، العملات الأخرى ستُفقد',
|
||||
trc20Fee: 'سيتم خصم رسوم $3 من المبلغ الخاص بك',
|
||||
depositAddress: 'عنوان الإيداع',
|
||||
notAvailable: 'غير متاح',
|
||||
memoLabel: 'المذكرة / التعليق (مطلوب)',
|
||||
memoWarning: 'اكتب هذا الرمز في المذكرة، وإلا لن يتم التعرف على إيداعك!',
|
||||
uniqueAddress: 'هذا العنوان خاص بك. لا حاجة لمذكرة.',
|
||||
howToDeposit: 'كيفية الإيداع؟',
|
||||
stepCopyAddress: 'انسخ العنوان',
|
||||
stepCopyMemo: 'انسخ رمز المذكرة',
|
||||
stepOpenTon: 'افتح محفظة تيليجرام أو محفظتك',
|
||||
stepOpenPolkadot: 'افتح محفظة Polkadot الخاصة بك',
|
||||
stepOpenTrc20: 'افتح TronLink أو محفظتك',
|
||||
stepSendUsdt: 'أرسل USDT إلى العنوان أعلاه',
|
||||
stepReceive: 'سيصل wUSDT إلى حسابك خلال دقائق قليلة',
|
||||
processingTime: 'وقت المعالجة: ~1-5 دقائق',
|
||||
copyFailed: 'فشل النسخ',
|
||||
statusPending: 'قيد الانتظار',
|
||||
statusConfirming: 'قيد التأكيد',
|
||||
statusCompleted: 'مكتمل',
|
||||
statusFailed: 'فشل',
|
||||
statusExpired: 'منتهي الصلاحية',
|
||||
viewTx: 'عرض المعاملة',
|
||||
trc20FeeWarning: 'رسوم شبكة TRC20 حوالي $3. نوصي بشبكة TON أو Polkadot.',
|
||||
},
|
||||
|
||||
p2p: {
|
||||
title: 'تبادل P2P',
|
||||
subtitle: 'تداول العملات الرقمية بين الأفراد',
|
||||
firstTime: 'أول مرة تستخدم P2P؟',
|
||||
steps: [
|
||||
'انقر على الزر أدناه لفتح تطبيق الويب',
|
||||
'أنشئ حسابًا أو سجّل الدخول',
|
||||
'أكمل عملية إعداد P2P',
|
||||
'بعد الإعداد، يمكنك الوصول إلى P2P مباشرة',
|
||||
],
|
||||
note: 'سيُفتح تطبيق الويب في نافذة جديدة. أكمل عملية التسجيل هناك.',
|
||||
button: 'فتح منصة P2P',
|
||||
},
|
||||
|
||||
update: {
|
||||
newVersion: 'يتوفر إصدار جديد!',
|
||||
description: 'حدّث للحصول على ميزات جديدة وإصلاحات أمنية.',
|
||||
later: 'لاحقًا',
|
||||
updateNow: 'تحديث',
|
||||
},
|
||||
|
||||
social: {
|
||||
followUs: 'تابعنا',
|
||||
stayConnected: 'ابقَ على تواصل واحصل على آخر الأخبار!',
|
||||
instagram: 'صور وقصص',
|
||||
tiktok: 'فيديوهات قصيرة',
|
||||
snapchat: 'أرسل لنا سناب!',
|
||||
telegram: 'القناة الرسمية',
|
||||
twitter: 'أخبار يومية',
|
||||
youtube: 'فيديوهاتنا',
|
||||
facebook: 'الصفحة الرسمية',
|
||||
discord: 'مجتمعنا',
|
||||
},
|
||||
|
||||
errorBoundary: {
|
||||
title: 'حدث خطأ ما',
|
||||
description: 'عذرًا، حدث خطأ تقني. يرجى المحاولة مجددًا.',
|
||||
retry: 'حاول مجددًا',
|
||||
},
|
||||
|
||||
loadingScreen: {
|
||||
loading: 'جارٍ التحميل...',
|
||||
},
|
||||
};
|
||||
|
||||
export default ar;
|
||||
@@ -0,0 +1,306 @@
|
||||
import type { Translations } from '../types';
|
||||
|
||||
const ckb: Translations = {
|
||||
nav: {
|
||||
announcements: 'هەواڵەکان',
|
||||
forum: 'فۆڕەم',
|
||||
rewards: 'خەڵاتەکان',
|
||||
p2p: 'P2P',
|
||||
wallet: 'جزدان',
|
||||
},
|
||||
|
||||
common: {
|
||||
back: 'گەڕانەوە',
|
||||
cancel: 'هەڵوەشاندنەوە',
|
||||
continue: 'بەردەوامبوون',
|
||||
close: 'داخستن',
|
||||
copy: 'لەبەرگرتنەوە',
|
||||
copied: 'لەبەرگیرا!',
|
||||
share: 'هاوبەشکردن',
|
||||
refresh: 'نوێکردنەوە',
|
||||
retry: 'دووبارە هەوڵبدەرەوە',
|
||||
loading: 'بارکردن...',
|
||||
error: 'هەڵە',
|
||||
anonymous: 'بێناو',
|
||||
pinned: 'سنجەکراو',
|
||||
locked: 'قفڵکراو',
|
||||
trending: 'بەرزەبایەخ',
|
||||
},
|
||||
|
||||
announcements: {
|
||||
title: 'ڕاگەیاندنەکان',
|
||||
readMore: 'زیاتر بخوێنەرەوە',
|
||||
reactionAuthRequired: 'بۆ دەنگدان دەبێت لە تێلێگرام بیت',
|
||||
},
|
||||
|
||||
forum: {
|
||||
title: 'فۆڕەم',
|
||||
newTopic: 'بابەتی نوێ',
|
||||
submitting: 'ناردن...',
|
||||
publish: 'بڵاوکردنەوە',
|
||||
category: 'پۆل',
|
||||
topicTitle: 'ناونیشان',
|
||||
topicTitlePlaceholder: 'ناونیشانی بابەت...',
|
||||
content: 'ناوەڕۆک',
|
||||
contentPlaceholder: 'ناوەڕۆکی بابەتەکە بنووسە...',
|
||||
tagsLabel: 'تاگەکان (بە کۆما جیابکەرەوە)',
|
||||
tagsPlaceholder: 'بلۆکچەین، کورد، پێز...',
|
||||
searchPlaceholder: 'گەڕان لە بابەتەکان...',
|
||||
sortRecent: 'نوێ',
|
||||
sortPopular: 'بەناوبانگ',
|
||||
sortReplies: 'وەڵامەکان',
|
||||
sortViews: 'بینینەکان',
|
||||
all: 'هەموو',
|
||||
replies: 'وەڵامەکان',
|
||||
noRepliesYet: 'هێشتا هیچ وەڵامێک نییە',
|
||||
beFirstToReply: 'یەکەم کەس بە بۆ وەڵامدانەوە!',
|
||||
replyPlaceholder: 'وەڵامەکەت بنووسە...',
|
||||
noTopicsFound: 'هیچ بابەتێک نەدۆزرایەوە',
|
||||
changeFilters: 'فلتەرەکانت بگۆڕە',
|
||||
createNewTopic: 'بابەتی نوێ دروستبکە',
|
||||
loginToVote: 'بۆ دەنگدان چوونەژوورەوە بکە',
|
||||
voteError: 'هەڵە لە دەنگدان',
|
||||
writeReply: 'تکایە وەڵامەکەت بنووسە',
|
||||
topicLocked: 'ئەم بابەتە قفڵکراوە',
|
||||
replyError: 'هەڵە لە ناردنی وەڵام',
|
||||
fillAllFields: 'تکایە هەموو خانەکان پڕبکەرەوە',
|
||||
topicCreated: 'بابەتەکە دروستکرا!',
|
||||
topicCreateError: 'هەڵە لە دروستکردنی بابەت',
|
||||
},
|
||||
|
||||
rewards: {
|
||||
title: 'خەڵاتەکان',
|
||||
subtitle: 'خەڵاتەکان - سیستەمی بانگهێشتکردن',
|
||||
connectWalletFirst: 'بۆ بینینی بانگهێشتکراوەکانت و خەڵاتەکان، سەرەتا جزدانەکەت پەیوەست بکە.',
|
||||
overview: 'پوختە',
|
||||
referral: 'بانگهێشتکردن',
|
||||
scores: 'خاڵەکان',
|
||||
referralScore: 'خاڵی بانگهێشتکردن',
|
||||
maxScore: 'زۆرترین خاڵ: ٥٠٠',
|
||||
referMoreTitle: 'زیاتر بانگهێشت بکە، زیاتر قازانج بکە!',
|
||||
referMoreDescription:
|
||||
'بۆ هەر کەسێک کە دەیهێنیت، HEZ و PEZ وەک خەڵات وەردەگریت. زیاتر بانگهێشتکردن = زیاتر خەڵات!',
|
||||
kycApproved: 'KYC پەسەندکراو',
|
||||
referrer: 'بانگهێشتکەر',
|
||||
none: 'هیچ',
|
||||
invitedMe: 'بانگهێشتی منی کرد',
|
||||
pendingReferral: 'بانگهێشتی چاوەڕوان',
|
||||
completeKyc: 'KYC تەواو بکە بۆ پەسەندکردنی بانگهێشتکردن لەلایەن',
|
||||
inviteFriends: 'هاوڕێکانت بانگهێشت بکە',
|
||||
yourLink: 'لینکەکەت',
|
||||
copySuccess: 'لەبەرگیرا!',
|
||||
copyLink: 'لەبەرگرتنەوە',
|
||||
shareLink: 'هاوبەشکردن',
|
||||
scoreSystem: 'سیستەمی خاڵ',
|
||||
activeStatus: 'دۆخی چالاکی',
|
||||
timeRemaining: 'کات: {time} ماوە',
|
||||
active: 'چالاک',
|
||||
inactive: 'ناچالاک',
|
||||
activeDescription:
|
||||
'هەر ٢٤ کاتژمێرێک جارێک کلیک بکە بۆ ئەوەی چالاک بمێنیت و زیاتر خەڵات بەدەستبهێنیت!',
|
||||
youAreActive: 'تۆ چالاکیت!',
|
||||
iAmActive: 'من چالاکم!',
|
||||
activatedAlert: 'ئێستا چالاکیت! دوای ٢٤ کاتژمێر دووبارە کلیک بکە.',
|
||||
shareText: 'پێزکوێچەین - دەوڵەتی دیجیتاڵی کوردستان! لە ڕێگەی لینکەکەمەوە پەیوەستمان ببە:',
|
||||
copyAlert: 'لەبەرگیرا',
|
||||
referralCount: '{count} بانگهێشتکراو (KYC پەسەندکراو)',
|
||||
noReferrals: 'هێشتا هیچ بانگهێشتکراوێکت نییە',
|
||||
shareYourLink: 'لینکەکەت هاوبەش بکە!',
|
||||
trustScore: 'خاڵی متمانە',
|
||||
rank: 'پلە: {rating}',
|
||||
citizen: 'هاوڵاتی',
|
||||
staking: 'ستەیکینگ',
|
||||
stakingNotStarted: 'دەستپێنەکراوە',
|
||||
stakingCountedInTrust: 'لە خاڵی متمانە ژمێردراوە',
|
||||
people: '{count} کەس',
|
||||
tiki: 'تیکی',
|
||||
nftRole: 'ڕۆڵی NFT',
|
||||
education: 'پەروەردە',
|
||||
reading: 'خوێندنەوە',
|
||||
stakingRewards: 'خەڵاتەکانی ستەیکینگ',
|
||||
totalRewards: 'کۆی خەڵاتە وەرگیراوەکان',
|
||||
recentRewards: 'خەڵاتە تازەکان',
|
||||
noRewardsYet: 'هێشتا هیچ خەڵاتێک تۆمار نەکراوە',
|
||||
scoreFormula: 'فۆرمولای خاڵ',
|
||||
stakingZeroWarning: 'ئەگەر ستەیکینگ ٠ بێت، خاڵی متمانەش ٠ دەبێت. سەرەتا ستەیک بکە!',
|
||||
refreshScores: 'نوێکردنەوەی خاڵەکان',
|
||||
points: 'خاڵ',
|
||||
},
|
||||
|
||||
wallet: {
|
||||
title: 'جزدان',
|
||||
authFailed: 'ناسینەوە سەرکەوتوو نەبوو',
|
||||
authDescription: 'تکایە دڵنیابەرەوە کە ئەم ئەپەت لەناو تێلێگرام کردووەتەوە',
|
||||
retry: 'دووبارە هەوڵبدەرەوە',
|
||||
},
|
||||
|
||||
walletSetup: {
|
||||
officialWallet: 'جزدانی فەرمی پێزکوێچەین',
|
||||
createNew: 'جزدانی نوێ دروستبکە',
|
||||
createNewDesc: 'جزدانی نوێ بە وشەی نهێنی دروستبکە',
|
||||
importWallet: 'هاوردەکردنی جزدان',
|
||||
importWalletDesc: 'وشەی نهێنی ئامادەکەت بەکاربهێنە',
|
||||
securityNote:
|
||||
'جزدانەکەت بە پاراستنەوە لە ئامێرەکەتدا هەڵدەگیرێت. ئێمە هەرگیز دەسمان بە کلیلەکانت ناگات.',
|
||||
},
|
||||
|
||||
walletCreate: {
|
||||
setPassword: 'وشەی نهێنی دابنێ',
|
||||
passwordDescription: 'ئەم وشەی نهێنییە بۆ کردنەوەی جزدانەکەت بەکاردێت',
|
||||
passwordLabel: 'وشەی نهێنی',
|
||||
passwordPlaceholder: 'لانیکەم ١٢ پیت',
|
||||
confirmPasswordLabel: 'دووپاتکردنەوەی وشەی نهێنی',
|
||||
confirmPasswordPlaceholder: 'وشەی نهێنی دووبارە بنووسە',
|
||||
passwordRequirements: 'مەرجەکانی وشەی نهێنی:',
|
||||
ruleMinLength: 'لانیکەم ١٢ پیت',
|
||||
ruleLowercase: 'لانیکەم ١ پیتی بچووک (a-z)',
|
||||
ruleUppercase: 'لانیکەم ١ پیتی گەورە (A-Z)',
|
||||
ruleNumber: 'لانیکەم ١ ژمارە (0-9)',
|
||||
ruleSpecialChar: 'لانیکەم ١ پیتی تایبەت (!@#$%...)',
|
||||
rulePasswordsMatch: 'وشەی نهێنییەکان وەکیەکن',
|
||||
walletServiceNotReady: 'خزمەتگوزاری جزدان ئامادە نییە. تکایە چاوەڕوان بە.',
|
||||
passwordRequirementsNotMet: 'تکایە هەموو مەرجەکانی وشەی نهێنی جێبەجێ بکە',
|
||||
walletCreationFailed: 'دروستکردنی جزدان سەرکەوتوو نەبوو. تکایە دووبارە هەوڵبدەرەوە',
|
||||
preparing: 'ئامادەکردن...',
|
||||
creating: 'دروستکردن...',
|
||||
meetPasswordRequirements: 'مەرجەکانی وشەی نهێنی جێبەجێ بکە',
|
||||
backupTitle: 'پاشەکەوتکردنی وشەی نهێنی',
|
||||
backupDescription: 'ئەم ١٢ وشەیە جزدانەکەتن. لە شوێنێکی سەلامەتدا بینووسە!',
|
||||
backupWarning:
|
||||
'گرنگ: ئەم وشانە تەنها یەک جار نیشان دەدرێن. ئەگەر لەدەست بدەیت، ناتوانیت دەستت بە جزدانەکەت بگات.',
|
||||
copiedMnemonic: 'لەبەرگیرا!',
|
||||
copyMnemonic: 'لەبەرگرتنەوە',
|
||||
conditionWrittenDown: 'ئەم ١٢ وشەم لە شوێنێکی سەلامەتدا نووسیوە',
|
||||
conditionNeverShare: 'تێدەگەم کە هەرگیز نابێت ئەم وشانە لەگەڵ کەسێکدا هاوبەش بکەم',
|
||||
conditionLossRisk: 'تێدەگەم کە ئەگەر ئەم وشانە لەدەست بدەم ناتوانم دەستم بە جزدانەکەم بگات',
|
||||
acceptAllConditions: 'هەموو مەرجەکان پەسەندبکە',
|
||||
verifyWords: 'پشتڕاستکردنەوەی وشەکان',
|
||||
reset: 'ڕیسێتکردن',
|
||||
verifyDescription: 'تکایە وشەکان بە ڕیزبەندی ڕاست ڕیزبکەرەوە',
|
||||
dropWordsHere: 'وشەکان لێرە دابنێ...',
|
||||
wrongOrder: 'ڕیزبەندی وشەکان هەڵەیە. تکایە دووبارە هەوڵبدەرەوە',
|
||||
saving: 'پاشەکەوتکردن...',
|
||||
verify: 'پشتڕاستکردنەوە',
|
||||
wordsCount: '{count}/١٢ وشە',
|
||||
walletCreated: 'جزدان دروستکرا!',
|
||||
walletReady: 'جزدانەکەت ئامادەیە',
|
||||
yourAddress: 'ناونیشانەکەت',
|
||||
getStarted: 'دەستپێبکە',
|
||||
},
|
||||
|
||||
walletImport: {
|
||||
title: 'هاوردەکردنی جزدان',
|
||||
description: 'وشەی نهێنی جزدانی ئامادەکەت بنووسە',
|
||||
seedPhraseLabel: 'وشەی نهێنی (١٢ یان ٢٤ وشە)',
|
||||
seedPhrasePlaceholder: 'وشەکان بە بۆشایی جیاکەرەوە بنووسە...',
|
||||
wordsCount: '{count} / ١٢ وشە',
|
||||
newPassword: 'وشەی نهێنی نوێ',
|
||||
seedPhraseInvalid: 'وشەی نهێنی دەبێت ١٢ یان ٢٤ وشە بێت',
|
||||
passwordInvalid: 'وشەی نهێنی نادروستە',
|
||||
passwordsMismatch: 'وشەی نهێنییەکان وەکیەک نین',
|
||||
importFailed: 'هاوردەکردن سەرکەوتوو نەبوو',
|
||||
importing: 'هاوردەکردن...',
|
||||
importButton: 'هاوردەکردن',
|
||||
},
|
||||
|
||||
walletConnect: {
|
||||
deleteTitle: 'جزدان بسڕیتەوە؟',
|
||||
deleteDescription:
|
||||
'ئەم کردارە ناگەڕێتەوە. ئەگەر وشەی نهێنیت نییە، ناتوانیت دەستت بە جزدانەکەت بگات.',
|
||||
deleteButton: 'سڕینەوە',
|
||||
openWallet: 'کردنەوەی جزدان',
|
||||
passwordLabel: 'وشەی نهێنی',
|
||||
passwordPlaceholder: 'وشەی نهێنی بنووسە',
|
||||
enterPassword: 'وشەی نهێنی بنووسە',
|
||||
wrongPassword: 'وشەی نهێنی هەڵەیە',
|
||||
connecting: 'کردنەوە...',
|
||||
connect: 'پەیوەستکردن',
|
||||
deleteWalletLink: 'سڕینەوەی جزدان',
|
||||
},
|
||||
|
||||
deposit: {
|
||||
title: 'پارەدانانی USDT',
|
||||
subtitle: 'بۆ wUSDT لەسەر Asset Hub',
|
||||
depositHistory: 'مێژووی پارەدانان',
|
||||
noDeposits: 'هێشتا هیچ پارەدانانێک نییە',
|
||||
goBack: 'گەڕانەوە',
|
||||
selectNetwork: 'تۆڕ هەڵبژێرە',
|
||||
recommended: 'پێشنیارکراو',
|
||||
warning: 'ئاگاداری!',
|
||||
example: 'بۆ نموونە: ١٠ USDT بنێرە ← ٧ wUSDT وەردەگریت ($٣ کرێ)',
|
||||
acceptTrc20: 'ڕازیم، لە ڕێگەی TRC20 بنێرە',
|
||||
important: 'گرنگ!',
|
||||
minimum: 'کەمترین: {amount} USDT',
|
||||
memoRequired: 'کۆدەکەت لە خانەی Memo/Comment بنووسە',
|
||||
onlyUsdt: 'تەنها USDT بنێرە، تۆکنی تر لەدەستدەچن',
|
||||
trc20Fee: '$٣ کرێ لە بڕەکەت دەبڕدرێتەوە',
|
||||
depositAddress: 'ناونیشانی پارەدانان',
|
||||
notAvailable: 'بەردەست نییە',
|
||||
memoLabel: 'Memo / Comment (پێویستە)',
|
||||
memoWarning: 'ئەم کۆدە لە memo بنووسە، ئەگەرنا پارەدانانەکەت ناسراونەتەوە!',
|
||||
uniqueAddress: 'ئەم ناونیشانە تایبەتە بە تۆ. پێویستی بە memo نییە.',
|
||||
howToDeposit: 'چۆن پارە دادەنێیت؟',
|
||||
stepCopyAddress: 'ناونیشانەکە لەبەربگرەوە',
|
||||
stepCopyMemo: 'کۆدی memo لەبەربگرەوە',
|
||||
stepOpenTon: 'جزدانی تێلێگرام یان جزدانەکەت بکەرەوە',
|
||||
stepOpenPolkadot: 'جزدانی Polkadot ـەکەت بکەرەوە',
|
||||
stepOpenTrc20: 'TronLink یان جزدانەکەت بکەرەوە',
|
||||
stepSendUsdt: 'USDT بنێرە بۆ ناونیشانی سەرەوە',
|
||||
stepReceive: 'wUSDT لە چەند خولەکێکدا دەگاتە ئەکاونتەکەت',
|
||||
processingTime: 'کاتی جێبەجێکردن: ~١-٥ خولەک',
|
||||
copyFailed: 'لەبەرگرتنەوە سەرکەوتوو نەبوو',
|
||||
statusPending: 'چاوەڕوان',
|
||||
statusConfirming: 'پشتڕاستکردنەوە',
|
||||
statusCompleted: 'تەواوبوو',
|
||||
statusFailed: 'سەرکەوتوو نەبوو',
|
||||
statusExpired: 'بەسەرچوو',
|
||||
viewTx: 'بینینی TX',
|
||||
trc20FeeWarning: 'کرێی تۆڕی TRC20 نزیکەی $٣ ـە. ئێمە تۆڕی TON یان Polkadot پێشنیار دەکەین.',
|
||||
},
|
||||
|
||||
p2p: {
|
||||
title: 'ئاڵوگۆڕی P2P',
|
||||
subtitle: 'ئاڵوگۆڕی کریپتۆ نێوان کەسەکان',
|
||||
firstTime: 'یەکەم جارە P2P بەکاردەهێنیت؟',
|
||||
steps: [
|
||||
'کلیک لەسەر دوگمەی خوارەوە بکە بۆ کردنەوەی وێب ئەپ',
|
||||
'ئەکاونتێک دروستبکە یان بچۆ ژوورەوە',
|
||||
'ڕێکخستنی P2P تەواو بکە',
|
||||
'دوای ڕێکخستن، دەتوانیت ڕاستەوخۆ دەستت بە P2P بگات',
|
||||
],
|
||||
note: 'وێب ئەپ لە پەنجەرەیەکی نوێدا دەکرێتەوە. ڕێکخستنەکە لەوێ تەواو بکە.',
|
||||
button: 'کردنەوەی پلاتفۆرمی P2P',
|
||||
},
|
||||
|
||||
update: {
|
||||
newVersion: 'وەشانی نوێ بەردەستە!',
|
||||
description: 'نوێکردنەوە بۆ تایبەتمەندی نوێ و چاکسازی ئاسایشی.',
|
||||
later: 'دواتر',
|
||||
updateNow: 'نوێکردنەوە',
|
||||
},
|
||||
|
||||
social: {
|
||||
followUs: 'شوێنمان بکەوە',
|
||||
stayConnected: 'پەیوەندیدار بمێنە و تازەترین هەواڵەکان وەربگرە!',
|
||||
instagram: 'وێنە و ستۆری',
|
||||
tiktok: 'ڤیدیۆی کورت',
|
||||
snapchat: 'سناپمان بۆ بنێرە!',
|
||||
telegram: 'کەناڵی فەرمی',
|
||||
twitter: 'هەواڵی ڕۆژانە',
|
||||
youtube: 'ڤیدیۆکانمان',
|
||||
facebook: 'پەیجی فەرمی',
|
||||
discord: 'کۆمەڵگاکەمان',
|
||||
},
|
||||
|
||||
errorBoundary: {
|
||||
title: 'کێشەیەک ڕوویدا',
|
||||
description: 'ببوورە، هەڵەیەکی تەکنیکی ڕوویدا. تکایە دووبارە هەوڵبدەرەوە.',
|
||||
retry: 'دووبارە هەوڵبدەرەوە',
|
||||
},
|
||||
|
||||
loadingScreen: {
|
||||
loading: 'بارکردن...',
|
||||
},
|
||||
};
|
||||
|
||||
export default ckb;
|
||||
@@ -0,0 +1,305 @@
|
||||
import type { Translations } from '../types';
|
||||
|
||||
const en: Translations = {
|
||||
nav: {
|
||||
announcements: 'News',
|
||||
forum: 'Forum',
|
||||
rewards: 'Rewards',
|
||||
p2p: 'P2P',
|
||||
wallet: 'Wallet',
|
||||
},
|
||||
|
||||
common: {
|
||||
back: 'Back',
|
||||
cancel: 'Cancel',
|
||||
continue: 'Continue',
|
||||
close: 'Close',
|
||||
copy: 'Copy',
|
||||
copied: 'Copied!',
|
||||
share: 'Share',
|
||||
refresh: 'Refresh',
|
||||
retry: 'Try again',
|
||||
loading: 'Loading...',
|
||||
error: 'Error',
|
||||
anonymous: 'Anonymous',
|
||||
pinned: 'Pinned',
|
||||
locked: 'Locked',
|
||||
trending: 'Trending',
|
||||
},
|
||||
|
||||
announcements: {
|
||||
title: 'Announcements',
|
||||
readMore: 'Read more',
|
||||
reactionAuthRequired: 'You must be in Telegram to vote',
|
||||
},
|
||||
|
||||
forum: {
|
||||
title: 'Forum',
|
||||
newTopic: 'New Topic',
|
||||
submitting: 'Submitting...',
|
||||
publish: 'Publish',
|
||||
category: 'Category',
|
||||
topicTitle: 'Title',
|
||||
topicTitlePlaceholder: 'Topic title...',
|
||||
content: 'Content',
|
||||
contentPlaceholder: 'Write the topic content...',
|
||||
tagsLabel: 'Tags (separate with comma)',
|
||||
tagsPlaceholder: 'blockchain, kurd, pez...',
|
||||
searchPlaceholder: 'Search topics...',
|
||||
sortRecent: 'New',
|
||||
sortPopular: 'Popular',
|
||||
sortReplies: 'Replies',
|
||||
sortViews: 'Views',
|
||||
all: 'All',
|
||||
replies: 'Replies',
|
||||
noRepliesYet: 'No replies yet',
|
||||
beFirstToReply: 'Be the first to reply!',
|
||||
replyPlaceholder: 'Write your reply...',
|
||||
noTopicsFound: 'No topics found',
|
||||
changeFilters: 'Change your filters',
|
||||
createNewTopic: 'Create New Topic',
|
||||
loginToVote: 'Log in to vote',
|
||||
voteError: 'Error voting',
|
||||
writeReply: 'Please write your reply',
|
||||
topicLocked: 'This topic is locked',
|
||||
replyError: 'Error sending reply',
|
||||
fillAllFields: 'Please fill in all fields',
|
||||
topicCreated: 'Topic created!',
|
||||
topicCreateError: 'Error creating topic',
|
||||
},
|
||||
|
||||
rewards: {
|
||||
title: 'Rewards',
|
||||
subtitle: 'Rewards - Referral System',
|
||||
connectWalletFirst: 'To see your referrals and rewards, connect your wallet first.',
|
||||
overview: 'Overview',
|
||||
referral: 'Referral',
|
||||
scores: 'Scores',
|
||||
referralScore: 'Referral Score',
|
||||
maxScore: 'Max score: 500',
|
||||
referMoreTitle: 'Refer more, earn more!',
|
||||
referMoreDescription:
|
||||
'For every person you bring, you receive HEZ and PEZ as rewards. More referrals = more rewards!',
|
||||
kycApproved: 'KYC Approved',
|
||||
referrer: 'Referrer',
|
||||
none: 'None',
|
||||
invitedMe: 'Invited me',
|
||||
pendingReferral: 'Pending referral',
|
||||
completeKyc: 'Complete KYC to approve referral from',
|
||||
inviteFriends: 'Invite your friends',
|
||||
yourLink: 'Your link',
|
||||
copySuccess: 'Copied!',
|
||||
copyLink: 'Copy',
|
||||
shareLink: 'Share',
|
||||
scoreSystem: 'Score system',
|
||||
activeStatus: 'Activity Status',
|
||||
timeRemaining: 'Time: {time} remaining',
|
||||
active: 'Active',
|
||||
inactive: 'Inactive',
|
||||
activeDescription: 'Click once every 24 hours to stay active and earn more rewards!',
|
||||
youAreActive: 'You are Active!',
|
||||
iAmActive: 'I am Active!',
|
||||
activatedAlert: 'You are now active! Click again after 24 hours.',
|
||||
shareText: 'Pezkuwichain - Digital State of Kurdistan! Join us through my link:',
|
||||
copyAlert: 'Copied',
|
||||
referralCount: '{count} referrals (KYC approved)',
|
||||
noReferrals: 'You have no referrals yet',
|
||||
shareYourLink: 'Share your link!',
|
||||
trustScore: 'Trust Score',
|
||||
rank: 'Rank: {rating}',
|
||||
citizen: 'Citizen',
|
||||
staking: 'Staking',
|
||||
stakingNotStarted: 'Not started',
|
||||
stakingCountedInTrust: 'Counted in Trust score',
|
||||
people: '{count} people',
|
||||
tiki: 'Tiki',
|
||||
nftRole: 'NFT Role',
|
||||
education: 'Education',
|
||||
reading: 'Reading',
|
||||
stakingRewards: 'Staking Rewards',
|
||||
totalRewards: 'Total rewards received',
|
||||
recentRewards: 'Recent rewards',
|
||||
noRewardsYet: 'No rewards recorded yet',
|
||||
scoreFormula: 'Score Formula',
|
||||
stakingZeroWarning: 'If Staking is 0, Trust score is also 0. Stake first!',
|
||||
refreshScores: 'Refresh Scores',
|
||||
points: 'points',
|
||||
},
|
||||
|
||||
wallet: {
|
||||
title: 'Wallet',
|
||||
authFailed: 'Authentication Failed',
|
||||
authDescription: 'Please make sure you open this app within Telegram',
|
||||
retry: 'Try Again',
|
||||
},
|
||||
|
||||
walletSetup: {
|
||||
officialWallet: 'Official Pezkuwichain wallet',
|
||||
createNew: 'Create New Wallet',
|
||||
createNewDesc: 'Create a new wallet with seed phrase',
|
||||
importWallet: 'Import Wallet',
|
||||
importWalletDesc: 'Use your existing seed phrase',
|
||||
securityNote:
|
||||
'Your wallet is securely stored on your device. We never have access to your keys.',
|
||||
},
|
||||
|
||||
walletCreate: {
|
||||
setPassword: 'Set Password',
|
||||
passwordDescription: 'This password will be used to unlock your wallet',
|
||||
passwordLabel: 'Password',
|
||||
passwordPlaceholder: 'At least 12 characters',
|
||||
confirmPasswordLabel: 'Confirm Password',
|
||||
confirmPasswordPlaceholder: 'Confirm your password',
|
||||
passwordRequirements: 'Password Requirements:',
|
||||
ruleMinLength: 'At least 12 characters',
|
||||
ruleLowercase: 'At least 1 lowercase letter (a-z)',
|
||||
ruleUppercase: 'At least 1 uppercase letter (A-Z)',
|
||||
ruleNumber: 'At least 1 number (0-9)',
|
||||
ruleSpecialChar: 'At least 1 special character (!@#$%...)',
|
||||
rulePasswordsMatch: 'Passwords match',
|
||||
walletServiceNotReady: 'Wallet service is not ready. Please wait.',
|
||||
passwordRequirementsNotMet: 'Please meet all password requirements',
|
||||
walletCreationFailed: 'Wallet creation failed. Please try again',
|
||||
preparing: 'Preparing...',
|
||||
creating: 'Creating...',
|
||||
meetPasswordRequirements: 'Meet password requirements',
|
||||
backupTitle: 'Backup Seed Phrase',
|
||||
backupDescription: 'These 12 words are your wallet. Write them in a safe place!',
|
||||
backupWarning:
|
||||
'Important: These words are shown only once. If you lose them, you cannot access your wallet.',
|
||||
copiedMnemonic: 'Copied!',
|
||||
copyMnemonic: 'Copy',
|
||||
conditionWrittenDown: 'I have written down these 12 words in a safe place',
|
||||
conditionNeverShare: 'I understand I must never share these words with anyone',
|
||||
conditionLossRisk: 'I understand if I lose these words I cannot access my wallet',
|
||||
acceptAllConditions: 'Accept all conditions',
|
||||
verifyWords: 'Verify Words',
|
||||
reset: 'Reset',
|
||||
verifyDescription: 'Please arrange the words in the correct order',
|
||||
dropWordsHere: 'Place words here...',
|
||||
wrongOrder: 'Wrong word order. Please try again',
|
||||
saving: 'Saving...',
|
||||
verify: 'Verify',
|
||||
wordsCount: '{count}/12 words',
|
||||
walletCreated: 'Wallet Created!',
|
||||
walletReady: 'Your wallet is ready',
|
||||
yourAddress: 'Your address',
|
||||
getStarted: 'Get Started',
|
||||
},
|
||||
|
||||
walletImport: {
|
||||
title: 'Import Wallet',
|
||||
description: 'Enter your existing wallet seed phrase',
|
||||
seedPhraseLabel: 'Seed Phrase (12 or 24 words)',
|
||||
seedPhrasePlaceholder: 'Enter your words separated by spaces...',
|
||||
wordsCount: '{count} / 12 words',
|
||||
newPassword: 'New Password',
|
||||
seedPhraseInvalid: 'Seed phrase must be 12 or 24 words',
|
||||
passwordInvalid: 'Password is invalid',
|
||||
passwordsMismatch: 'Passwords do not match',
|
||||
importFailed: 'Import failed',
|
||||
importing: 'Importing...',
|
||||
importButton: 'Import',
|
||||
},
|
||||
|
||||
walletConnect: {
|
||||
deleteTitle: 'Delete Wallet?',
|
||||
deleteDescription:
|
||||
"This action cannot be undone. If you don't have your seed phrase, you will not be able to access your wallet.",
|
||||
deleteButton: 'Delete',
|
||||
openWallet: 'Open Wallet',
|
||||
passwordLabel: 'Password',
|
||||
passwordPlaceholder: 'Enter your password',
|
||||
enterPassword: 'Enter your password',
|
||||
wrongPassword: 'Wrong password',
|
||||
connecting: 'Opening...',
|
||||
connect: 'Connect',
|
||||
deleteWalletLink: 'Delete wallet',
|
||||
},
|
||||
|
||||
deposit: {
|
||||
title: 'Deposit USDT',
|
||||
subtitle: 'For wUSDT on Asset Hub',
|
||||
depositHistory: 'Deposit History',
|
||||
noDeposits: 'No deposits yet',
|
||||
goBack: 'Go back',
|
||||
selectNetwork: 'Select Network',
|
||||
recommended: 'Recommended',
|
||||
warning: 'Warning!',
|
||||
example: 'Example: Send 10 USDT \u2192 Receive 7 wUSDT ($3 fee)',
|
||||
acceptTrc20: 'I accept, send via TRC20',
|
||||
important: 'Important!',
|
||||
minimum: 'Minimum: {amount} USDT',
|
||||
memoRequired: 'Write your code in the Memo/Comment field',
|
||||
onlyUsdt: 'Only send USDT, other tokens will be lost',
|
||||
trc20Fee: '$3 fee will be deducted from your amount',
|
||||
depositAddress: 'Deposit Address',
|
||||
notAvailable: 'Not available',
|
||||
memoLabel: 'Memo / Comment (REQUIRED)',
|
||||
memoWarning: 'Write this code in the memo, otherwise your deposit will not be recognized!',
|
||||
uniqueAddress: 'This address is uniquely yours. No memo needed.',
|
||||
howToDeposit: 'How to Deposit?',
|
||||
stepCopyAddress: 'Copy the address',
|
||||
stepCopyMemo: 'Copy the memo code',
|
||||
stepOpenTon: 'Open Telegram Wallet or your wallet',
|
||||
stepOpenPolkadot: 'Open your Polkadot wallet',
|
||||
stepOpenTrc20: 'Open TronLink or your wallet',
|
||||
stepSendUsdt: 'Send USDT to the address above',
|
||||
stepReceive: 'wUSDT will be in your account within a few minutes',
|
||||
processingTime: 'Processing time: ~1-5 minutes',
|
||||
copyFailed: 'Copy failed',
|
||||
statusPending: 'Pending',
|
||||
statusConfirming: 'Confirming',
|
||||
statusCompleted: 'Completed',
|
||||
statusFailed: 'Failed',
|
||||
statusExpired: 'Expired',
|
||||
viewTx: 'View TX',
|
||||
trc20FeeWarning: 'TRC20 network fee is about $3. We recommend TON or Polkadot network.',
|
||||
},
|
||||
|
||||
p2p: {
|
||||
title: 'P2P Exchange',
|
||||
subtitle: 'Trade crypto peer-to-peer',
|
||||
firstTime: 'First time using P2P?',
|
||||
steps: [
|
||||
'Click the button below to open the web app',
|
||||
'Create an account or log in',
|
||||
'Complete the P2P setup process',
|
||||
'After setup, you can access P2P directly',
|
||||
],
|
||||
note: 'The web app will open in a new window. Complete the registration process there.',
|
||||
button: 'Open P2P Platform',
|
||||
},
|
||||
|
||||
update: {
|
||||
newVersion: 'New version available!',
|
||||
description: 'Update for new features and security fixes.',
|
||||
later: 'Later',
|
||||
updateNow: 'Update',
|
||||
},
|
||||
|
||||
social: {
|
||||
followUs: 'Follow us',
|
||||
stayConnected: 'Stay connected and get the latest news!',
|
||||
instagram: 'Photos & Stories',
|
||||
tiktok: 'Short videos',
|
||||
snapchat: 'Snap us!',
|
||||
telegram: 'Official channel',
|
||||
twitter: 'Daily news',
|
||||
youtube: 'Our videos',
|
||||
facebook: 'Official page',
|
||||
discord: 'Our community',
|
||||
},
|
||||
|
||||
errorBoundary: {
|
||||
title: 'Something went wrong',
|
||||
description: 'Sorry, a technical error occurred. Please try again.',
|
||||
retry: 'Try again',
|
||||
},
|
||||
|
||||
loadingScreen: {
|
||||
loading: 'Loading...',
|
||||
},
|
||||
};
|
||||
|
||||
export default en;
|
||||
@@ -0,0 +1,305 @@
|
||||
import type { Translations } from '../types';
|
||||
|
||||
const fa: Translations = {
|
||||
nav: {
|
||||
announcements: 'اخبار',
|
||||
forum: 'فروم',
|
||||
rewards: 'جوایز',
|
||||
p2p: 'P2P',
|
||||
wallet: 'کیف پول',
|
||||
},
|
||||
|
||||
common: {
|
||||
back: 'بازگشت',
|
||||
cancel: 'لغو',
|
||||
continue: 'ادامه',
|
||||
close: 'بستن',
|
||||
copy: 'کپی',
|
||||
copied: 'کپی شد!',
|
||||
share: 'اشتراکگذاری',
|
||||
refresh: 'بازنشانی',
|
||||
retry: 'دوباره تلاش کنید',
|
||||
loading: 'در حال بارگذاری...',
|
||||
error: 'خطا',
|
||||
anonymous: 'ناشناس',
|
||||
pinned: 'سنجاق شده',
|
||||
locked: 'قفل شده',
|
||||
trending: 'داغ',
|
||||
},
|
||||
|
||||
announcements: {
|
||||
title: 'اطلاعیهها',
|
||||
readMore: 'بیشتر بخوانید',
|
||||
reactionAuthRequired: 'برای رأی دادن باید در تلگرام باشید',
|
||||
},
|
||||
|
||||
forum: {
|
||||
title: 'فروم',
|
||||
newTopic: 'موضوع جدید',
|
||||
submitting: 'در حال ارسال...',
|
||||
publish: 'انتشار',
|
||||
category: 'دستهبندی',
|
||||
topicTitle: 'عنوان',
|
||||
topicTitlePlaceholder: 'عنوان موضوع...',
|
||||
content: 'محتوا',
|
||||
contentPlaceholder: 'محتوای موضوع را بنویسید...',
|
||||
tagsLabel: 'برچسبها (با کاما جدا کنید)',
|
||||
tagsPlaceholder: 'blockchain, kurd, pez...',
|
||||
searchPlaceholder: 'جستجوی موضوعات...',
|
||||
sortRecent: 'جدید',
|
||||
sortPopular: 'محبوب',
|
||||
sortReplies: 'پاسخها',
|
||||
sortViews: 'بازدیدها',
|
||||
all: 'همه',
|
||||
replies: 'پاسخها',
|
||||
noRepliesYet: 'هنوز پاسخی نیست',
|
||||
beFirstToReply: 'اولین نفری باشید که پاسخ میدهد!',
|
||||
replyPlaceholder: 'پاسخ خود را بنویسید...',
|
||||
noTopicsFound: 'موضوعی یافت نشد',
|
||||
changeFilters: 'فیلترهای خود را تغییر دهید',
|
||||
createNewTopic: 'ایجاد موضوع جدید',
|
||||
loginToVote: 'برای رأی دادن وارد شوید',
|
||||
voteError: 'خطا در رأی دادن',
|
||||
writeReply: 'لطفاً پاسخ خود را بنویسید',
|
||||
topicLocked: 'این موضوع قفل شده است',
|
||||
replyError: 'خطا در ارسال پاسخ',
|
||||
fillAllFields: 'لطفاً تمام فیلدها را پر کنید',
|
||||
topicCreated: 'موضوع ایجاد شد!',
|
||||
topicCreateError: 'خطا در ایجاد موضوع',
|
||||
},
|
||||
|
||||
rewards: {
|
||||
title: 'جوایز',
|
||||
subtitle: 'جوایز - سیستم دعوت',
|
||||
connectWalletFirst: 'برای مشاهده دعوتها و جوایز، ابتدا کیف پول خود را متصل کنید.',
|
||||
overview: 'نمای کلی',
|
||||
referral: 'دعوت',
|
||||
scores: 'امتیازها',
|
||||
referralScore: 'امتیاز دعوت',
|
||||
maxScore: 'حداکثر امتیاز: ۵۰۰',
|
||||
referMoreTitle: 'بیشتر دعوت کنید، بیشتر کسب کنید!',
|
||||
referMoreDescription:
|
||||
'به ازای هر نفری که دعوت کنید، HEZ و PEZ به عنوان جایزه دریافت میکنید. دعوت بیشتر = جایزه بیشتر!',
|
||||
kycApproved: 'KYC تأیید شده',
|
||||
referrer: 'دعوتکننده',
|
||||
none: 'هیچ',
|
||||
invitedMe: 'مرا دعوت کرده',
|
||||
pendingReferral: 'دعوت در انتظار',
|
||||
completeKyc: 'KYC را تکمیل کنید تا دعوت تأیید شود از',
|
||||
inviteFriends: 'دوستان خود را دعوت کنید',
|
||||
yourLink: 'لینک شما',
|
||||
copySuccess: 'کپی شد!',
|
||||
copyLink: 'کپی',
|
||||
shareLink: 'اشتراکگذاری',
|
||||
scoreSystem: 'سیستم امتیازدهی',
|
||||
activeStatus: 'وضعیت فعالیت',
|
||||
timeRemaining: 'زمان: {time} باقیمانده',
|
||||
active: 'فعال',
|
||||
inactive: 'غیرفعال',
|
||||
activeDescription: 'هر ۲۴ ساعت یک بار کلیک کنید تا فعال بمانید و جوایز بیشتری کسب کنید!',
|
||||
youAreActive: 'شما فعال هستید!',
|
||||
iAmActive: 'من فعال هستم!',
|
||||
activatedAlert: 'شما اکنون فعال هستید! پس از ۲۴ ساعت دوباره کلیک کنید.',
|
||||
shareText: 'Pezkuwichain - دولت دیجیتال کردستان! از طریق لینک من بپیوندید:',
|
||||
copyAlert: 'کپی شد',
|
||||
referralCount: '{count} دعوت (KYC تأیید شده)',
|
||||
noReferrals: 'شما هنوز دعوتی ندارید',
|
||||
shareYourLink: 'لینک خود را به اشتراک بگذارید!',
|
||||
trustScore: 'امتیاز اعتماد',
|
||||
rank: 'رتبه: {rating}',
|
||||
citizen: 'شهروند',
|
||||
staking: 'سهامگذاری',
|
||||
stakingNotStarted: 'شروع نشده',
|
||||
stakingCountedInTrust: 'در امتیاز اعتماد محاسبه میشود',
|
||||
people: '{count} نفر',
|
||||
tiki: 'تیکی',
|
||||
nftRole: 'نقش NFT',
|
||||
education: 'آموزش',
|
||||
reading: 'مطالعه',
|
||||
stakingRewards: 'جوایز سهامگذاری',
|
||||
totalRewards: 'کل جوایز دریافت شده',
|
||||
recentRewards: 'جوایز اخیر',
|
||||
noRewardsYet: 'هنوز جایزهای ثبت نشده',
|
||||
scoreFormula: 'فرمول امتیاز',
|
||||
stakingZeroWarning: 'اگر سهامگذاری ۰ باشد، امتیاز اعتماد نیز ۰ است. ابتدا سهامگذاری کنید!',
|
||||
refreshScores: 'بازنشانی امتیازها',
|
||||
points: 'امتیاز',
|
||||
},
|
||||
|
||||
wallet: {
|
||||
title: 'کیف پول',
|
||||
authFailed: 'احراز هویت ناموفق',
|
||||
authDescription: 'لطفاً مطمئن شوید که این برنامه را در تلگرام باز کردهاید',
|
||||
retry: 'دوباره تلاش کنید',
|
||||
},
|
||||
|
||||
walletSetup: {
|
||||
officialWallet: 'کیف پول رسمی Pezkuwichain',
|
||||
createNew: 'ایجاد کیف پول جدید',
|
||||
createNewDesc: 'ایجاد کیف پول جدید با عبارت بازیابی',
|
||||
importWallet: 'وارد کردن کیف پول',
|
||||
importWalletDesc: 'استفاده از عبارت بازیابی موجود',
|
||||
securityNote:
|
||||
'کیف پول شما به صورت امن در دستگاه شما ذخیره میشود. ما هرگز به کلیدهای شما دسترسی نداریم.',
|
||||
},
|
||||
|
||||
walletCreate: {
|
||||
setPassword: 'تنظیم رمز عبور',
|
||||
passwordDescription: 'این رمز عبور برای باز کردن قفل کیف پول شما استفاده میشود',
|
||||
passwordLabel: 'رمز عبور',
|
||||
passwordPlaceholder: 'حداقل ۱۲ کاراکتر',
|
||||
confirmPasswordLabel: 'تأیید رمز عبور',
|
||||
confirmPasswordPlaceholder: 'رمز عبور خود را تأیید کنید',
|
||||
passwordRequirements: 'الزامات رمز عبور:',
|
||||
ruleMinLength: 'حداقل ۱۲ کاراکتر',
|
||||
ruleLowercase: 'حداقل ۱ حرف کوچک (a-z)',
|
||||
ruleUppercase: 'حداقل ۱ حرف بزرگ (A-Z)',
|
||||
ruleNumber: 'حداقل ۱ عدد (0-9)',
|
||||
ruleSpecialChar: 'حداقل ۱ کاراکتر ویژه (!@#$%...)',
|
||||
rulePasswordsMatch: 'رمزهای عبور مطابقت دارند',
|
||||
walletServiceNotReady: 'سرویس کیف پول آماده نیست. لطفاً صبر کنید.',
|
||||
passwordRequirementsNotMet: 'لطفاً تمام الزامات رمز عبور را رعایت کنید',
|
||||
walletCreationFailed: 'ایجاد کیف پول ناموفق بود. لطفاً دوباره تلاش کنید',
|
||||
preparing: 'در حال آمادهسازی...',
|
||||
creating: 'در حال ایجاد...',
|
||||
meetPasswordRequirements: 'الزامات رمز عبور را رعایت کنید',
|
||||
backupTitle: 'پشتیبانگیری از عبارت بازیابی',
|
||||
backupDescription: 'این ۱۲ کلمه کیف پول شما هستند. آنها را در جای امنی بنویسید!',
|
||||
backupWarning:
|
||||
'مهم: این کلمات فقط یک بار نمایش داده میشوند. اگر آنها را گم کنید، نمیتوانید به کیف پول خود دسترسی پیدا کنید.',
|
||||
copiedMnemonic: 'کپی شد!',
|
||||
copyMnemonic: 'کپی',
|
||||
conditionWrittenDown: 'این ۱۲ کلمه را در جای امنی نوشتهام',
|
||||
conditionNeverShare: 'میدانم که هرگز نباید این کلمات را با کسی به اشتراک بگذارم',
|
||||
conditionLossRisk: 'میدانم که اگر این کلمات را گم کنم نمیتوانم به کیف پولم دسترسی پیدا کنم',
|
||||
acceptAllConditions: 'پذیرش تمام شرایط',
|
||||
verifyWords: 'تأیید کلمات',
|
||||
reset: 'بازنشانی',
|
||||
verifyDescription: 'لطفاً کلمات را به ترتیب صحیح مرتب کنید',
|
||||
dropWordsHere: 'کلمات را اینجا قرار دهید...',
|
||||
wrongOrder: 'ترتیب کلمات اشتباه است. لطفاً دوباره تلاش کنید',
|
||||
saving: 'در حال ذخیره...',
|
||||
verify: 'تأیید',
|
||||
wordsCount: '{count}/۱۲ کلمه',
|
||||
walletCreated: 'کیف پول ایجاد شد!',
|
||||
walletReady: 'کیف پول شما آماده است',
|
||||
yourAddress: 'آدرس شما',
|
||||
getStarted: 'شروع کنید',
|
||||
},
|
||||
|
||||
walletImport: {
|
||||
title: 'وارد کردن کیف پول',
|
||||
description: 'عبارت بازیابی کیف پول موجود خود را وارد کنید',
|
||||
seedPhraseLabel: 'عبارت بازیابی (۱۲ یا ۲۴ کلمه)',
|
||||
seedPhrasePlaceholder: 'کلمات خود را با فاصله وارد کنید...',
|
||||
wordsCount: '{count} / ۱۲ کلمه',
|
||||
newPassword: 'رمز عبور جدید',
|
||||
seedPhraseInvalid: 'عبارت بازیابی باید ۱۲ یا ۲۴ کلمه باشد',
|
||||
passwordInvalid: 'رمز عبور نامعتبر است',
|
||||
passwordsMismatch: 'رمزهای عبور مطابقت ندارند',
|
||||
importFailed: 'وارد کردن ناموفق بود',
|
||||
importing: 'در حال وارد کردن...',
|
||||
importButton: 'وارد کردن',
|
||||
},
|
||||
|
||||
walletConnect: {
|
||||
deleteTitle: 'حذف کیف پول؟',
|
||||
deleteDescription:
|
||||
'این عمل قابل بازگشت نیست. اگر عبارت بازیابی خود را ندارید، نمیتوانید به کیف پول خود دسترسی پیدا کنید.',
|
||||
deleteButton: 'حذف',
|
||||
openWallet: 'باز کردن کیف پول',
|
||||
passwordLabel: 'رمز عبور',
|
||||
passwordPlaceholder: 'رمز عبور خود را وارد کنید',
|
||||
enterPassword: 'رمز عبور خود را وارد کنید',
|
||||
wrongPassword: 'رمز عبور اشتباه است',
|
||||
connecting: 'در حال باز کردن...',
|
||||
connect: 'اتصال',
|
||||
deleteWalletLink: 'حذف کیف پول',
|
||||
},
|
||||
|
||||
deposit: {
|
||||
title: 'واریز USDT',
|
||||
subtitle: 'برای wUSDT در Asset Hub',
|
||||
depositHistory: 'تاریخچه واریز',
|
||||
noDeposits: 'هنوز واریزی انجام نشده',
|
||||
goBack: 'بازگشت',
|
||||
selectNetwork: 'انتخاب شبکه',
|
||||
recommended: 'پیشنهادی',
|
||||
warning: 'هشدار!',
|
||||
example: 'مثال: ارسال ۱۰ USDT \u2192 دریافت ۷ wUSDT (کارمزد ۳ دلار)',
|
||||
acceptTrc20: 'قبول میکنم، از طریق TRC20 ارسال کنید',
|
||||
important: 'مهم!',
|
||||
minimum: 'حداقل: {amount} USDT',
|
||||
memoRequired: 'کد خود را در فیلد یادداشت/توضیحات بنویسید',
|
||||
onlyUsdt: 'فقط USDT ارسال کنید، توکنهای دیگر از بین میروند',
|
||||
trc20Fee: 'کارمزد ۳ دلار از مبلغ شما کسر میشود',
|
||||
depositAddress: 'آدرس واریز',
|
||||
notAvailable: 'در دسترس نیست',
|
||||
memoLabel: 'یادداشت / توضیحات (الزامی)',
|
||||
memoWarning: 'این کد را در یادداشت بنویسید، در غیر این صورت واریز شما شناسایی نمیشود!',
|
||||
uniqueAddress: 'این آدرس مختص شماست. نیازی به یادداشت نیست.',
|
||||
howToDeposit: 'چگونه واریز کنم؟',
|
||||
stepCopyAddress: 'آدرس را کپی کنید',
|
||||
stepCopyMemo: 'کد یادداشت را کپی کنید',
|
||||
stepOpenTon: 'کیف پول تلگرام یا کیف پول خود را باز کنید',
|
||||
stepOpenPolkadot: 'کیف پول Polkadot خود را باز کنید',
|
||||
stepOpenTrc20: 'TronLink یا کیف پول خود را باز کنید',
|
||||
stepSendUsdt: 'USDT را به آدرس بالا ارسال کنید',
|
||||
stepReceive: 'wUSDT ظرف چند دقیقه در حساب شما خواهد بود',
|
||||
processingTime: 'زمان پردازش: حدود ۱ تا ۵ دقیقه',
|
||||
copyFailed: 'کپی ناموفق بود',
|
||||
statusPending: 'در انتظار',
|
||||
statusConfirming: 'در حال تأیید',
|
||||
statusCompleted: 'تکمیل شده',
|
||||
statusFailed: 'ناموفق',
|
||||
statusExpired: 'منقضی شده',
|
||||
viewTx: 'مشاهده تراکنش',
|
||||
trc20FeeWarning: 'کارمزد شبکه TRC20 حدود ۳ دلار است. شبکه TON یا Polkadot پیشنهاد میشود.',
|
||||
},
|
||||
|
||||
p2p: {
|
||||
title: 'صرافی P2P',
|
||||
subtitle: 'معامله رمزارز به صورت همتا به همتا',
|
||||
firstTime: 'اولین بار است که از P2P استفاده میکنید؟',
|
||||
steps: [
|
||||
'روی دکمه زیر کلیک کنید تا برنامه وب باز شود',
|
||||
'یک حساب بسازید یا وارد شوید',
|
||||
'فرآیند راهاندازی P2P را تکمیل کنید',
|
||||
'پس از راهاندازی، میتوانید مستقیماً به P2P دسترسی پیدا کنید',
|
||||
],
|
||||
note: 'برنامه وب در پنجره جدیدی باز میشود. فرآیند ثبتنام را در آنجا تکمیل کنید.',
|
||||
button: 'باز کردن پلتفرم P2P',
|
||||
},
|
||||
|
||||
update: {
|
||||
newVersion: 'نسخه جدید موجود است!',
|
||||
description: 'برای ویژگیهای جدید و رفع مشکلات امنیتی بهروزرسانی کنید.',
|
||||
later: 'بعداً',
|
||||
updateNow: 'بهروزرسانی',
|
||||
},
|
||||
|
||||
social: {
|
||||
followUs: 'ما را دنبال کنید',
|
||||
stayConnected: 'در ارتباط باشید و آخرین اخبار را دریافت کنید!',
|
||||
instagram: 'عکسها و استوریها',
|
||||
tiktok: 'ویدیوهای کوتاه',
|
||||
snapchat: 'اسنپ بفرستید!',
|
||||
telegram: 'کانال رسمی',
|
||||
twitter: 'اخبار روزانه',
|
||||
youtube: 'ویدیوهای ما',
|
||||
facebook: 'صفحه رسمی',
|
||||
discord: 'جامعه ما',
|
||||
},
|
||||
|
||||
errorBoundary: {
|
||||
title: 'مشکلی پیش آمد',
|
||||
description: 'متأسفیم، یک خطای فنی رخ داد. لطفاً دوباره تلاش کنید.',
|
||||
retry: 'دوباره تلاش کنید',
|
||||
},
|
||||
|
||||
loadingScreen: {
|
||||
loading: 'در حال بارگذاری...',
|
||||
},
|
||||
};
|
||||
|
||||
export default fa;
|
||||
@@ -0,0 +1,320 @@
|
||||
import type { Translations } from '../types';
|
||||
|
||||
const krd: Translations = {
|
||||
nav: {
|
||||
announcements: 'Ragihandin',
|
||||
forum: 'Forum',
|
||||
rewards: 'Xelat',
|
||||
p2p: 'P2P',
|
||||
wallet: 'Ber\u00eek',
|
||||
},
|
||||
|
||||
common: {
|
||||
back: 'Pa\u015f',
|
||||
cancel: 'Betal',
|
||||
continue: 'Berdewam',
|
||||
close: 'Bigire',
|
||||
copy: 'Kop\u00ee bike',
|
||||
copied: 'Kop\u00ee b\u00fb!',
|
||||
share: 'Parve bike',
|
||||
refresh: 'N\u00fbve bike',
|
||||
retry: 'D\u00eesa bicerb\u00eene',
|
||||
loading: 'T\u00ea barkirin...',
|
||||
error: '\u00c7ewt\u00ee',
|
||||
anonymous: 'Anonymous',
|
||||
pinned: 'Pinned',
|
||||
locked: 'Kil\u00eetk\u00eer\u00ee',
|
||||
trending: 'Trending',
|
||||
},
|
||||
|
||||
announcements: {
|
||||
title: 'Ragihandin',
|
||||
readMore: 'Z\u00eadetir bixw\u00eene',
|
||||
reactionAuthRequired: 'Ji bo dengdan\u00ea div\u00ea tu di Telegram\u00ea de b\u00ee',
|
||||
},
|
||||
|
||||
forum: {
|
||||
title: 'Forum',
|
||||
newTopic: 'Mijara N\u00fb',
|
||||
submitting: 'T\u00ea \u015fandin...',
|
||||
publish: 'Biwe\u015f\u00eene',
|
||||
category: 'Kategor\u00ee',
|
||||
topicTitle: 'Sernav',
|
||||
topicTitlePlaceholder: 'Nav\u00ea mijar\u00ea...',
|
||||
content: 'Naverok',
|
||||
contentPlaceholder: 'Naveroka mijar\u00ea bin\u00eev\u00eese...',
|
||||
tagsLabel: 'Et\u00eeket (bi virgul\u00ea cuda bike)',
|
||||
tagsPlaceholder: 'blockchain, kurd, pez...',
|
||||
searchPlaceholder: 'Mijar bigere...',
|
||||
sortRecent: 'N\u00fb',
|
||||
sortPopular: 'Populer',
|
||||
sortReplies: 'Bersiv',
|
||||
sortViews: 'D\u00eetin',
|
||||
all: 'Hem\u00fb',
|
||||
replies: 'Bersiv',
|
||||
noRepliesYet: 'H\u00eaj bersiv tune ye',
|
||||
beFirstToReply: 'Yekem\u00een bersiv\u00ea tu bide!',
|
||||
replyPlaceholder: 'Bersiva xwe bin\u00eev\u00eese...',
|
||||
noTopicsFound: 'Mijar nehat d\u00eetin',
|
||||
changeFilters: 'Filter\u00ean xwe biguh\u00eare',
|
||||
createNewTopic: 'Mijara N\u00fb Biaf\u00eer\u00eene',
|
||||
loginToVote: 'Ji bo dengdan\u00ea t\u00eakeve',
|
||||
voteError: '\u00c7ewt\u00ee di dengdan\u00ea de',
|
||||
writeReply: 'Ji kerema xwe bersiva xwe bin\u00eev\u00eese',
|
||||
topicLocked: 'Ev mijar kil\u00eetk\u00eer\u00ee ye',
|
||||
replyError: '\u00c7ewt\u00ee di \u015fandina bersiv\u00ea de',
|
||||
fillAllFields: 'Ji kerema xwe hem\u00fb qadan tije bike',
|
||||
topicCreated: 'Mijar hat afirandin!',
|
||||
topicCreateError: '\u00c7ewt\u00ee di afirandina mijar\u00ea de',
|
||||
},
|
||||
|
||||
rewards: {
|
||||
title: 'Xelat',
|
||||
subtitle: 'Xelat - Referral System',
|
||||
connectWalletFirst:
|
||||
'Ji bo d\u00eetina referral \u00fb xelat\u00ean xwe, ber\u00ee her ti\u015ft\u00ee c\u00eezdan\u00ea xwe gir\u00eade.',
|
||||
overview: 'Ge\u015fb\u00een',
|
||||
referral: 'Referral',
|
||||
scores: 'Xal',
|
||||
referralScore: 'P\u00fbana Referral',
|
||||
maxScore: 'Max p\u00fban: 500',
|
||||
referMoreTitle:
|
||||
'\u0632\u06cc\u0627\u062a\u0631 \u0695\u06cc\u0641\u06d5\u0631 \u0628\u06a9\u06d5\u060c \u0632\u06cc\u0627\u062a\u0631 \u0642\u0627\u0632\u0627\u0646\u062c \u0628\u06a9\u06d5!',
|
||||
referMoreDescription:
|
||||
'\u0647\u06d5\u0631 \u06a9\u06d5\u0633\u06ce\u06a9 \u0628\u0647\u06ce\u0646\u06cc\u062a\u060c HEZ \u0648 PEZ \u0648\u06d5\u06a9 \u062e\u06d5\u06b5\u0627\u062a \u0648\u06d5\u0631\u062f\u06d5\u06af\u0631\u06cc\u062a. \u0632\u06cc\u0627\u062a\u0631 \u0695\u06cc\u0641\u06d5\u0631 = \u0632\u06cc\u0627\u062a\u0631 \u062e\u06d5\u06b5\u0627\u062a!',
|
||||
kycApproved: 'KYC pejirand\u00ee',
|
||||
referrer: 'Referrer',
|
||||
none: 'Tune',
|
||||
invitedMe: 'Min vexwand',
|
||||
pendingReferral: 'Referral li bend\u00ea',
|
||||
completeKyc: 'KYC temam bike ji bo pejirandina referral ji',
|
||||
inviteFriends: 'Heval\u00ean xwe vexw\u00eene',
|
||||
yourLink: 'L\u00eenka te',
|
||||
copySuccess: 'Kop\u00ee b\u00fb!',
|
||||
copyLink: 'Kop\u00ee bike',
|
||||
shareLink: 'Parve bike',
|
||||
scoreSystem: 'S\u00eestema p\u00fbanan',
|
||||
activeStatus: 'Rew\u015fa Akt\u00eevb\u00fbn\u00ea',
|
||||
timeRemaining: 'Dem: {time} maye',
|
||||
active: 'Akt\u00eev',
|
||||
inactive: 'Ne Akt\u00eev',
|
||||
activeDescription:
|
||||
'Her 24 saet carek\u00ea bikirt\u00eene da ku akt\u00eev bim\u00een\u00ee \u00fb xelat\u00ean z\u00eadetir qezenc bik\u00ee!',
|
||||
youAreActive: 'Tu Akt\u00eev \u00ee!',
|
||||
iAmActive: 'Ez Akt\u00eev im!',
|
||||
activatedAlert: 'Tu niha akt\u00eev \u00ee! 24 saet pa\u015f\u00ea d\u00eesa bikirt\u00eene.',
|
||||
shareText:
|
||||
'Pezkuwichain - Dewleta D\u00eej\u00eetal a Kurd! Bi l\u00eenka min ve tev li me bibe:',
|
||||
copyAlert: 'Kop\u00ee b\u00fb',
|
||||
referralCount: '{count} referral (KYC pejirand\u00ee)',
|
||||
noReferrals: 'H\u00eaj referral\u00ean te tune ne',
|
||||
shareYourLink: 'L\u00eenka xwe parve bike!',
|
||||
trustScore: 'P\u00fbana P\u00eabaweriy\u00ea (Trust)',
|
||||
rank: 'R\u00eaze: {rating}',
|
||||
citizen: 'Welat\u00ee',
|
||||
staking: 'Staking',
|
||||
stakingNotStarted: 'Nehat\u00eeye destp\u00eakirin',
|
||||
stakingCountedInTrust: 'Di Trust de t\u00ea hesibandin',
|
||||
people: '{count} kes',
|
||||
tiki: 'Tiki',
|
||||
nftRole: 'Rola NFT',
|
||||
education: 'Perwerde',
|
||||
reading: 'Xwendin',
|
||||
stakingRewards: 'Xelat\u00ean Staking',
|
||||
totalRewards: 'Tevah\u00eeya xelat\u00ean wergirt\u00ee',
|
||||
recentRewards: 'Xelat\u00ean daw\u00ee',
|
||||
noRewardsYet: 'H\u00eaj xelatek nehat\u00eeye tomark\u00eerin',
|
||||
scoreFormula: 'Form\u00fbla P\u00fban\u00ea',
|
||||
stakingZeroWarning:
|
||||
'Staking 0 be, Trust p\u00fban j\u00ee 0 dibe. Ber\u00ee her ti\u015ft\u00ee stake bike!',
|
||||
refreshScores: 'P\u00fbanan N\u00fbve Bike',
|
||||
points: 'p\u00fban',
|
||||
},
|
||||
|
||||
wallet: {
|
||||
title: 'Ber\u00eek',
|
||||
authFailed: 'Teketin Tek Cu',
|
||||
authDescription: 'Ji kerema xwe pistrast bikin ku hun ve app-e di nav Telegram de vedikin',
|
||||
retry: 'Disa Biceribine',
|
||||
},
|
||||
|
||||
walletSetup: {
|
||||
officialWallet: 'Ber\u00eeka ferm\u00ee ya Pezkuwichain',
|
||||
createNew: 'Wallet N\u00fb \u00c7\u00eabike',
|
||||
createNewDesc: "Wallet'ek\u00ee n\u00fb bi seed phrase \u00e7\u00eabike",
|
||||
importWallet: 'Wallet Import Bike',
|
||||
importWalletDesc: "Seed phrase'\u00ea xwe y\u00ea hey\u00ee bi kar b\u00eene",
|
||||
securityNote:
|
||||
"Wallet'\u00ea te bi ewleh\u00ee li c\u00eehaza te t\u00ea hilan\u00een. Em tu car\u00ee gih\u00ee\u015ftina mift\u00eey\u00ean te tune.",
|
||||
},
|
||||
|
||||
walletCreate: {
|
||||
setPassword: '\u015e\u00eefre (Password) Diyar Bike',
|
||||
passwordDescription:
|
||||
"Ev \u015f\u00eefre (password) d\u00ea ji bo vekirina wallet'\u00ea were bikar\u00een\u00een",
|
||||
passwordLabel: '\u015e\u00eefre (Password)',
|
||||
passwordPlaceholder: 'Her\u00ee k\u00eam 12 t\u00eep (min 12 characters)',
|
||||
confirmPasswordLabel: '\u015e\u00eefre Dubare (Confirm Password)',
|
||||
confirmPasswordPlaceholder: '\u015e\u00eefre dubare bin\u00eev\u00eese (confirm password)',
|
||||
passwordRequirements: '\u015eert\u00ean \u015e\u00eefre (Password):',
|
||||
ruleMinLength: 'Her\u00ee k\u00eam 12 t\u00eep (min 12 characters)',
|
||||
ruleLowercase: 'Her\u00ee k\u00eam 1 t\u00eepa bi\u00e7\u00fbk (a-z)',
|
||||
ruleUppercase: 'Her\u00ee k\u00eam 1 t\u00eepa mezin (A-Z)',
|
||||
ruleNumber: 'Her\u00ee k\u00eam 1 hejmar (0-9)',
|
||||
ruleSpecialChar: 'Her\u00ee k\u00eam 1 sembola taybet\u00ee (!@#$%...)',
|
||||
rulePasswordsMatch: '\u015e\u00eefre (password) hev digirin',
|
||||
walletServiceNotReady: 'Wallet service amade n\u00eene. Ji kerema xwe bisekinin.',
|
||||
passwordRequirementsNotMet:
|
||||
'Ji kerema xwe hem\u00fb \u015fert\u00ean \u015f\u00eefre (password) bic\u00eeh b\u00eenin',
|
||||
walletCreationFailed:
|
||||
'Wallet \u00e7\u00eaneb\u00fb. Ji kerema xwe d\u00eesa bicerb\u00een\u00een',
|
||||
preparing: 'T\u00ea amadekirin...',
|
||||
creating: 'T\u00ea \u00e7\u00eakirin...',
|
||||
meetPasswordRequirements: '\u015eert\u00ean \u015f\u00eefre (password) bic\u00eeh b\u00eenin',
|
||||
backupTitle: 'Seed Phrase Pa\u015fguh Bike',
|
||||
backupDescription:
|
||||
"Ev 12 peyv wallet'\u00ea te ne. Wan li cihek\u00ee ewle bin\u00eev\u00eese!",
|
||||
backupWarning:
|
||||
"Gir\u00eeng: Ev peyvan ten\u00ea yek car t\u00eane xuyang kirin. Eger te ev peyv winda bikin, tu nikar\u00ee gih\u00ee\u015ftina wallet'\u00ea xwe bist\u00een\u00ee.",
|
||||
copiedMnemonic: 'Hat kop\u00eekirin!',
|
||||
copyMnemonic: 'Kop\u00ee Bike',
|
||||
conditionWrittenDown: 'Min ev 12 peyv li cihek\u00ee ewle niv\u00eesandine',
|
||||
conditionNeverShare: 'Ez f\u00eam dikim ku ez nikarim ev peyvan bi kes\u00ee re parve bikim',
|
||||
conditionLossRisk:
|
||||
"Ez f\u00eam dikim ku eger van peyvan winda bikim ez nikarim gih\u00ee\u015ftina wallet'\u00ea xwe bist\u00eenim",
|
||||
acceptAllConditions: 'Hem\u00fb \u015fertan bipejirinIn',
|
||||
verifyWords: 'Peyvan Verast Bike',
|
||||
reset: 'Reset',
|
||||
verifyDescription: 'Ji kerema xwe peyvan bi r\u00eaza rast bixin nav qut\u00eek\u00ea',
|
||||
dropWordsHere: 'Peyvan li vir bixin...',
|
||||
wrongOrder: 'R\u00eaza peyvan ne rast e. Ji kerema xwe d\u00eesa bicerb\u00een\u00een',
|
||||
saving: 'T\u00ea tomark\u00eerin...',
|
||||
verify: 'Verast Bike',
|
||||
wordsCount: '{count}/12 peyv',
|
||||
walletCreated: 'Wallet Hat \u00c7\u00eakirin!',
|
||||
walletReady: "Wallet'\u00ea te amade ye",
|
||||
yourAddress: 'Navnishana te',
|
||||
getStarted: 'Dest P\u00ea Bike',
|
||||
},
|
||||
|
||||
walletImport: {
|
||||
title: 'Wallet Import Bike',
|
||||
description: "Seed phrase'\u00ea wallet'\u00ea xwe y\u00ea hey\u00ee bin\u00eev\u00eese",
|
||||
seedPhraseLabel: 'Seed Phrase (12 an 24 peyv)',
|
||||
seedPhrasePlaceholder: 'Peyv\u00ean xwe bi valah\u00ee cuda bin\u00eev\u00eese...',
|
||||
wordsCount: '{count} / 12 peyv',
|
||||
newPassword: '\u015e\u00eefreya N\u00fb (New Password)',
|
||||
seedPhraseInvalid: 'Seed phrase div\u00ea 12 an 24 peyv be',
|
||||
passwordInvalid: '\u015e\u00eefre (password) ne derbasdar e',
|
||||
passwordsMismatch: '\u015e\u00eefre (password) hev nagirin',
|
||||
importFailed: 'Import neseret\u00ee',
|
||||
importing: 'T\u00ea import kirin...',
|
||||
importButton: 'Import Bike',
|
||||
},
|
||||
|
||||
walletConnect: {
|
||||
deleteTitle: 'Wallet J\u00ea Bibe?',
|
||||
deleteDescription:
|
||||
"Ev \u00e7alak\u00ee nay\u00ea pa\u015fveki\u015fandin. Eger seed phrase'\u00ea te tune be, tu nikar\u00ee gih\u00ee\u015ftina wallet'\u00ea xwe bist\u00een\u00ee.",
|
||||
deleteButton: 'J\u00ea Bibe',
|
||||
openWallet: 'Wallet Veke',
|
||||
passwordLabel: '\u015e\u00eefre (Password)',
|
||||
passwordPlaceholder: '\u015e\u00eefre (password) bin\u00eev\u00eese',
|
||||
enterPassword: '\u015e\u00eefre (password) bin\u00eev\u00eese',
|
||||
wrongPassword: '\u015e\u00eefre (password) \u00e7ewt e',
|
||||
connecting: 'T\u00ea vekirin...',
|
||||
connect: 'Connect',
|
||||
deleteWalletLink: 'Wallet j\u00ea bibe',
|
||||
},
|
||||
|
||||
deposit: {
|
||||
title: 'USDT Depo Bike',
|
||||
subtitle: 'Bo wUSDT li Asset Hub',
|
||||
depositHistory: 'D\u00eeroka Depoyan',
|
||||
noDeposits: 'H\u00een depo tune',
|
||||
goBack: 'Vegere',
|
||||
selectNetwork: 'Tor\u00ea Hilbij\u00eare',
|
||||
recommended: 'P\u00ea\u015fniyar',
|
||||
warning: 'Dikkkat!',
|
||||
example: 'M\u00eenak: 10 USDT bi\u015f\u00eene \u2192 7 wUSDT werbigire ($3 masraf)',
|
||||
acceptTrc20: 'Qeb\u00fbl dikim, bi TRC20 bi\u015f\u00eene',
|
||||
important: 'Gir\u00eeng!',
|
||||
minimum: 'K\u00eamtir\u00een: {amount} USDT',
|
||||
memoRequired: 'Memo/Comment qada de koda xwe bin\u00eev\u00eese',
|
||||
onlyUsdt: 'Ten\u00ea USDT bi\u015f\u00eene, token\u00ean din winda dibin',
|
||||
trc20Fee: '$3 masraf d\u00ea ji m\u00eeqdara we b\u00ea k\u00eamkirin',
|
||||
depositAddress: 'Navnishana Depoy\u00ea',
|
||||
notAvailable: 'Amade n\u00eene',
|
||||
memoLabel: 'Memo / Comment (P\u00caW\u00ceST)',
|
||||
memoWarning:
|
||||
'V\u00ea kod\u00ea di memo de bin\u00eev\u00eese, wek\u00ee din depoya te nay\u00ea nas kirin!',
|
||||
uniqueAddress: 'Ev navnishana ten\u00ea ya te ye. Memo ne p\u00eaw\u00eest e.',
|
||||
howToDeposit: '\u00c7awa Depo Bikim?',
|
||||
stepCopyAddress: 'Navnishana kop\u00ee bike',
|
||||
stepCopyMemo: 'Memo kod\u00ea kop\u00ee bike',
|
||||
stepOpenTon: 'Telegram Wallet an c\u00eezdana xwe veke',
|
||||
stepOpenPolkadot: 'Polkadot c\u00eezdana xwe veke',
|
||||
stepOpenTrc20: 'TronLink an c\u00eezdana xwe veke',
|
||||
stepSendUsdt: 'USDT bi\u015f\u00eene navnishana jor\u00een',
|
||||
stepReceive: 'wUSDT d\u00ea di nav \u00e7end h\u00fbrdeman de li hesab\u00ea te be',
|
||||
processingTime: 'Dema p\u00eavajoy\u00ea: ~1-5 h\u00fbrdem',
|
||||
copyFailed: 'Kop\u00ee nekir',
|
||||
statusPending: 'Li benda',
|
||||
statusConfirming: 'T\u00ea pejirandin',
|
||||
statusCompleted: 'Qediya',
|
||||
statusFailed: 'Neseret\u00ee',
|
||||
statusExpired: 'Dema w\u00ea derbas b\u00fb',
|
||||
viewTx: 'TX bib\u00eene',
|
||||
trc20FeeWarning:
|
||||
'Mesrefa tora TRC20 bi qas\u00ee $3 ye. Em tora TON an Polkadot p\u00ea\u015fniyar dikin.',
|
||||
},
|
||||
|
||||
p2p: {
|
||||
title: 'P2P Dan\u00fbstandin',
|
||||
subtitle: 'Dan\u00fbstandina kr\u00eeto di navbera kesan de',
|
||||
firstTime: 'Cara yekem P2P bikar t\u00eenin?',
|
||||
steps: [
|
||||
'Li bi\u015fkoja j\u00ear\u00een bikirt\u00eenin da ku malpera web\u00ea vebike',
|
||||
'Hesabek \u00e7\u00eabikin an t\u00eakevin',
|
||||
'P\u00eav ajoya sazkirina P2P temam bikin',
|
||||
'Pi\u015ft\u00ee sazkirin\u00ea, h\u00fbn dikarin rasterast bigih\u00eejin P2P',
|
||||
],
|
||||
note: 'Malpera web\u00ea di pencereyek n\u00fb de vedibe. P\u00eav ajoya qeydk\u00eerin\u00ea li wir temam bikin.',
|
||||
button: 'P2P Veke',
|
||||
},
|
||||
|
||||
update: {
|
||||
newVersion: 'Guhertoya n\u00fb heye!',
|
||||
description:
|
||||
'Ji bo taybetmend\u00eey\u00ean n\u00fb \u00fb rastkirin\u00ean ewlehiy\u00ea n\u00fbve bike.',
|
||||
later: 'Pa\u015f\u00ea',
|
||||
updateNow: 'N\u00fbve bike',
|
||||
},
|
||||
|
||||
social: {
|
||||
followUs: 'Me bi\u015fop\u00eene',
|
||||
stayConnected:
|
||||
'Bi me re t\u00eak\u00eel\u00eey\u00ea ragire \u00fb n\u00fb\u00e7ey\u00ean her\u00ee daw\u00ee bist\u00eene!',
|
||||
instagram: 'W\u00eane \u00fb Story',
|
||||
tiktok: 'V\u00eedyoy\u00ean kurt',
|
||||
snapchat: 'Snap bike!',
|
||||
telegram: 'Kanala ferm\u00ee',
|
||||
twitter: 'N\u00fb\u00e7ey\u00ean rojane',
|
||||
youtube: 'V\u00eedyoy\u00ean me',
|
||||
facebook: 'R\u00fbpela ferm\u00ee',
|
||||
discord: 'Civaka me',
|
||||
},
|
||||
|
||||
errorBoundary: {
|
||||
title: 'Ti\u015ftek \u00e7ewt \u00e7\u00eab\u00fb',
|
||||
description:
|
||||
'Bibore, pirsgir\u00eakek tekn\u00eek\u00ee derket. Ji kerema xwe d\u00eesa bicerb\u00eene.',
|
||||
retry: 'D\u00eesa bicerb\u00eene',
|
||||
},
|
||||
|
||||
loadingScreen: {
|
||||
loading: 'T\u00ea barkirin...',
|
||||
},
|
||||
};
|
||||
|
||||
export default krd;
|
||||
@@ -0,0 +1,305 @@
|
||||
import type { Translations } from '../types';
|
||||
|
||||
const tr: Translations = {
|
||||
nav: {
|
||||
announcements: 'Haberler',
|
||||
forum: 'Forum',
|
||||
rewards: 'Ödüller',
|
||||
p2p: 'P2P',
|
||||
wallet: 'Cüzdan',
|
||||
},
|
||||
|
||||
common: {
|
||||
back: 'Geri',
|
||||
cancel: 'İptal',
|
||||
continue: 'Devam',
|
||||
close: 'Kapat',
|
||||
copy: 'Kopyala',
|
||||
copied: 'Kopyalandı!',
|
||||
share: 'Paylaş',
|
||||
refresh: 'Yenile',
|
||||
retry: 'Tekrar dene',
|
||||
loading: 'Yükleniyor...',
|
||||
error: 'Hata',
|
||||
anonymous: 'Anonim',
|
||||
pinned: 'Sabitlenmiş',
|
||||
locked: 'Kilitli',
|
||||
trending: 'Trend',
|
||||
},
|
||||
|
||||
announcements: {
|
||||
title: 'Duyurular',
|
||||
readMore: 'Devamını oku',
|
||||
reactionAuthRequired: "Oy vermek için Telegram'da olmalısınız",
|
||||
},
|
||||
|
||||
forum: {
|
||||
title: 'Forum',
|
||||
newTopic: 'Yeni Konu',
|
||||
submitting: 'Gönderiliyor...',
|
||||
publish: 'Yayınla',
|
||||
category: 'Kategori',
|
||||
topicTitle: 'Başlık',
|
||||
topicTitlePlaceholder: 'Konu başlığı...',
|
||||
content: 'İçerik',
|
||||
contentPlaceholder: 'Konu içeriğini yazın...',
|
||||
tagsLabel: 'Etiketler (virgülle ayırın)',
|
||||
tagsPlaceholder: 'blockchain, kurd, pez...',
|
||||
searchPlaceholder: 'Konu ara...',
|
||||
sortRecent: 'Yeni',
|
||||
sortPopular: 'Popüler',
|
||||
sortReplies: 'Yanıtlar',
|
||||
sortViews: 'Görüntüleme',
|
||||
all: 'Tümü',
|
||||
replies: 'Yanıtlar',
|
||||
noRepliesYet: 'Henüz yanıt yok',
|
||||
beFirstToReply: 'İlk yanıtı siz verin!',
|
||||
replyPlaceholder: 'Yanıtınızı yazın...',
|
||||
noTopicsFound: 'Konu bulunamadı',
|
||||
changeFilters: 'Filtrelerinizi değiştirin',
|
||||
createNewTopic: 'Yeni Konu Oluştur',
|
||||
loginToVote: 'Oy vermek için giriş yapın',
|
||||
voteError: 'Oy verme hatası',
|
||||
writeReply: 'Lütfen yanıtınızı yazın',
|
||||
topicLocked: 'Bu konu kilitli',
|
||||
replyError: 'Yanıt gönderme hatası',
|
||||
fillAllFields: 'Lütfen tüm alanları doldurun',
|
||||
topicCreated: 'Konu oluşturuldu!',
|
||||
topicCreateError: 'Konu oluşturma hatası',
|
||||
},
|
||||
|
||||
rewards: {
|
||||
title: 'Ödüller',
|
||||
subtitle: 'Ödüller - Davet Sistemi',
|
||||
connectWalletFirst: 'Davetlerinizi ve ödüllerinizi görmek için önce cüzdanınızı bağlayın.',
|
||||
overview: 'Genel Bakış',
|
||||
referral: 'Davet',
|
||||
scores: 'Puanlar',
|
||||
referralScore: 'Davet Puanı',
|
||||
maxScore: 'Maksimum puan: 500',
|
||||
referMoreTitle: 'Daha çok davet edin, daha çok kazanın!',
|
||||
referMoreDescription:
|
||||
'Getirdiğiniz her kişi için HEZ ve PEZ ödülleri alırsınız. Daha fazla davet = daha fazla ödül!',
|
||||
kycApproved: 'KYC Onaylandı',
|
||||
referrer: 'Davet Eden',
|
||||
none: 'Yok',
|
||||
invitedMe: 'Beni davet etti',
|
||||
pendingReferral: 'Bekleyen davet',
|
||||
completeKyc: "Davetini onaylamak için KYC'yi tamamlayın:",
|
||||
inviteFriends: 'Arkadaşlarınızı davet edin',
|
||||
yourLink: 'Bağlantınız',
|
||||
copySuccess: 'Kopyalandı!',
|
||||
copyLink: 'Kopyala',
|
||||
shareLink: 'Paylaş',
|
||||
scoreSystem: 'Puan sistemi',
|
||||
activeStatus: 'Aktivite Durumu',
|
||||
timeRemaining: 'Süre: {time} kaldı',
|
||||
active: 'Aktif',
|
||||
inactive: 'Pasif',
|
||||
activeDescription: 'Aktif kalmak ve daha fazla ödül kazanmak için her 24 saatte bir tıklayın!',
|
||||
youAreActive: 'Aktifsiniz!',
|
||||
iAmActive: 'Aktifim!',
|
||||
activatedAlert: 'Artık aktifsiniz! 24 saat sonra tekrar tıklayın.',
|
||||
shareText: 'Pezkuwichain - Kürdistan Dijital Devleti! Bağlantımdan bize katılın:',
|
||||
copyAlert: 'Kopyalandı',
|
||||
referralCount: '{count} davet (KYC onaylı)',
|
||||
noReferrals: 'Henüz davetiniz yok',
|
||||
shareYourLink: 'Bağlantınızı paylaşın!',
|
||||
trustScore: 'Güven Puanı',
|
||||
rank: 'Sıralama: {rating}',
|
||||
citizen: 'Vatandaş',
|
||||
staking: 'Staking',
|
||||
stakingNotStarted: 'Başlamadı',
|
||||
stakingCountedInTrust: 'Güven puanına dahil',
|
||||
people: '{count} kişi',
|
||||
tiki: 'Tiki',
|
||||
nftRole: 'NFT Rolü',
|
||||
education: 'Eğitim',
|
||||
reading: 'Okuma',
|
||||
stakingRewards: 'Staking Ödülleri',
|
||||
totalRewards: 'Toplam alınan ödüller',
|
||||
recentRewards: 'Son ödüller',
|
||||
noRewardsYet: 'Henüz kaydedilmiş ödül yok',
|
||||
scoreFormula: 'Puan Formülü',
|
||||
stakingZeroWarning: 'Staking 0 ise Güven puanı da 0 olur. Önce stake yapın!',
|
||||
refreshScores: 'Puanları Yenile',
|
||||
points: 'puan',
|
||||
},
|
||||
|
||||
wallet: {
|
||||
title: 'Cüzdan',
|
||||
authFailed: 'Kimlik Doğrulama Başarısız',
|
||||
authDescription: 'Lütfen bu uygulamayı Telegram içinden açtığınızdan emin olun',
|
||||
retry: 'Tekrar Dene',
|
||||
},
|
||||
|
||||
walletSetup: {
|
||||
officialWallet: 'Resmi Pezkuwichain cüzdanı',
|
||||
createNew: 'Yeni Cüzdan Oluştur',
|
||||
createNewDesc: 'Kurtarma kelimeleriyle yeni bir cüzdan oluşturun',
|
||||
importWallet: 'Cüzdan İçe Aktar',
|
||||
importWalletDesc: 'Mevcut kurtarma kelimelerinizi kullanın',
|
||||
securityNote:
|
||||
'Cüzdanınız cihazınızda güvenli bir şekilde saklanır. Anahtarlarınıza asla erişimimiz yoktur.',
|
||||
},
|
||||
|
||||
walletCreate: {
|
||||
setPassword: 'Şifre Belirle',
|
||||
passwordDescription: 'Bu şifre cüzdanınızın kilidini açmak için kullanılacaktır',
|
||||
passwordLabel: 'Şifre',
|
||||
passwordPlaceholder: 'En az 12 karakter',
|
||||
confirmPasswordLabel: 'Şifreyi Onayla',
|
||||
confirmPasswordPlaceholder: 'Şifrenizi tekrar girin',
|
||||
passwordRequirements: 'Şifre Gereksinimleri:',
|
||||
ruleMinLength: 'En az 12 karakter',
|
||||
ruleLowercase: 'En az 1 küçük harf (a-z)',
|
||||
ruleUppercase: 'En az 1 büyük harf (A-Z)',
|
||||
ruleNumber: 'En az 1 rakam (0-9)',
|
||||
ruleSpecialChar: 'En az 1 özel karakter (!@#$%...)',
|
||||
rulePasswordsMatch: 'Şifreler eşleşiyor',
|
||||
walletServiceNotReady: 'Cüzdan hizmeti hazır değil. Lütfen bekleyin.',
|
||||
passwordRequirementsNotMet: 'Lütfen tüm şifre gereksinimlerini karşılayın',
|
||||
walletCreationFailed: 'Cüzdan oluşturma başarısız. Lütfen tekrar deneyin',
|
||||
preparing: 'Hazırlanıyor...',
|
||||
creating: 'Oluşturuluyor...',
|
||||
meetPasswordRequirements: 'Şifre gereksinimlerini karşılayın',
|
||||
backupTitle: 'Kurtarma Kelimelerini Yedekle',
|
||||
backupDescription: 'Bu 12 kelime cüzdanınızdır. Güvenli bir yere yazın!',
|
||||
backupWarning:
|
||||
'Önemli: Bu kelimeler yalnızca bir kez gösterilir. Kaybederseniz cüzdanınıza erişemezsiniz.',
|
||||
copiedMnemonic: 'Kopyalandı!',
|
||||
copyMnemonic: 'Kopyala',
|
||||
conditionWrittenDown: 'Bu 12 kelimeyi güvenli bir yere yazdım',
|
||||
conditionNeverShare: 'Bu kelimeleri asla kimseyle paylaşmamam gerektiğini anlıyorum',
|
||||
conditionLossRisk: 'Bu kelimeleri kaybedersem cüzdanıma erişemeyeceğimi anlıyorum',
|
||||
acceptAllConditions: 'Tüm koşulları kabul et',
|
||||
verifyWords: 'Kelimeleri Doğrula',
|
||||
reset: 'Sıfırla',
|
||||
verifyDescription: 'Lütfen kelimeleri doğru sıraya dizin',
|
||||
dropWordsHere: 'Kelimeleri buraya yerleştirin...',
|
||||
wrongOrder: 'Yanlış kelime sırası. Lütfen tekrar deneyin',
|
||||
saving: 'Kaydediliyor...',
|
||||
verify: 'Doğrula',
|
||||
wordsCount: '{count}/12 kelime',
|
||||
walletCreated: 'Cüzdan Oluşturuldu!',
|
||||
walletReady: 'Cüzdanınız hazır',
|
||||
yourAddress: 'Adresiniz',
|
||||
getStarted: 'Başlayın',
|
||||
},
|
||||
|
||||
walletImport: {
|
||||
title: 'Cüzdan İçe Aktar',
|
||||
description: 'Mevcut cüzdanınızın kurtarma kelimelerini girin',
|
||||
seedPhraseLabel: 'Kurtarma Kelimeleri (12 veya 24 kelime)',
|
||||
seedPhrasePlaceholder: 'Kelimeleri boşlukla ayırarak girin...',
|
||||
wordsCount: '{count} / 12 kelime',
|
||||
newPassword: 'Yeni Şifre',
|
||||
seedPhraseInvalid: 'Kurtarma kelimeleri 12 veya 24 kelime olmalıdır',
|
||||
passwordInvalid: 'Şifre geçersiz',
|
||||
passwordsMismatch: 'Şifreler eşleşmiyor',
|
||||
importFailed: 'İçe aktarma başarısız',
|
||||
importing: 'İçe aktarılıyor...',
|
||||
importButton: 'İçe Aktar',
|
||||
},
|
||||
|
||||
walletConnect: {
|
||||
deleteTitle: 'Cüzdan Silinsin mi?',
|
||||
deleteDescription:
|
||||
'Bu işlem geri alınamaz. Kurtarma kelimeleriniz yoksa cüzdanınıza erişemezsiniz.',
|
||||
deleteButton: 'Sil',
|
||||
openWallet: 'Cüzdanı Aç',
|
||||
passwordLabel: 'Şifre',
|
||||
passwordPlaceholder: 'Şifrenizi girin',
|
||||
enterPassword: 'Şifrenizi girin',
|
||||
wrongPassword: 'Yanlış şifre',
|
||||
connecting: 'Açılıyor...',
|
||||
connect: 'Bağlan',
|
||||
deleteWalletLink: 'Cüzdanı sil',
|
||||
},
|
||||
|
||||
deposit: {
|
||||
title: 'USDT Yatır',
|
||||
subtitle: 'Asset Hub üzerinde wUSDT için',
|
||||
depositHistory: 'Yatırma Geçmişi',
|
||||
noDeposits: 'Henüz yatırma yok',
|
||||
goBack: 'Geri dön',
|
||||
selectNetwork: 'Ağ Seçin',
|
||||
recommended: 'Önerilen',
|
||||
warning: 'Uyarı!',
|
||||
example: 'Örnek: 10 USDT gönderin \u2192 7 wUSDT alın (3$ komisyon)',
|
||||
acceptTrc20: 'Kabul ediyorum, TRC20 ile gönder',
|
||||
important: 'Önemli!',
|
||||
minimum: 'Minimum: {amount} USDT',
|
||||
memoRequired: 'Memo/Açıklama alanına kodunuzu yazın',
|
||||
onlyUsdt: 'Yalnızca USDT gönderin, diğer tokenlar kaybolur',
|
||||
trc20Fee: 'Tutarınızdan 3$ komisyon düşülecektir',
|
||||
depositAddress: 'Yatırma Adresi',
|
||||
notAvailable: 'Mevcut değil',
|
||||
memoLabel: 'Memo / Açıklama (ZORUNLU)',
|
||||
memoWarning: 'Bu kodu memo alanına yazın, aksi takdirde yatırmanız tanınmaz!',
|
||||
uniqueAddress: 'Bu adres size özeldir. Memo gerekmez.',
|
||||
howToDeposit: 'Nasıl Yatırılır?',
|
||||
stepCopyAddress: 'Adresi kopyalayın',
|
||||
stepCopyMemo: 'Memo kodunu kopyalayın',
|
||||
stepOpenTon: 'Telegram Cüzdanı veya cüzdanınızı açın',
|
||||
stepOpenPolkadot: 'Polkadot cüzdanınızı açın',
|
||||
stepOpenTrc20: 'TronLink veya cüzdanınızı açın',
|
||||
stepSendUsdt: 'Yukarıdaki adrese USDT gönderin',
|
||||
stepReceive: 'wUSDT birkaç dakika içinde hesabınızda olacak',
|
||||
processingTime: 'İşlem süresi: ~1-5 dakika',
|
||||
copyFailed: 'Kopyalama başarısız',
|
||||
statusPending: 'Beklemede',
|
||||
statusConfirming: 'Onaylanıyor',
|
||||
statusCompleted: 'Tamamlandı',
|
||||
statusFailed: 'Başarısız',
|
||||
statusExpired: 'Süresi Doldu',
|
||||
viewTx: 'TX Görüntüle',
|
||||
trc20FeeWarning: "TRC20 ağ komisyonu yaklaşık 3$'dır. TON veya Polkadot ağını öneririz.",
|
||||
},
|
||||
|
||||
p2p: {
|
||||
title: 'P2P Borsa',
|
||||
subtitle: 'Eşler arası kripto ticareti',
|
||||
firstTime: "P2P'yi ilk kez mi kullanıyorsunuz?",
|
||||
steps: [
|
||||
'Web uygulamasını açmak için aşağıdaki düğmeye tıklayın',
|
||||
'Hesap oluşturun veya giriş yapın',
|
||||
'P2P kurulum sürecini tamamlayın',
|
||||
"Kurulumdan sonra P2P'ye doğrudan erişebilirsiniz",
|
||||
],
|
||||
note: 'Web uygulaması yeni bir pencerede açılacak. Kayıt işlemini orada tamamlayın.',
|
||||
button: 'P2P Platformunu Aç',
|
||||
},
|
||||
|
||||
update: {
|
||||
newVersion: 'Yeni sürüm mevcut!',
|
||||
description: 'Yeni özellikler ve güvenlik düzeltmeleri için güncelleyin.',
|
||||
later: 'Sonra',
|
||||
updateNow: 'Güncelle',
|
||||
},
|
||||
|
||||
social: {
|
||||
followUs: 'Bizi takip edin',
|
||||
stayConnected: 'Bağlantıda kalın ve en son haberleri alın!',
|
||||
instagram: 'Fotoğraflar ve Hikayeler',
|
||||
tiktok: 'Kısa videolar',
|
||||
snapchat: 'Snap gönderin!',
|
||||
telegram: 'Resmi kanal',
|
||||
twitter: 'Günlük haberler',
|
||||
youtube: 'Videolarımız',
|
||||
facebook: 'Resmi sayfa',
|
||||
discord: 'Topluluğumuz',
|
||||
},
|
||||
|
||||
errorBoundary: {
|
||||
title: 'Bir şeyler yanlış gitti',
|
||||
description: 'Üzgünüz, teknik bir hata oluştu. Lütfen tekrar deneyin.',
|
||||
retry: 'Tekrar dene',
|
||||
},
|
||||
|
||||
loadingScreen: {
|
||||
loading: 'Yükleniyor...',
|
||||
},
|
||||
};
|
||||
|
||||
export default tr;
|
||||
@@ -0,0 +1,323 @@
|
||||
export interface Translations {
|
||||
// Navigation
|
||||
nav: {
|
||||
announcements: string;
|
||||
forum: string;
|
||||
rewards: string;
|
||||
p2p: string;
|
||||
wallet: string;
|
||||
};
|
||||
|
||||
// Common
|
||||
common: {
|
||||
back: string;
|
||||
cancel: string;
|
||||
continue: string;
|
||||
close: string;
|
||||
copy: string;
|
||||
copied: string;
|
||||
share: string;
|
||||
refresh: string;
|
||||
retry: string;
|
||||
loading: string;
|
||||
error: string;
|
||||
anonymous: string;
|
||||
pinned: string;
|
||||
locked: string;
|
||||
trending: string;
|
||||
};
|
||||
|
||||
// Announcements section
|
||||
announcements: {
|
||||
title: string;
|
||||
readMore: string;
|
||||
reactionAuthRequired: string;
|
||||
};
|
||||
|
||||
// Forum section
|
||||
forum: {
|
||||
title: string;
|
||||
newTopic: string;
|
||||
submitting: string;
|
||||
publish: string;
|
||||
category: string;
|
||||
topicTitle: string;
|
||||
topicTitlePlaceholder: string;
|
||||
content: string;
|
||||
contentPlaceholder: string;
|
||||
tagsLabel: string;
|
||||
tagsPlaceholder: string;
|
||||
searchPlaceholder: string;
|
||||
sortRecent: string;
|
||||
sortPopular: string;
|
||||
sortReplies: string;
|
||||
sortViews: string;
|
||||
all: string;
|
||||
replies: string;
|
||||
noRepliesYet: string;
|
||||
beFirstToReply: string;
|
||||
replyPlaceholder: string;
|
||||
noTopicsFound: string;
|
||||
changeFilters: string;
|
||||
createNewTopic: string;
|
||||
loginToVote: string;
|
||||
voteError: string;
|
||||
writeReply: string;
|
||||
topicLocked: string;
|
||||
replyError: string;
|
||||
fillAllFields: string;
|
||||
topicCreated: string;
|
||||
topicCreateError: string;
|
||||
};
|
||||
|
||||
// Rewards section
|
||||
rewards: {
|
||||
title: string;
|
||||
subtitle: string;
|
||||
connectWalletFirst: string;
|
||||
overview: string;
|
||||
referral: string;
|
||||
scores: string;
|
||||
referralScore: string;
|
||||
maxScore: string;
|
||||
referMoreTitle: string;
|
||||
referMoreDescription: string;
|
||||
kycApproved: string;
|
||||
referrer: string;
|
||||
none: string;
|
||||
invitedMe: string;
|
||||
pendingReferral: string;
|
||||
completeKyc: string;
|
||||
inviteFriends: string;
|
||||
yourLink: string;
|
||||
copySuccess: string;
|
||||
copyLink: string;
|
||||
shareLink: string;
|
||||
scoreSystem: string;
|
||||
activeStatus: string;
|
||||
timeRemaining: string;
|
||||
active: string;
|
||||
inactive: string;
|
||||
activeDescription: string;
|
||||
youAreActive: string;
|
||||
iAmActive: string;
|
||||
activatedAlert: string;
|
||||
shareText: string;
|
||||
copyAlert: string;
|
||||
referralCount: string;
|
||||
noReferrals: string;
|
||||
shareYourLink: string;
|
||||
trustScore: string;
|
||||
rank: string;
|
||||
citizen: string;
|
||||
staking: string;
|
||||
stakingNotStarted: string;
|
||||
stakingCountedInTrust: string;
|
||||
people: string;
|
||||
tiki: string;
|
||||
nftRole: string;
|
||||
education: string;
|
||||
reading: string;
|
||||
stakingRewards: string;
|
||||
totalRewards: string;
|
||||
recentRewards: string;
|
||||
noRewardsYet: string;
|
||||
scoreFormula: string;
|
||||
stakingZeroWarning: string;
|
||||
refreshScores: string;
|
||||
points: string;
|
||||
};
|
||||
|
||||
// Wallet section
|
||||
wallet: {
|
||||
title: string;
|
||||
authFailed: string;
|
||||
authDescription: string;
|
||||
retry: string;
|
||||
};
|
||||
|
||||
// Wallet Setup
|
||||
walletSetup: {
|
||||
officialWallet: string;
|
||||
createNew: string;
|
||||
createNewDesc: string;
|
||||
importWallet: string;
|
||||
importWalletDesc: string;
|
||||
securityNote: string;
|
||||
};
|
||||
|
||||
// Wallet Create
|
||||
walletCreate: {
|
||||
setPassword: string;
|
||||
passwordDescription: string;
|
||||
passwordLabel: string;
|
||||
passwordPlaceholder: string;
|
||||
confirmPasswordLabel: string;
|
||||
confirmPasswordPlaceholder: string;
|
||||
passwordRequirements: string;
|
||||
ruleMinLength: string;
|
||||
ruleLowercase: string;
|
||||
ruleUppercase: string;
|
||||
ruleNumber: string;
|
||||
ruleSpecialChar: string;
|
||||
rulePasswordsMatch: string;
|
||||
walletServiceNotReady: string;
|
||||
passwordRequirementsNotMet: string;
|
||||
walletCreationFailed: string;
|
||||
preparing: string;
|
||||
creating: string;
|
||||
meetPasswordRequirements: string;
|
||||
backupTitle: string;
|
||||
backupDescription: string;
|
||||
backupWarning: string;
|
||||
copiedMnemonic: string;
|
||||
copyMnemonic: string;
|
||||
conditionWrittenDown: string;
|
||||
conditionNeverShare: string;
|
||||
conditionLossRisk: string;
|
||||
acceptAllConditions: string;
|
||||
verifyWords: string;
|
||||
reset: string;
|
||||
verifyDescription: string;
|
||||
dropWordsHere: string;
|
||||
wrongOrder: string;
|
||||
saving: string;
|
||||
verify: string;
|
||||
wordsCount: string;
|
||||
walletCreated: string;
|
||||
walletReady: string;
|
||||
yourAddress: string;
|
||||
getStarted: string;
|
||||
};
|
||||
|
||||
// Wallet Import
|
||||
walletImport: {
|
||||
title: string;
|
||||
description: string;
|
||||
seedPhraseLabel: string;
|
||||
seedPhrasePlaceholder: string;
|
||||
wordsCount: string;
|
||||
newPassword: string;
|
||||
seedPhraseInvalid: string;
|
||||
passwordInvalid: string;
|
||||
passwordsMismatch: string;
|
||||
importFailed: string;
|
||||
importing: string;
|
||||
importButton: string;
|
||||
};
|
||||
|
||||
// Wallet Connect
|
||||
walletConnect: {
|
||||
deleteTitle: string;
|
||||
deleteDescription: string;
|
||||
deleteButton: string;
|
||||
openWallet: string;
|
||||
passwordLabel: string;
|
||||
passwordPlaceholder: string;
|
||||
enterPassword: string;
|
||||
wrongPassword: string;
|
||||
connecting: string;
|
||||
connect: string;
|
||||
deleteWalletLink: string;
|
||||
};
|
||||
|
||||
// Deposit USDT Modal
|
||||
deposit: {
|
||||
title: string;
|
||||
subtitle: string;
|
||||
depositHistory: string;
|
||||
noDeposits: string;
|
||||
goBack: string;
|
||||
selectNetwork: string;
|
||||
recommended: string;
|
||||
warning: string;
|
||||
example: string;
|
||||
acceptTrc20: string;
|
||||
important: string;
|
||||
minimum: string;
|
||||
memoRequired: string;
|
||||
onlyUsdt: string;
|
||||
trc20Fee: string;
|
||||
depositAddress: string;
|
||||
notAvailable: string;
|
||||
memoLabel: string;
|
||||
memoWarning: string;
|
||||
uniqueAddress: string;
|
||||
howToDeposit: string;
|
||||
stepCopyAddress: string;
|
||||
stepCopyMemo: string;
|
||||
stepOpenTon: string;
|
||||
stepOpenPolkadot: string;
|
||||
stepOpenTrc20: string;
|
||||
stepSendUsdt: string;
|
||||
stepReceive: string;
|
||||
processingTime: string;
|
||||
copyFailed: string;
|
||||
statusPending: string;
|
||||
statusConfirming: string;
|
||||
statusCompleted: string;
|
||||
statusFailed: string;
|
||||
statusExpired: string;
|
||||
viewTx: string;
|
||||
trc20FeeWarning: string;
|
||||
};
|
||||
|
||||
// P2P Modal
|
||||
p2p: {
|
||||
title: string;
|
||||
subtitle: string;
|
||||
firstTime: string;
|
||||
steps: string[];
|
||||
note: string;
|
||||
button: string;
|
||||
};
|
||||
|
||||
// Update Notification
|
||||
update: {
|
||||
newVersion: string;
|
||||
description: string;
|
||||
later: string;
|
||||
updateNow: string;
|
||||
};
|
||||
|
||||
// Social Links
|
||||
social: {
|
||||
followUs: string;
|
||||
stayConnected: string;
|
||||
instagram: string;
|
||||
tiktok: string;
|
||||
snapchat: string;
|
||||
telegram: string;
|
||||
twitter: string;
|
||||
youtube: string;
|
||||
facebook: string;
|
||||
discord: string;
|
||||
};
|
||||
|
||||
// Error Boundary
|
||||
errorBoundary: {
|
||||
title: string;
|
||||
description: string;
|
||||
retry: string;
|
||||
};
|
||||
|
||||
// Loading Screen
|
||||
loadingScreen: {
|
||||
loading: string;
|
||||
};
|
||||
}
|
||||
|
||||
export type LanguageCode = 'krd' | 'en' | 'tr' | 'ckb' | 'fa' | 'ar';
|
||||
|
||||
export const VALID_LANGS: LanguageCode[] = ['krd', 'en', 'tr', 'ckb', 'fa', 'ar'];
|
||||
export const DEFAULT_LANG: LanguageCode = 'krd';
|
||||
export const RTL_LANGUAGES: LanguageCode[] = ['ckb', 'fa', 'ar'];
|
||||
|
||||
export const LANGUAGE_NAMES: Record<LanguageCode, string> = {
|
||||
krd: 'Kurmancî',
|
||||
en: 'English',
|
||||
tr: 'Türkçe',
|
||||
ckb: 'سۆرانی',
|
||||
fa: 'فارسی',
|
||||
ar: 'العربية',
|
||||
};
|
||||
+12
-9
@@ -5,6 +5,7 @@ import { AuthProvider } from './contexts/AuthContext';
|
||||
import { WalletProvider } from './contexts/WalletContext';
|
||||
import { ReferralProvider } from './contexts/ReferralContext';
|
||||
import { ErrorBoundary } from './components/ErrorBoundary';
|
||||
import { LanguageProvider } from './i18n';
|
||||
import App from './App';
|
||||
import './index.css';
|
||||
|
||||
@@ -42,15 +43,17 @@ if (!rootElement) {
|
||||
createRoot(rootElement).render(
|
||||
<StrictMode>
|
||||
<ErrorBoundary>
|
||||
<QueryClientProvider client={queryClient}>
|
||||
<AuthProvider>
|
||||
<WalletProvider>
|
||||
<ReferralProvider>
|
||||
<App />
|
||||
</ReferralProvider>
|
||||
</WalletProvider>
|
||||
</AuthProvider>
|
||||
</QueryClientProvider>
|
||||
<LanguageProvider>
|
||||
<QueryClientProvider client={queryClient}>
|
||||
<AuthProvider>
|
||||
<WalletProvider>
|
||||
<ReferralProvider>
|
||||
<App />
|
||||
</ReferralProvider>
|
||||
</WalletProvider>
|
||||
</AuthProvider>
|
||||
</QueryClientProvider>
|
||||
</LanguageProvider>
|
||||
</ErrorBoundary>
|
||||
</StrictMode>
|
||||
);
|
||||
|
||||
@@ -10,17 +10,19 @@ import {
|
||||
import { cn, formatDate, formatNumber } from '@/lib/utils';
|
||||
import { useTelegram } from '@/hooks/useTelegram';
|
||||
import { useAnnouncements, useAnnouncementReaction } from '@/hooks/useSupabase';
|
||||
import { useTranslation } from '@/i18n';
|
||||
|
||||
export function AnnouncementsSection() {
|
||||
const { hapticImpact, hapticNotification, openLink } = useTelegram();
|
||||
const { data: announcements, isLoading, refetch, isRefetching } = useAnnouncements();
|
||||
const reactionMutation = useAnnouncementReaction();
|
||||
const { t } = useTranslation();
|
||||
|
||||
const handleReaction = (id: string, reaction: 'like' | 'dislike') => {
|
||||
if (!window.Telegram?.WebApp?.initData) {
|
||||
hapticNotification('error');
|
||||
if (window.Telegram?.WebApp) {
|
||||
window.Telegram.WebApp.showAlert('Ji bo dengdanê divê tu di Telegramê de bî');
|
||||
window.Telegram.WebApp.showAlert(t('announcements.reactionAuthRequired'));
|
||||
}
|
||||
return;
|
||||
}
|
||||
@@ -31,7 +33,7 @@ export function AnnouncementsSection() {
|
||||
onSuccess: () => hapticNotification('success'),
|
||||
onError: (err) => {
|
||||
hapticNotification('error');
|
||||
window.Telegram?.WebApp?.showAlert(err.message || 'Çewtî');
|
||||
window.Telegram?.WebApp?.showAlert(err.message || t('common.error'));
|
||||
},
|
||||
}
|
||||
);
|
||||
@@ -51,7 +53,7 @@ export function AnnouncementsSection() {
|
||||
<div className="w-8 h-8 rounded-lg bg-primary/20 flex items-center justify-center">
|
||||
<Megaphone className="w-4 h-4 text-primary" />
|
||||
</div>
|
||||
<h1 className="text-lg font-semibold">Ragihandin</h1>
|
||||
<h1 className="text-lg font-semibold">{t('announcements.title')}</h1>
|
||||
</div>
|
||||
<button
|
||||
onClick={handleRefresh}
|
||||
@@ -113,7 +115,7 @@ export function AnnouncementsSection() {
|
||||
className="flex items-center gap-1.5 text-sm text-primary mb-3 hover:underline"
|
||||
>
|
||||
<ExternalLink className="w-3.5 h-3.5" />
|
||||
Zêdetir bixwîne
|
||||
{t('announcements.readMore')}
|
||||
</button>
|
||||
)}
|
||||
|
||||
|
||||
+47
-41
@@ -31,12 +31,14 @@ import { useTelegram } from '@/hooks/useTelegram';
|
||||
import { useAuth } from '@/contexts/AuthContext';
|
||||
import { useForum, type ForumDiscussion, type ForumReply } from '@/hooks/useForum';
|
||||
import { formatDistanceToNow } from 'date-fns';
|
||||
import { useTranslation } from '@/i18n';
|
||||
|
||||
type SortBy = 'recent' | 'popular' | 'replies' | 'views';
|
||||
|
||||
export function ForumSection() {
|
||||
const { hapticImpact, hapticNotification, showAlert } = useTelegram();
|
||||
const { user: authUser } = useAuth();
|
||||
const { t } = useTranslation();
|
||||
// Use authenticated user ID from backend, not initDataUnsafe
|
||||
const userId = authUser?.telegram_id?.toString() || '';
|
||||
const userName = authUser?.first_name || 'Telegram User';
|
||||
@@ -116,7 +118,7 @@ export function ForumSection() {
|
||||
|
||||
const handleVoteDiscussion = async (voteType: 'upvote' | 'downvote') => {
|
||||
if (!selectedDiscussion || !userId) {
|
||||
showAlert('Ji bo dengdanê têkeve');
|
||||
showAlert(t('forum.loginToVote'));
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -132,13 +134,13 @@ export function ForumSection() {
|
||||
}
|
||||
} catch {
|
||||
hapticNotification('error');
|
||||
showAlert('Çewtî di dengdanê de');
|
||||
showAlert(t('forum.voteError'));
|
||||
}
|
||||
};
|
||||
|
||||
const handleVoteReply = async (replyId: string, voteType: 'upvote' | 'downvote') => {
|
||||
if (!userId) {
|
||||
showAlert('Ji bo dengdanê têkeve');
|
||||
showAlert(t('forum.loginToVote'));
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -159,12 +161,12 @@ export function ForumSection() {
|
||||
|
||||
const handleSubmitReply = async () => {
|
||||
if (!selectedDiscussion || !replyText.trim() || !userId) {
|
||||
showAlert('Ji kerema xwe bersiva xwe binivîse');
|
||||
showAlert(t('forum.writeReply'));
|
||||
return;
|
||||
}
|
||||
|
||||
if (selectedDiscussion.is_locked) {
|
||||
showAlert('Ev mijar kilîtkirî ye');
|
||||
showAlert(t('forum.topicLocked'));
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -187,7 +189,7 @@ export function ForumSection() {
|
||||
setReplies(loadedReplies);
|
||||
} catch {
|
||||
hapticNotification('error');
|
||||
showAlert('Çewtî di şandina bersivê de');
|
||||
showAlert(t('forum.replyError'));
|
||||
} finally {
|
||||
setSubmittingReply(false);
|
||||
}
|
||||
@@ -195,7 +197,7 @@ export function ForumSection() {
|
||||
|
||||
const handleSubmitDiscussion = async () => {
|
||||
if (!newTitle.trim() || !newContent.trim() || !newCategory || !userId) {
|
||||
showAlert('Ji kerema xwe hemû qadan tije bike');
|
||||
showAlert(t('forum.fillAllFields'));
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -205,8 +207,8 @@ export function ForumSection() {
|
||||
try {
|
||||
const tags = newTags
|
||||
.split(',')
|
||||
.map((t) => t.trim())
|
||||
.filter((t) => t.length > 0);
|
||||
.map((tag) => tag.trim())
|
||||
.filter((tag) => tag.length > 0);
|
||||
|
||||
await createDiscussion({
|
||||
title: newTitle.trim(),
|
||||
@@ -218,11 +220,11 @@ export function ForumSection() {
|
||||
});
|
||||
|
||||
hapticNotification('success');
|
||||
showAlert('Mijar hat afirandin!');
|
||||
showAlert(t('forum.topicCreated'));
|
||||
handleCloseCreate();
|
||||
} catch {
|
||||
hapticNotification('error');
|
||||
showAlert('Çewtî di afirandina mijarê de');
|
||||
showAlert(t('forum.topicCreateError'));
|
||||
} finally {
|
||||
setSubmittingDiscussion(false);
|
||||
}
|
||||
@@ -291,7 +293,7 @@ export function ForumSection() {
|
||||
>
|
||||
<X className="w-5 h-5" />
|
||||
</button>
|
||||
<h1 className="text-lg font-semibold">Mijara Nû</h1>
|
||||
<h1 className="text-lg font-semibold">{t('forum.newTopic')}</h1>
|
||||
</div>
|
||||
<button
|
||||
onClick={handleSubmitDiscussion}
|
||||
@@ -303,7 +305,7 @@ export function ForumSection() {
|
||||
: 'bg-primary text-primary-foreground'
|
||||
)}
|
||||
>
|
||||
{submittingDiscussion ? 'Tê şandin...' : 'Biweşîne'}
|
||||
{submittingDiscussion ? t('forum.submitting') : t('forum.publish')}
|
||||
</button>
|
||||
</div>
|
||||
</header>
|
||||
@@ -311,7 +313,9 @@ export function ForumSection() {
|
||||
<div className="flex-1 overflow-y-auto hide-scrollbar p-4 space-y-4">
|
||||
{/* Category */}
|
||||
<div>
|
||||
<label className="text-sm text-muted-foreground mb-2 block">Kategorî</label>
|
||||
<label className="text-sm text-muted-foreground mb-2 block">
|
||||
{t('forum.category')}
|
||||
</label>
|
||||
<div className="flex gap-2 flex-wrap">
|
||||
{categories.map((cat) => (
|
||||
<button
|
||||
@@ -336,12 +340,14 @@ export function ForumSection() {
|
||||
|
||||
{/* Title */}
|
||||
<div>
|
||||
<label className="text-sm text-muted-foreground mb-2 block">Sernav</label>
|
||||
<label className="text-sm text-muted-foreground mb-2 block">
|
||||
{t('forum.topicTitle')}
|
||||
</label>
|
||||
<input
|
||||
type="text"
|
||||
value={newTitle}
|
||||
onChange={(e) => setNewTitle(e.target.value)}
|
||||
placeholder="Navê mijarê..."
|
||||
placeholder={t('forum.topicTitlePlaceholder')}
|
||||
className="w-full px-4 py-3 bg-secondary rounded-lg text-foreground"
|
||||
maxLength={200}
|
||||
/>
|
||||
@@ -349,11 +355,11 @@ export function ForumSection() {
|
||||
|
||||
{/* Content */}
|
||||
<div>
|
||||
<label className="text-sm text-muted-foreground mb-2 block">Naverok</label>
|
||||
<label className="text-sm text-muted-foreground mb-2 block">{t('forum.content')}</label>
|
||||
<textarea
|
||||
value={newContent}
|
||||
onChange={(e) => setNewContent(e.target.value)}
|
||||
placeholder="Naveroka mijarê binivîse..."
|
||||
placeholder={t('forum.contentPlaceholder')}
|
||||
className="w-full px-4 py-3 bg-secondary rounded-lg text-foreground min-h-[200px] resize-none"
|
||||
/>
|
||||
</div>
|
||||
@@ -361,13 +367,13 @@ export function ForumSection() {
|
||||
{/* Tags */}
|
||||
<div>
|
||||
<label className="text-sm text-muted-foreground mb-2 block">
|
||||
Etîket (bi virgulê cuda bike)
|
||||
{t('forum.tagsLabel')}
|
||||
</label>
|
||||
<input
|
||||
type="text"
|
||||
value={newTags}
|
||||
onChange={(e) => setNewTags(e.target.value)}
|
||||
placeholder="blockchain, kurd, pez..."
|
||||
placeholder={t('forum.tagsPlaceholder')}
|
||||
className="w-full px-4 py-3 bg-secondary rounded-lg text-foreground"
|
||||
/>
|
||||
</div>
|
||||
@@ -395,13 +401,13 @@ export function ForumSection() {
|
||||
{selectedDiscussion.is_pinned && (
|
||||
<span className="inline-flex items-center gap-1 text-xs bg-yellow-500/20 text-yellow-400 px-2 py-1 rounded-full">
|
||||
<Pin className="w-3 h-3" />
|
||||
Pinned
|
||||
{t('common.pinned')}
|
||||
</span>
|
||||
)}
|
||||
{selectedDiscussion.is_locked && (
|
||||
<span className="inline-flex items-center gap-1 text-xs bg-red-500/20 text-red-400 px-2 py-1 rounded-full">
|
||||
<Lock className="w-3 h-3" />
|
||||
Kilîtkirî
|
||||
{t('common.locked')}
|
||||
</span>
|
||||
)}
|
||||
{selectedDiscussion.category && (
|
||||
@@ -419,7 +425,7 @@ export function ForumSection() {
|
||||
</div>
|
||||
<div>
|
||||
<p className="text-sm font-medium">
|
||||
{selectedDiscussion.author_name || 'Anonymous'}
|
||||
{selectedDiscussion.author_name || t('common.anonymous')}
|
||||
</p>
|
||||
<p className="text-xs text-muted-foreground">
|
||||
{formatDistanceToNow(new Date(selectedDiscussion.created_at), {
|
||||
@@ -499,7 +505,7 @@ export function ForumSection() {
|
||||
<div className="mb-4">
|
||||
<h3 className="text-sm font-semibold text-muted-foreground mb-3 flex items-center gap-2">
|
||||
<MessageSquare className="w-4 h-4" />
|
||||
Bersiv ({replies.length})
|
||||
{t('forum.replies')} ({replies.length})
|
||||
</h3>
|
||||
|
||||
{loadingReplies ? (
|
||||
@@ -514,8 +520,8 @@ export function ForumSection() {
|
||||
) : replies.length === 0 ? (
|
||||
<div className="text-center py-8 text-muted-foreground">
|
||||
<MessageSquare className="w-8 h-8 mx-auto mb-2 opacity-50" />
|
||||
<p className="text-sm">Hêj bersiv tune ye</p>
|
||||
<p className="text-xs">Yekemîn bersivê tu bide!</p>
|
||||
<p className="text-sm">{t('forum.noRepliesYet')}</p>
|
||||
<p className="text-xs">{t('forum.beFirstToReply')}</p>
|
||||
</div>
|
||||
) : (
|
||||
<div className="space-y-3">
|
||||
@@ -529,7 +535,7 @@ export function ForumSection() {
|
||||
{reply.author_name?.charAt(0) || 'A'}
|
||||
</div>
|
||||
<span className="text-sm font-medium">
|
||||
{reply.author_name || 'Anonymous'}
|
||||
{reply.author_name || t('common.anonymous')}
|
||||
</span>
|
||||
<span className="text-xs text-muted-foreground">
|
||||
{formatDistanceToNow(new Date(reply.created_at), { addSuffix: true })}
|
||||
@@ -579,7 +585,7 @@ export function ForumSection() {
|
||||
type="text"
|
||||
value={replyText}
|
||||
onChange={(e) => setReplyText(e.target.value)}
|
||||
placeholder="Bersiva xwe binivîse..."
|
||||
placeholder={t('forum.replyPlaceholder')}
|
||||
className="flex-1 px-4 py-2.5 bg-secondary rounded-lg text-sm"
|
||||
onKeyDown={(e) => {
|
||||
if (e.key === 'Enter' && !e.shiftKey) {
|
||||
@@ -616,7 +622,7 @@ export function ForumSection() {
|
||||
<div className="w-8 h-8 rounded-lg bg-blue-500/20 flex items-center justify-center">
|
||||
<MessageCircle className="w-4 h-4 text-blue-400" />
|
||||
</div>
|
||||
<h1 className="text-lg font-semibold">Forum</h1>
|
||||
<h1 className="text-lg font-semibold">{t('forum.title')}</h1>
|
||||
<span className="text-xs text-muted-foreground">({discussions.length})</span>
|
||||
</div>
|
||||
<div className="flex items-center gap-1">
|
||||
@@ -648,7 +654,7 @@ export function ForumSection() {
|
||||
type="text"
|
||||
value={searchQuery}
|
||||
onChange={(e) => setSearchQuery(e.target.value)}
|
||||
placeholder="Mijar bigere..."
|
||||
placeholder={t('forum.searchPlaceholder')}
|
||||
className="w-full pl-9 pr-4 py-2 bg-secondary rounded-lg text-sm"
|
||||
/>
|
||||
</div>
|
||||
@@ -656,10 +662,10 @@ export function ForumSection() {
|
||||
{/* Sort Tabs */}
|
||||
<div className="flex gap-1 bg-secondary/50 rounded-lg p-1">
|
||||
{[
|
||||
{ id: 'recent' as SortBy, icon: Clock, label: 'Nû' },
|
||||
{ id: 'popular' as SortBy, icon: TrendingUp, label: 'Populer' },
|
||||
{ id: 'replies' as SortBy, icon: MessageSquare, label: 'Bersiv' },
|
||||
{ id: 'views' as SortBy, icon: Eye, label: 'Dîtin' },
|
||||
{ id: 'recent' as SortBy, icon: Clock, label: t('forum.sortRecent') },
|
||||
{ id: 'popular' as SortBy, icon: TrendingUp, label: t('forum.sortPopular') },
|
||||
{ id: 'replies' as SortBy, icon: MessageSquare, label: t('forum.sortReplies') },
|
||||
{ id: 'views' as SortBy, icon: Eye, label: t('forum.sortViews') },
|
||||
].map(({ id, icon: Icon, label }) => (
|
||||
<button
|
||||
key={id}
|
||||
@@ -718,7 +724,7 @@ export function ForumSection() {
|
||||
: 'bg-secondary text-muted-foreground'
|
||||
)}
|
||||
>
|
||||
Hemû
|
||||
{t('forum.all')}
|
||||
</button>
|
||||
{categories.map((category) => (
|
||||
<button
|
||||
@@ -755,14 +761,14 @@ export function ForumSection() {
|
||||
) : filteredDiscussions.length === 0 ? (
|
||||
<div className="flex flex-col items-center justify-center h-64 p-8 text-center">
|
||||
<MessageCircle className="w-12 h-12 text-muted-foreground/50 mb-4" />
|
||||
<p className="text-muted-foreground">Mijar nehat dîtin</p>
|
||||
<p className="text-sm text-muted-foreground/70 mb-4">Filterên xwe biguhêre</p>
|
||||
<p className="text-muted-foreground">{t('forum.noTopicsFound')}</p>
|
||||
<p className="text-sm text-muted-foreground/70 mb-4">{t('forum.changeFilters')}</p>
|
||||
<button
|
||||
onClick={handleOpenCreate}
|
||||
className="flex items-center gap-2 px-4 py-2 bg-primary text-primary-foreground rounded-lg text-sm"
|
||||
>
|
||||
<Plus className="w-4 h-4" />
|
||||
Mijara Nû Biafirîne
|
||||
{t('forum.createNewTopic')}
|
||||
</button>
|
||||
</div>
|
||||
) : (
|
||||
@@ -778,7 +784,7 @@ export function ForumSection() {
|
||||
{discussion.is_pinned && (
|
||||
<span className="inline-flex items-center gap-1 text-[10px] bg-yellow-500/20 text-yellow-400 px-1.5 py-0.5 rounded">
|
||||
<Pin className="w-2.5 h-2.5" />
|
||||
Pinned
|
||||
{t('common.pinned')}
|
||||
</span>
|
||||
)}
|
||||
{discussion.is_locked && (
|
||||
@@ -794,7 +800,7 @@ export function ForumSection() {
|
||||
{(discussion.upvotes || 0) > 10 && (
|
||||
<span className="inline-flex items-center gap-1 text-[10px] bg-orange-500/20 text-orange-400 px-1.5 py-0.5 rounded">
|
||||
<Flame className="w-2.5 h-2.5" />
|
||||
Trending
|
||||
{t('common.trending')}
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
@@ -817,7 +823,7 @@ export function ForumSection() {
|
||||
|
||||
{/* Meta */}
|
||||
<div className="flex items-center gap-3 text-xs text-muted-foreground flex-wrap">
|
||||
<span>{discussion.author_name || 'Anonymous'}</span>
|
||||
<span>{discussion.author_name || t('common.anonymous')}</span>
|
||||
<span>
|
||||
{formatDistanceToNow(new Date(discussion.last_activity_at), {
|
||||
addSuffix: true,
|
||||
|
||||
+77
-70
@@ -29,6 +29,7 @@ import { useAuth } from '@/contexts/AuthContext';
|
||||
import { useReferral } from '@/contexts/ReferralContext';
|
||||
import { useWallet } from '@/contexts/WalletContext';
|
||||
import { SocialLinks } from '@/components/SocialLinks';
|
||||
import { useTranslation } from '@/i18n';
|
||||
import {
|
||||
getAllScores,
|
||||
getStakingScoreStatus,
|
||||
@@ -54,6 +55,7 @@ export function RewardsSection() {
|
||||
const { user: authUser } = useAuth();
|
||||
const { stats, myReferrals, loading, refreshStats } = useReferral();
|
||||
const { isConnected, address, peopleApi } = useWallet();
|
||||
const { t } = useTranslation();
|
||||
|
||||
const [copied, setCopied] = useState(false);
|
||||
const [activeTab, setActiveTab] = useState<'overview' | 'referrals' | 'scores'>('overview');
|
||||
@@ -136,7 +138,7 @@ export function RewardsSection() {
|
||||
localStorage.setItem(ACTIVITY_STORAGE_KEY, Date.now().toString());
|
||||
setIsActive(true);
|
||||
setTimeRemaining('24s 0d');
|
||||
showAlert('Tu niha aktîv î! 24 saet paşê dîsa bikirtîne.');
|
||||
showAlert(t('rewards.activatedAlert'));
|
||||
};
|
||||
|
||||
// Telegram referral link (for sharing) - use authenticated user ID
|
||||
@@ -151,16 +153,13 @@ export function RewardsSection() {
|
||||
hapticNotification('success');
|
||||
setTimeout(() => setCopied(false), 2000);
|
||||
} catch {
|
||||
showAlert('Kopî bû');
|
||||
showAlert(t('rewards.copyAlert'));
|
||||
}
|
||||
};
|
||||
|
||||
const handleShare = () => {
|
||||
hapticImpact('medium');
|
||||
shareUrl(
|
||||
referralLink,
|
||||
'Pezkuwichain - Dewleta Dîjîtal a Kurd! Bi lînka min ve tev li me bibe:'
|
||||
);
|
||||
shareUrl(referralLink, t('rewards.shareText'));
|
||||
};
|
||||
|
||||
const handleRefresh = () => {
|
||||
@@ -180,10 +179,8 @@ export function RewardsSection() {
|
||||
return (
|
||||
<div className="flex flex-col h-full items-center justify-center p-8 text-center">
|
||||
<Gift className="w-16 h-16 text-purple-400 mb-4" />
|
||||
<h2 className="text-xl font-semibold mb-2">Xelat - Referral System</h2>
|
||||
<p className="text-muted-foreground mb-4">
|
||||
Ji bo dîtina referral û xelatên xwe, berî her tiştî cîzdanê xwe girêde.
|
||||
</p>
|
||||
<h2 className="text-xl font-semibold mb-2">{t('rewards.subtitle')}</h2>
|
||||
<p className="text-muted-foreground mb-4">{t('rewards.connectWalletFirst')}</p>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -197,7 +194,7 @@ export function RewardsSection() {
|
||||
<div className="w-8 h-8 rounded-lg bg-purple-500/20 flex items-center justify-center">
|
||||
<Gift className="w-4 h-4 text-purple-400" />
|
||||
</div>
|
||||
<h1 className="text-lg font-semibold">Xelat</h1>
|
||||
<h1 className="text-lg font-semibold">{t('rewards.title')}</h1>
|
||||
</div>
|
||||
<button
|
||||
onClick={handleRefresh}
|
||||
@@ -213,9 +210,9 @@ export function RewardsSection() {
|
||||
{/* Tabs */}
|
||||
<div className="flex gap-1 bg-secondary/50 rounded-lg p-1">
|
||||
{[
|
||||
{ id: 'overview' as const, label: 'Geşbîn' },
|
||||
{ id: 'referrals' as const, label: 'Referral' },
|
||||
{ id: 'scores' as const, label: 'Xal' },
|
||||
{ id: 'overview' as const, label: t('rewards.overview') },
|
||||
{ id: 'referrals' as const, label: t('rewards.referral') },
|
||||
{ id: 'scores' as const, label: t('rewards.scores') },
|
||||
].map(({ id, label }) => (
|
||||
<button
|
||||
key={id}
|
||||
@@ -255,7 +252,7 @@ export function RewardsSection() {
|
||||
<div className="bg-gradient-to-br from-purple-600 to-pink-600 rounded-2xl p-4 text-white">
|
||||
<div className="flex items-center justify-between mb-4">
|
||||
<div>
|
||||
<p className="text-purple-100 text-sm">Pûana Referral</p>
|
||||
<p className="text-purple-100 text-sm">{t('rewards.referralScore')}</p>
|
||||
<p className="text-4xl font-bold">{stats?.referralScore ?? 0}</p>
|
||||
</div>
|
||||
<div className="w-16 h-16 rounded-full bg-white/20 flex items-center justify-center">
|
||||
@@ -264,7 +261,7 @@ export function RewardsSection() {
|
||||
</div>
|
||||
<div className="flex items-center gap-2 text-sm text-purple-100">
|
||||
<TrendingUp className="w-4 h-4" />
|
||||
<span>Max pûan: 500</span>
|
||||
<span>{t('rewards.maxScore')}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -276,10 +273,10 @@ export function RewardsSection() {
|
||||
</div>
|
||||
<div>
|
||||
<h4 className="font-semibold text-amber-100 mb-1">
|
||||
زیاتر ڕیفەر بکە، زیاتر قازانج بکە!
|
||||
{t('rewards.referMoreTitle')}
|
||||
</h4>
|
||||
<p className="text-sm text-amber-200/80">
|
||||
هەر کەسێک بهێنیت، HEZ و PEZ وەک خەڵات وەردەگریت. زیاتر ڕیفەر = زیاتر خەڵات!
|
||||
{t('rewards.referMoreDescription')}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
@@ -290,27 +287,27 @@ export function RewardsSection() {
|
||||
<div className="bg-secondary/30 rounded-xl p-4 border border-border/50">
|
||||
<div className="flex items-center gap-2 mb-2">
|
||||
<Users className="w-4 h-4 text-green-400" />
|
||||
<span className="text-xs text-muted-foreground">Referral</span>
|
||||
<span className="text-xs text-muted-foreground">{t('rewards.referral')}</span>
|
||||
</div>
|
||||
<p className="text-2xl font-bold text-foreground">
|
||||
{stats?.referralCount ?? 0}
|
||||
</p>
|
||||
<p className="text-xs text-muted-foreground">KYC pejirandî</p>
|
||||
<p className="text-xs text-muted-foreground">{t('rewards.kycApproved')}</p>
|
||||
</div>
|
||||
|
||||
<div className="bg-secondary/30 rounded-xl p-4 border border-border/50">
|
||||
<div className="flex items-center gap-2 mb-2">
|
||||
<Award className="w-4 h-4 text-blue-400" />
|
||||
<span className="text-xs text-muted-foreground">Referrer</span>
|
||||
<span className="text-xs text-muted-foreground">{t('rewards.referrer')}</span>
|
||||
</div>
|
||||
{stats?.whoInvitedMe ? (
|
||||
<p className="text-sm font-mono text-foreground truncate">
|
||||
{formatAddress(stats.whoInvitedMe, 6)}
|
||||
</p>
|
||||
) : (
|
||||
<p className="text-sm text-muted-foreground">Tune</p>
|
||||
<p className="text-sm text-muted-foreground">{t('rewards.none')}</p>
|
||||
)}
|
||||
<p className="text-xs text-muted-foreground">Min vexwand</p>
|
||||
<p className="text-xs text-muted-foreground">{t('rewards.invitedMe')}</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -322,9 +319,11 @@ export function RewardsSection() {
|
||||
<Award className="w-5 h-5 text-blue-400" />
|
||||
</div>
|
||||
<div className="flex-1">
|
||||
<div className="text-white font-semibold">Referral li bendê</div>
|
||||
<div className="text-white font-semibold">
|
||||
{t('rewards.pendingReferral')}
|
||||
</div>
|
||||
<div className="text-sm text-blue-300">
|
||||
KYC temam bike ji bo pejirandina referral ji{' '}
|
||||
{t('rewards.completeKyc')}{' '}
|
||||
<span className="font-mono">
|
||||
{formatAddress(stats.pendingReferral, 6)}
|
||||
</span>
|
||||
@@ -338,11 +337,11 @@ export function RewardsSection() {
|
||||
<div className="bg-secondary/30 rounded-xl p-4 border border-border/50">
|
||||
<h3 className="font-medium text-foreground mb-3 flex items-center gap-2">
|
||||
<Share2 className="w-4 h-4 text-primary" />
|
||||
Hevalên xwe vexwîne
|
||||
{t('rewards.inviteFriends')}
|
||||
</h3>
|
||||
|
||||
<div className="bg-background rounded-lg p-3 mb-3">
|
||||
<p className="text-xs text-muted-foreground mb-1">Lînka te</p>
|
||||
<p className="text-xs text-muted-foreground mb-1">{t('rewards.yourLink')}</p>
|
||||
<code className="text-sm text-foreground break-all">{referralLink}</code>
|
||||
</div>
|
||||
|
||||
@@ -357,14 +356,14 @@ export function RewardsSection() {
|
||||
)}
|
||||
>
|
||||
{copied ? <Check className="w-4 h-4" /> : <Copy className="w-4 h-4" />}
|
||||
{copied ? 'Kopî bû!' : 'Kopî bike'}
|
||||
{copied ? t('rewards.copySuccess') : t('rewards.copyLink')}
|
||||
</button>
|
||||
<button
|
||||
onClick={handleShare}
|
||||
className="flex-1 flex items-center justify-center gap-2 py-2.5 bg-primary rounded-lg text-primary-foreground text-sm font-medium"
|
||||
>
|
||||
<Share2 className="w-4 h-4" />
|
||||
Parve bike
|
||||
{t('rewards.shareLink')}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
@@ -373,7 +372,7 @@ export function RewardsSection() {
|
||||
<div className="bg-secondary/30 rounded-xl p-4 border border-border/50">
|
||||
<h3 className="font-medium text-foreground mb-3 flex items-center gap-2">
|
||||
<Star className="w-4 h-4 text-yellow-400" />
|
||||
Sîstema pûanan
|
||||
{t('rewards.scoreSystem')}
|
||||
</h3>
|
||||
<div className="space-y-2 text-sm">
|
||||
<div className="flex justify-between py-2 border-b border-border/30">
|
||||
@@ -403,9 +402,11 @@ export function RewardsSection() {
|
||||
className={cn('w-5 h-5', isActive ? 'text-green-400' : 'text-gray-400')}
|
||||
/>
|
||||
<div>
|
||||
<h3 className="font-medium text-foreground">Rewşa Aktîvbûnê</h3>
|
||||
<h3 className="font-medium text-foreground">{t('rewards.activeStatus')}</h3>
|
||||
{isActive && timeRemaining && (
|
||||
<p className="text-xs text-green-400">Dem: {timeRemaining} maye</p>
|
||||
<p className="text-xs text-green-400">
|
||||
{t('rewards.timeRemaining', { time: timeRemaining })}
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
@@ -415,11 +416,11 @@ export function RewardsSection() {
|
||||
isActive ? 'bg-green-500/20 text-green-400' : 'bg-red-500/20 text-red-400'
|
||||
)}
|
||||
>
|
||||
{isActive ? 'Aktîv' : 'Ne Aktîv'}
|
||||
{isActive ? t('rewards.active') : t('rewards.inactive')}
|
||||
</div>
|
||||
</div>
|
||||
<p className="text-sm text-muted-foreground mb-3">
|
||||
Her 24 saet carekê bikirtîne da ku aktîv bimînî û xelatên zêdetir qezenc bikî!
|
||||
{t('rewards.activeDescription')}
|
||||
</p>
|
||||
<button
|
||||
onClick={handleActivate}
|
||||
@@ -432,7 +433,7 @@ export function RewardsSection() {
|
||||
)}
|
||||
>
|
||||
<Zap className="w-5 h-5" />
|
||||
{isActive ? 'Tu Aktîv î!' : 'Ez Aktîv im!'}
|
||||
{isActive ? t('rewards.youAreActive') : t('rewards.iAmActive')}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
@@ -454,11 +455,9 @@ export function RewardsSection() {
|
||||
</div>
|
||||
<div>
|
||||
<h4 className="font-semibold text-amber-100 mb-1">
|
||||
زیاتر ڕیفەر بکە، زیاتر قازانج بکە!
|
||||
{t('rewards.referMoreTitle')}
|
||||
</h4>
|
||||
<p className="text-sm text-amber-200/80">
|
||||
هەر کەسێک بهێنیت، HEZ و PEZ وەک خەڵات وەردەگریت. زیاتر ڕیفەر = زیاتر خەڵات!
|
||||
</p>
|
||||
<p className="text-sm text-amber-200/80">{t('rewards.referMoreDescription')}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -469,9 +468,11 @@ export function RewardsSection() {
|
||||
<div className="flex items-center gap-2">
|
||||
<Zap className={cn('w-5 h-5', isActive ? 'text-green-400' : 'text-gray-400')} />
|
||||
<div>
|
||||
<h3 className="font-medium text-foreground">Rewşa Aktîvbûnê</h3>
|
||||
<h3 className="font-medium text-foreground">{t('rewards.activeStatus')}</h3>
|
||||
{isActive && timeRemaining && (
|
||||
<p className="text-xs text-green-400">Dem: {timeRemaining} maye</p>
|
||||
<p className="text-xs text-green-400">
|
||||
{t('rewards.timeRemaining', { time: timeRemaining })}
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
@@ -481,7 +482,7 @@ export function RewardsSection() {
|
||||
isActive ? 'bg-green-500/20 text-green-400' : 'bg-red-500/20 text-red-400'
|
||||
)}
|
||||
>
|
||||
{isActive ? 'Aktîv' : 'Ne Aktîv'}
|
||||
{isActive ? t('rewards.active') : t('rewards.inactive')}
|
||||
</div>
|
||||
</div>
|
||||
<button
|
||||
@@ -495,7 +496,7 @@ export function RewardsSection() {
|
||||
)}
|
||||
>
|
||||
<Zap className="w-5 h-5" />
|
||||
{isActive ? 'Tu Aktîv î!' : 'Ez Aktîv im!'}
|
||||
{isActive ? t('rewards.youAreActive') : t('rewards.iAmActive')}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
@@ -510,7 +511,7 @@ export function RewardsSection() {
|
||||
) : myReferrals.length > 0 ? (
|
||||
<div className="space-y-3">
|
||||
<div className="text-sm text-muted-foreground mb-2">
|
||||
{myReferrals.length} referral (KYC pejirandî)
|
||||
{t('rewards.referralCount', { count: myReferrals.length })}
|
||||
</div>
|
||||
{myReferrals.map((referralAddress, index) => (
|
||||
<div
|
||||
@@ -524,11 +525,11 @@ export function RewardsSection() {
|
||||
<code className="text-sm text-foreground">
|
||||
{formatAddress(referralAddress, 8)}
|
||||
</code>
|
||||
<p className="text-xs text-green-400">KYC Pejirandî</p>
|
||||
<p className="text-xs text-green-400">{t('rewards.kycApproved')}</p>
|
||||
</div>
|
||||
<div className="text-right">
|
||||
<span className="text-green-400 text-sm font-medium">
|
||||
+{getPointsForPosition(index + 1)} pûan
|
||||
+{getPointsForPosition(index + 1)} {t('rewards.points')}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
@@ -537,14 +538,14 @@ export function RewardsSection() {
|
||||
) : (
|
||||
<div className="flex flex-col items-center justify-center py-12 text-center">
|
||||
<Users className="w-12 h-12 text-muted-foreground mb-4" />
|
||||
<p className="text-muted-foreground">Hêj referralên te tune ne</p>
|
||||
<p className="text-sm text-muted-foreground mt-1">Lînka xwe parve bike!</p>
|
||||
<p className="text-muted-foreground">{t('rewards.noReferrals')}</p>
|
||||
<p className="text-sm text-muted-foreground mt-1">{t('rewards.shareYourLink')}</p>
|
||||
<button
|
||||
onClick={handleShare}
|
||||
className="mt-4 flex items-center gap-2 px-4 py-2 bg-primary rounded-lg text-primary-foreground text-sm font-medium"
|
||||
>
|
||||
<Share2 className="w-4 h-4" />
|
||||
Parve bike
|
||||
{t('rewards.shareLink')}
|
||||
</button>
|
||||
</div>
|
||||
)}
|
||||
@@ -571,7 +572,7 @@ export function RewardsSection() {
|
||||
<div>
|
||||
<p className="text-purple-100 text-sm flex items-center gap-2">
|
||||
<Shield className="w-4 h-4" />
|
||||
Pûana Pêbaweriyê (Trust)
|
||||
{t('rewards.trustScore')}
|
||||
</p>
|
||||
<p
|
||||
className={cn(
|
||||
@@ -588,11 +589,11 @@ export function RewardsSection() {
|
||||
</div>
|
||||
<div className="flex items-center justify-between text-sm">
|
||||
<span className="text-purple-100">
|
||||
Rêze: {getScoreRating(userScores?.trustScore || 0)}
|
||||
{t('rewards.rank', { rating: getScoreRating(userScores?.trustScore || 0) })}
|
||||
</span>
|
||||
{userScores?.isCitizen && (
|
||||
<span className="bg-green-500/30 text-green-200 px-2 py-1 rounded-full text-xs">
|
||||
Welatî
|
||||
{t('rewards.citizen')}
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
@@ -604,7 +605,7 @@ export function RewardsSection() {
|
||||
<div className="bg-secondary/30 rounded-xl p-4 border border-border/50">
|
||||
<div className="flex items-center gap-2 mb-2">
|
||||
<Target className="w-4 h-4 text-blue-400" />
|
||||
<span className="text-xs text-muted-foreground">Staking</span>
|
||||
<span className="text-xs text-muted-foreground">{t('rewards.staking')}</span>
|
||||
</div>
|
||||
<p className="text-2xl font-bold text-blue-400">
|
||||
{stakingStatus?.isTracking ? (
|
||||
@@ -613,23 +614,27 @@ export function RewardsSection() {
|
||||
{formatDuration(stakingStatus.durationBlocks)}
|
||||
</span>
|
||||
) : (
|
||||
<span className="text-sm text-muted-foreground">Nehatiye destpêkirin</span>
|
||||
<span className="text-sm text-muted-foreground">
|
||||
{t('rewards.stakingNotStarted')}
|
||||
</span>
|
||||
)}
|
||||
</p>
|
||||
<p className="text-xs text-muted-foreground mt-1">Di Trust de tê hesibandin</p>
|
||||
<p className="text-xs text-muted-foreground mt-1">
|
||||
{t('rewards.stakingCountedInTrust')}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{/* Referral Score */}
|
||||
<div className="bg-secondary/30 rounded-xl p-4 border border-border/50">
|
||||
<div className="flex items-center gap-2 mb-2">
|
||||
<Users className="w-4 h-4 text-green-400" />
|
||||
<span className="text-xs text-muted-foreground">Referral</span>
|
||||
<span className="text-xs text-muted-foreground">{t('rewards.referral')}</span>
|
||||
</div>
|
||||
<p className="text-2xl font-bold text-green-400">
|
||||
{userScores?.referralScore ?? 0}
|
||||
</p>
|
||||
<p className="text-xs text-muted-foreground mt-1">
|
||||
{stats?.referralCount ?? 0} kes
|
||||
{t('rewards.people', { count: stats?.referralCount ?? 0 })}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
@@ -637,24 +642,26 @@ export function RewardsSection() {
|
||||
<div className="bg-secondary/30 rounded-xl p-4 border border-border/50">
|
||||
<div className="flex items-center gap-2 mb-2">
|
||||
<Sparkles className="w-4 h-4 text-yellow-400" />
|
||||
<span className="text-xs text-muted-foreground">Tiki</span>
|
||||
<span className="text-xs text-muted-foreground">{t('rewards.tiki')}</span>
|
||||
</div>
|
||||
<p className="text-2xl font-bold text-yellow-400">
|
||||
{userScores?.tikiScore ?? 0}
|
||||
</p>
|
||||
<p className="text-xs text-muted-foreground mt-1">Rola NFT</p>
|
||||
<p className="text-xs text-muted-foreground mt-1">{t('rewards.nftRole')}</p>
|
||||
</div>
|
||||
|
||||
{/* Perwerde Score */}
|
||||
<div className="bg-secondary/30 rounded-xl p-4 border border-border/50">
|
||||
<div className="flex items-center gap-2 mb-2">
|
||||
<GraduationCap className="w-4 h-4 text-pink-400" />
|
||||
<span className="text-xs text-muted-foreground">Perwerde</span>
|
||||
<span className="text-xs text-muted-foreground">
|
||||
{t('rewards.education')}
|
||||
</span>
|
||||
</div>
|
||||
<p className="text-2xl font-bold text-pink-400">
|
||||
{userScores?.perwerdeScore ?? 0}
|
||||
</p>
|
||||
<p className="text-xs text-muted-foreground mt-1">Xwendin</p>
|
||||
<p className="text-xs text-muted-foreground mt-1">{t('rewards.reading')}</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -662,12 +669,12 @@ export function RewardsSection() {
|
||||
<div className="bg-secondary/30 rounded-xl p-4 border border-border/50">
|
||||
<h3 className="font-medium text-foreground mb-3 flex items-center gap-2">
|
||||
<Coins className="w-4 h-4 text-amber-400" />
|
||||
Xelatên Staking
|
||||
{t('rewards.stakingRewards')}
|
||||
</h3>
|
||||
|
||||
{/* Total Accumulated */}
|
||||
<div className="bg-amber-500/10 rounded-lg p-3 mb-3 border border-amber-500/20">
|
||||
<p className="text-xs text-amber-300 mb-1">Tevahiya xelatên wergirtî</p>
|
||||
<p className="text-xs text-amber-300 mb-1">{t('rewards.totalRewards')}</p>
|
||||
<p className="text-2xl font-bold text-amber-400">
|
||||
{stakingRewards && stakingRewards.totalAccumulatedHez > 0
|
||||
? `${stakingRewards.totalAccumulatedHez.toFixed(4)} HEZ`
|
||||
@@ -678,7 +685,9 @@ export function RewardsSection() {
|
||||
{/* Recent Rewards List */}
|
||||
{stakingRewards && stakingRewards.rewards.length > 0 ? (
|
||||
<div className="space-y-2">
|
||||
<p className="text-xs text-muted-foreground mb-2">Xelatên dawî</p>
|
||||
<p className="text-xs text-muted-foreground mb-2">
|
||||
{t('rewards.recentRewards')}
|
||||
</p>
|
||||
{stakingRewards.rewards.map((reward) => (
|
||||
<div
|
||||
key={reward.id}
|
||||
@@ -709,7 +718,7 @@ export function RewardsSection() {
|
||||
</div>
|
||||
) : (
|
||||
<p className="text-sm text-muted-foreground text-center py-3">
|
||||
Hêj xelatek nehatiye tomarkirin
|
||||
{t('rewards.noRewardsYet')}
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
@@ -718,7 +727,7 @@ export function RewardsSection() {
|
||||
<div className="bg-secondary/30 rounded-xl p-4 border border-border/50">
|
||||
<h3 className="font-medium text-foreground mb-3 flex items-center gap-2">
|
||||
<Star className="w-4 h-4 text-yellow-400" />
|
||||
Formûla Pûanê
|
||||
{t('rewards.scoreFormula')}
|
||||
</h3>
|
||||
<div className="text-sm text-muted-foreground space-y-2">
|
||||
<p>Trust = (Staking × Weighted Sum) / 100</p>
|
||||
@@ -726,9 +735,7 @@ export function RewardsSection() {
|
||||
Weighted Sum = Staking×100 + Referral×300 + Perwerde×300 + Tiki×300
|
||||
</p>
|
||||
<div className="mt-3 p-2 bg-yellow-500/10 rounded-lg border border-yellow-500/20">
|
||||
<p className="text-yellow-300 text-xs">
|
||||
Staking 0 be, Trust pûan jî 0 dibe. Berî her tiştî stake bike!
|
||||
</p>
|
||||
<p className="text-yellow-300 text-xs">{t('rewards.stakingZeroWarning')}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -740,7 +747,7 @@ export function RewardsSection() {
|
||||
className="w-full py-3 bg-primary rounded-lg text-primary-foreground font-medium flex items-center justify-center gap-2"
|
||||
>
|
||||
<RefreshCw className={cn('w-4 h-4', scoresLoading && 'animate-spin')} />
|
||||
Pûanan Nûve Bike
|
||||
{t('rewards.refreshScores')}
|
||||
</button>
|
||||
</>
|
||||
)}
|
||||
|
||||
@@ -16,6 +16,7 @@ import {
|
||||
} from '@/components/wallet';
|
||||
import { LoadingScreen } from '@/components/LoadingScreen';
|
||||
import { VersionInfo } from '@/components/VersionInfo';
|
||||
import { useTranslation } from '@/i18n';
|
||||
|
||||
type Screen = 'loading' | 'auth-error' | 'setup' | 'create' | 'import' | 'connect' | 'dashboard';
|
||||
type UserScreen = 'create' | 'import' | null;
|
||||
@@ -23,6 +24,7 @@ type UserScreen = 'create' | 'import' | null;
|
||||
export function WalletSection() {
|
||||
const { isInitialized, isConnected, hasWallet, deleteWalletData } = useWallet();
|
||||
const { isAuthenticated, isLoading: authLoading, authError, signIn } = useAuth();
|
||||
const { t } = useTranslation();
|
||||
const [userScreen, setUserScreen] = useState<UserScreen>(null);
|
||||
|
||||
// Derive screen from wallet state and user navigation
|
||||
@@ -80,10 +82,8 @@ export function WalletSection() {
|
||||
<AlertTriangle className="w-8 h-8 text-red-400" />
|
||||
</div>
|
||||
<div>
|
||||
<h2 className="text-xl font-semibold mb-2">Teketin Tek Cu</h2>
|
||||
<p className="text-muted-foreground text-sm">
|
||||
Ji kerema xwe pistrast bikin ku hun ve app-e di nav Telegram de vedikin
|
||||
</p>
|
||||
<h2 className="text-xl font-semibold mb-2">{t('wallet.authFailed')}</h2>
|
||||
<p className="text-muted-foreground text-sm">{t('wallet.authDescription')}</p>
|
||||
{authError && (
|
||||
<p className="text-xs text-red-400 mt-2 font-mono break-all px-4">{authError}</p>
|
||||
)}
|
||||
@@ -93,7 +93,7 @@ export function WalletSection() {
|
||||
className="px-6 py-3 bg-primary text-primary-foreground rounded-xl font-semibold flex items-center gap-2 mx-auto"
|
||||
>
|
||||
<RefreshCw className="w-4 h-4" />
|
||||
Disa Biceribine
|
||||
{t('wallet.retry')}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
@@ -132,6 +132,7 @@ export function WalletSection() {
|
||||
|
||||
// Header component
|
||||
function Header() {
|
||||
const { t } = useTranslation();
|
||||
return (
|
||||
<header className="flex-shrink-0 px-4 py-3 border-b border-border bg-background/80 backdrop-blur-sm safe-area-top">
|
||||
<div className="flex items-center justify-between">
|
||||
@@ -139,7 +140,7 @@ function Header() {
|
||||
<div className="w-8 h-8 rounded-lg bg-cyan-500/20 flex items-center justify-center">
|
||||
<Wallet className="w-4 h-4 text-cyan-400" />
|
||||
</div>
|
||||
<h1 className="text-lg font-semibold">Berîk</h1>
|
||||
<h1 className="text-lg font-semibold">{t('wallet.title')}</h1>
|
||||
</div>
|
||||
<VersionInfo />
|
||||
</div>
|
||||
|
||||
+3
-3
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"version": "1.0.185",
|
||||
"buildTime": "2026-02-14T08:02:05.985Z",
|
||||
"buildNumber": 1771056125986
|
||||
"version": "1.0.186",
|
||||
"buildTime": "2026-02-14T08:06:14.928Z",
|
||||
"buildNumber": 1771056374928
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user