feat: simplify account creation flow

This commit is contained in:
codytseng
2025-12-23 21:52:32 +08:00
parent cd7c52eda0
commit a880a92748
35 changed files with 1247 additions and 222 deletions

View File

@@ -1,85 +0,0 @@
import { Button } from '@/components/ui/button'
import { Input } from '@/components/ui/input'
import { Label } from '@/components/ui/label'
import { useNostr } from '@/providers/NostrProvider'
import { Check, Copy, RefreshCcw } from 'lucide-react'
import { generateSecretKey } from 'nostr-tools'
import { nsecEncode } from 'nostr-tools/nip19'
import { useState } from 'react'
import { useTranslation } from 'react-i18next'
export default function GenerateNewAccount({
back,
onLoginSuccess
}: {
back: () => void
onLoginSuccess: () => void
}) {
const { t } = useTranslation()
const { nsecLogin } = useNostr()
const [nsec, setNsec] = useState(generateNsec())
const [copied, setCopied] = useState(false)
const [password, setPassword] = useState('')
const handleLogin = () => {
nsecLogin(nsec, password, true).then(() => onLoginSuccess())
}
return (
<form
className="space-y-4"
onSubmit={(e) => {
e.preventDefault()
handleLogin()
}}
>
<div className="text-orange-400">
{t(
'This is a private key. Do not share it with anyone. Keep it safe and secure. You will not be able to recover it if you lose it.'
)}
</div>
<div className="grid gap-2">
<Label>nsec</Label>
<div className="flex gap-2">
<Input value={nsec} />
<Button type="button" variant="secondary" onClick={() => setNsec(generateNsec())}>
<RefreshCcw />
</Button>
<Button
type="button"
onClick={() => {
navigator.clipboard.writeText(nsec)
setCopied(true)
setTimeout(() => setCopied(false), 2000)
}}
>
{copied ? <Check /> : <Copy />}
</Button>
</div>
</div>
<div className="grid gap-2">
<Label htmlFor="password-input">{t('password')}</Label>
<Input
id="password-input"
type="password"
placeholder={t('optional: encrypt nsec')}
value={password}
onChange={(e) => setPassword(e.target.value)}
/>
</div>
<div className="flex gap-2">
<Button className="w-fit px-8" variant="secondary" type="button" onClick={back}>
{t('Back')}
</Button>
<Button className="flex-1" type="submit">
{t('Login')}
</Button>
</div>
</form>
)
}
function generateNsec() {
const sk = generateSecretKey()
return nsecEncode(sk)
}

View File

@@ -0,0 +1,227 @@
import { Button } from '@/components/ui/button'
import { Checkbox } from '@/components/ui/checkbox'
import { Input } from '@/components/ui/input'
import { Label } from '@/components/ui/label'
import { useNostr } from '@/providers/NostrProvider'
import { Check, Copy, Download, RefreshCcw } from 'lucide-react'
import { generateSecretKey } from 'nostr-tools'
import { nsecEncode } from 'nostr-tools/nip19'
import { useState } from 'react'
import { useTranslation } from 'react-i18next'
import InfoCard from '../InfoCard'
type Step = 'generate' | 'password'
export default function Signup({
back,
onSignupSuccess
}: {
back: () => void
onSignupSuccess: () => void
}) {
const { t } = useTranslation()
const { nsecLogin } = useNostr()
const [step, setStep] = useState<Step>('generate')
const [nsec, setNsec] = useState(generateNsec())
const [checkedSaveKey, setCheckedSaveKey] = useState(false)
const [password, setPassword] = useState('')
const [confirmPassword, setConfirmPassword] = useState('')
const [copied, setCopied] = useState(false)
const handleDownload = () => {
const blob = new Blob([nsec], { type: 'text/plain' })
const url = URL.createObjectURL(blob)
const a = document.createElement('a')
a.href = url
a.download = 'nostr-private-key.txt'
document.body.appendChild(a)
a.click()
document.body.removeChild(a)
URL.revokeObjectURL(url)
}
const handleSignup = async () => {
await nsecLogin(nsec, password || undefined, true)
onSignupSuccess()
}
const passwordsMatch = password === confirmPassword
const canSubmit = !password || passwordsMatch
const renderStepIndicator = () => (
<div className="flex items-center justify-center gap-2">
{(['generate', 'password'] as Step[]).map((s, index) => (
<div key={s} className="flex items-center">
<div
className={`w-8 h-8 rounded-full flex items-center justify-center text-sm font-semibold ${
step === s
? 'bg-primary text-primary-foreground'
: step === 'password' && s === 'generate'
? 'bg-primary/20 text-primary'
: 'bg-muted text-muted-foreground'
}`}
>
{index + 1}
</div>
{index < 1 && <div className="w-12 h-0.5 bg-muted mx-1" />}
</div>
))}
</div>
)
if (step === 'generate') {
return (
<div className="space-y-6">
{renderStepIndicator()}
<div className="text-center">
<h3 className="text-lg font-semibold mb-2">{t('Create Your Nostr Account')}</h3>
<p className="text-sm text-muted-foreground">
{t('Generate your unique private key. This is your digital identity.')}
</p>
</div>
<InfoCard
variant="alert"
title={t('Critical: Save Your Private Key')}
content={t(
'Your private key IS your account. There is no password recovery. If you lose it, you lose your account forever. Please save it in a secure location.'
)}
/>
<div className="space-y-1">
<Label>{t('Your Private Key')}</Label>
<div className="flex gap-2">
<Input
value={nsec}
readOnly
className="font-mono text-sm"
onClick={(e) => e.currentTarget.select()}
/>
<Button
type="button"
variant="secondary"
size="icon"
onClick={() => setNsec(generateNsec())}
title={t('Generate new key')}
>
<RefreshCcw />
</Button>
</div>
</div>
<div className="w-full flex gap-2 items-center">
<Button onClick={handleDownload} className="w-full">
<Download />
{t('Download Backup File')}
</Button>
<Button
onClick={() => {
navigator.clipboard.writeText(nsec)
setCopied(true)
setTimeout(() => setCopied(false), 2000)
}}
variant="secondary"
className="w-full"
>
{copied ? <Check /> : <Copy />}
{copied ? t('Copied to Clipboard') : t('Copy to Clipboard')}
</Button>
</div>
<div className="flex items-center gap-2 ml-2">
<Checkbox
id="acknowledge-checkbox"
checked={checkedSaveKey}
onCheckedChange={(c) => setCheckedSaveKey(!!c)}
/>
<Label htmlFor="acknowledge-checkbox" className="cursor-pointer">
{t('I have safely backed up my private key')}
</Label>
</div>
<div className="flex gap-2">
<Button variant="secondary" onClick={back} className="w-fit px-6">
{t('Back')}
</Button>
<Button onClick={() => setStep('password')} className="flex-1" disabled={!checkedSaveKey}>
{t('Continue')}
</Button>
</div>
</div>
)
}
// step === 'password'
return (
<div className="space-y-6">
{renderStepIndicator()}
<div className="text-center">
<h3 className="text-lg font-semibold mb-2">{t('Secure Your Account')}</h3>
<p className="text-sm text-muted-foreground">
{t('Add an extra layer of protection with a password')}
</p>
</div>
<InfoCard
title={t('Password Protection (Recommended)')}
content={t(
'Add a password to encrypt your private key in this browser. This is optional but strongly recommended for better security.'
)}
/>
<div className="space-y-2">
<div className="space-y-1">
<Label htmlFor="password-input">{t('Password (Optional)')}</Label>
<Input
id="password-input"
type="password"
placeholder={t('Create a password (or skip)')}
value={password}
onChange={(e) => setPassword(e.target.value)}
/>
</div>
{password && (
<div className="space-y-1">
<Label htmlFor="confirm-password-input">{t('Confirm Password')}</Label>
<Input
id="confirm-password-input"
type="password"
placeholder={t('Enter your password again')}
value={confirmPassword}
onChange={(e) => setConfirmPassword(e.target.value)}
/>
{confirmPassword && !passwordsMatch && (
<p className="text-xs text-red-500">{t('Passwords do not match')}</p>
)}
</div>
)}
</div>
<div className="w-full flex gap-2">
<Button
variant="secondary"
onClick={() => {
setStep('generate')
setPassword('')
setConfirmPassword('')
}}
className="w-fit px-6"
>
{t('Back')}
</Button>
<Button onClick={handleSignup} className="flex-1" disabled={!canSubmit}>
{t('Complete Signup')}
</Button>
</div>
</div>
)
}
function generateNsec() {
const sk = generateSecretKey()
return nsecEncode(sk)
}

View File

@@ -2,17 +2,15 @@ import { Button } from '@/components/ui/button'
import { Separator } from '@/components/ui/separator'
import { isDevEnv } from '@/lib/utils'
import { useNostr } from '@/providers/NostrProvider'
import { useTheme } from '@/providers/ThemeProvider'
import { NstartModal } from 'nstart-modal'
import { useState } from 'react'
import { useTranslation } from 'react-i18next'
import AccountList from '../AccountList'
import GenerateNewAccount from './GenerateNewAccount'
import NostrConnectLogin from './NostrConnectionLogin'
import NpubLogin from './NpubLogin'
import PrivateKeyLogin from './PrivateKeyLogin'
import Signup from './Signup'
type TAccountManagerPage = 'nsec' | 'bunker' | 'generate' | 'npub' | null
type TAccountManagerPage = 'nsec' | 'bunker' | 'npub' | 'signup' | null
export default function AccountManager({ close }: { close?: () => void }) {
const [page, setPage] = useState<TAccountManagerPage>(null)
@@ -23,10 +21,10 @@ export default function AccountManager({ close }: { close?: () => void }) {
<PrivateKeyLogin back={() => setPage(null)} onLoginSuccess={() => close?.()} />
) : page === 'bunker' ? (
<NostrConnectLogin back={() => setPage(null)} onLoginSuccess={() => close?.()} />
) : page === 'generate' ? (
<GenerateNewAccount back={() => setPage(null)} onLoginSuccess={() => close?.()} />
) : page === 'npub' ? (
<NpubLogin back={() => setPage(null)} onLoginSuccess={() => close?.()} />
) : page === 'signup' ? (
<Signup back={() => setPage(null)} onSignupSuccess={() => close?.()} />
) : (
<AccountManagerNav setPage={setPage} close={close} />
)}
@@ -41,9 +39,8 @@ function AccountManagerNav({
setPage: (page: TAccountManagerPage) => void
close?: () => void
}) {
const { t, i18n } = useTranslation()
const { themeSetting } = useTheme()
const { nip07Login, bunkerLogin, nsecLogin, ncryptsecLogin, accounts } = useNostr()
const { t } = useTranslation()
const { nip07Login, accounts } = useNostr()
return (
<div onClick={(e) => e.stopPropagation()} className="flex flex-col gap-8">
@@ -75,38 +72,8 @@ function AccountManagerNav({
<div className="text-center text-muted-foreground text-sm font-semibold">
{t("Don't have an account yet?")}
</div>
<Button
onClick={() => {
const wizard = new NstartModal({
baseUrl: 'https://nstart.me',
an: 'Jumble',
am: themeSetting === 'pure-black' ? 'dark' : themeSetting,
al: i18n.language.slice(0, 2),
onComplete: ({ nostrLogin }) => {
if (!nostrLogin) return
if (nostrLogin.startsWith('bunker://')) {
bunkerLogin(nostrLogin)
} else if (nostrLogin.startsWith('ncryptsec')) {
ncryptsecLogin(nostrLogin)
} else if (nostrLogin.startsWith('nsec')) {
nsecLogin(nostrLogin)
}
}
})
close?.()
wizard.open()
}}
className="w-full mt-4"
>
{t('Sign up')}
</Button>
<Button
variant="link"
onClick={() => setPage('generate')}
className="w-full text-muted-foreground py-0 h-fit mt-1"
>
{t('or simply generate a private key')}
<Button onClick={() => setPage('signup')} className="w-full mt-4">
{t('Create New Account')}
</Button>
</div>
{accounts.length > 0 && (

View File

@@ -1,13 +0,0 @@
import { TriangleAlert } from 'lucide-react'
export default function AlertCard({ title, content }: { title: string; content: string }) {
return (
<div className="p-3 rounded-lg text-sm bg-amber-100/20 dark:bg-amber-950/20 border border-amber-500 text-amber-500 [&_svg]:size-4">
<div className="flex items-center gap-2">
<TriangleAlert />
<div className="font-medium">{title}</div>
</div>
<div className="pl-6">{content}</div>
</div>
)
}

View File

@@ -60,39 +60,41 @@ export default function FollowButton({ pubkey }: { pubkey: string }) {
}
return isFollowing ? (
<AlertDialog>
<AlertDialogTrigger asChild>
<Button
className="rounded-full min-w-28"
variant={hover ? 'destructive' : 'secondary'}
disabled={updating}
onMouseEnter={() => setHover(true)}
onMouseLeave={() => setHover(false)}
>
{updating ? (
<Loader className="animate-spin" />
) : hover ? (
t('Unfollow')
) : (
t('buttonFollowing')
)}
</Button>
</AlertDialogTrigger>
<AlertDialogContent>
<AlertDialogHeader>
<AlertDialogTitle>{t('Unfollow')}?</AlertDialogTitle>
<AlertDialogDescription>
{t('Are you sure you want to unfollow this user?')}
</AlertDialogDescription>
</AlertDialogHeader>
<AlertDialogFooter>
<AlertDialogCancel>{t('Cancel')}</AlertDialogCancel>
<AlertDialogAction onClick={handleUnfollow} variant="destructive">
{t('Unfollow')}
</AlertDialogAction>
</AlertDialogFooter>
</AlertDialogContent>
</AlertDialog>
<div onClick={(e) => e.stopPropagation()}>
<AlertDialog>
<AlertDialogTrigger asChild>
<Button
className="rounded-full min-w-28"
variant={hover ? 'destructive' : 'secondary'}
disabled={updating}
onMouseEnter={() => setHover(true)}
onMouseLeave={() => setHover(false)}
>
{updating ? (
<Loader className="animate-spin" />
) : hover ? (
t('Unfollow')
) : (
t('buttonFollowing')
)}
</Button>
</AlertDialogTrigger>
<AlertDialogContent>
<AlertDialogHeader>
<AlertDialogTitle>{t('Unfollow')}?</AlertDialogTitle>
<AlertDialogDescription>
{t('Are you sure you want to unfollow this user?')}
</AlertDialogDescription>
</AlertDialogHeader>
<AlertDialogFooter>
<AlertDialogCancel>{t('Cancel')}</AlertDialogCancel>
<AlertDialogAction onClick={handleUnfollow} variant="destructive">
{t('Unfollow')}
</AlertDialogAction>
</AlertDialogFooter>
</AlertDialogContent>
</AlertDialog>
</div>
) : (
<Button className="rounded-full min-w-28" onClick={handleFollow} disabled={updating}>
{updating ? <Loader className="animate-spin" /> : t('Follow')}

View File

@@ -0,0 +1,36 @@
import { cn } from '@/lib/utils'
import { CheckCircle2, Info, TriangleAlert } from 'lucide-react'
const ICON_MAP = {
info: <Info />,
success: <CheckCircle2 />,
alert: <TriangleAlert />
}
const VARIANT_STYLES = {
info: 'bg-blue-100/20 dark:bg-blue-950/20 border border-blue-500 text-blue-500',
success: 'bg-green-100/20 dark:bg-green-950/20 border border-green-500 text-green-500',
alert: 'bg-amber-100/20 dark:bg-amber-950/20 border border-amber-500 text-amber-500'
}
export default function InfoCard({
title,
content,
icon,
variant = 'info'
}: {
title: string
content?: string
icon?: React.ReactNode
variant?: 'info' | 'success' | 'alert'
}) {
return (
<div className={cn('p-3 rounded-lg text-sm [&_svg]:size-4', VARIANT_STYLES[variant])}>
<div className="flex items-center gap-2">
{icon ?? ICON_MAP[variant]}
<div className="font-medium">{title}</div>
</div>
{content && <div className="pl-6">{content}</div>}
</div>
)
}

View File

@@ -1,7 +1,7 @@
import { TMailboxRelay } from '@/types'
import { useMemo } from 'react'
import { useTranslation } from 'react-i18next'
import AlertCard from '../AlertCard'
import InfoCard from '../InfoCard'
export default function RelayCountWarning({ relays }: { relays: TMailboxRelay[] }) {
const { t } = useTranslation()
@@ -19,7 +19,8 @@ export default function RelayCountWarning({ relays }: { relays: TMailboxRelay[]
}
return (
<AlertCard
<InfoCard
variant="alert"
title={showReadWarning ? t('Too many read relays') : t('Too many write relays')}
content={
showReadWarning

View File

@@ -15,13 +15,15 @@ export default function NormalFeed({
areAlgoRelays = false,
isMainFeed = false,
showRelayCloseReason = false,
disable24hMode = false
disable24hMode = false,
onRefresh
}: {
subRequests: TFeedSubRequest[]
areAlgoRelays?: boolean
isMainFeed?: boolean
showRelayCloseReason?: boolean
disable24hMode?: boolean
onRefresh?: () => void
}) {
const { hideUntrustedNotes } = useUserTrust()
const { showKinds } = useKindFilter()
@@ -65,6 +67,10 @@ export default function NormalFeed({
{!supportTouch && (
<RefreshButton
onClick={() => {
if (onRefresh) {
onRefresh()
return
}
if (listMode === '24h') {
userAggregationListRef.current?.refresh()
} else {

View File

@@ -8,7 +8,7 @@ import dayjs from 'dayjs'
import { Eraser, X } from 'lucide-react'
import { Dispatch, SetStateAction, useEffect, useState } from 'react'
import { useTranslation } from 'react-i18next'
import AlertCard from '../AlertCard'
import InfoCard from '../InfoCard'
export default function PollEditor({
pollCreateData,
@@ -125,7 +125,8 @@ export default function PollEditor({
</div>
<div className="grid gap-2">
<AlertCard
<InfoCard
variant="alert"
title={t('This is a poll note.')}
content={t(
'Unlike regular notes, polls are not widely supported and may not display on other clients.'

View File

@@ -34,7 +34,7 @@ export default function TooManyRelaysAlertDialog() {
const dismissed = storage.getDismissedTooManyRelaysAlert()
if (dismissed) return
if (relayList && (relayList.read.length > 4 || relayList.write.length > 4)) {
if (relayList && (relayList.read.length > 5 || relayList.write.length > 5)) {
setOpen(true)
} else {
setOpen(false)

View File

@@ -25,7 +25,7 @@ const buttonVariants = cva(
default: 'h-9 px-4 py-2',
sm: 'h-8 rounded-md px-3 text-xs',
lg: 'h-10 rounded-lg px-8',
icon: 'h-9 w-9',
icon: 'h-9 w-9 shrink-0',
'titlebar-icon': 'h-10 w-10 shrink-0 rounded-xl [&_svg]:size-5'
}
},

View File

@@ -1,4 +1,5 @@
import { kinds } from 'nostr-tools'
import { TMailboxRelay } from './types'
export const JUMBLE_API_BASE_URL = 'https://api.jumble.social'
@@ -71,6 +72,13 @@ export const SEARCHABLE_RELAY_URLS = ['wss://relay.nostr.band/', 'wss://search.n
export const TRENDING_NOTES_RELAY_URLS = ['wss://trending.relays.land/']
export const NEW_USER_RELAY_LIST: TMailboxRelay[] = [
{ url: 'wss://nos.lol/', scope: 'both' },
{ url: 'wss://offchain.pub/', scope: 'both' },
{ url: 'wss://relay.damus.io/', scope: 'both' },
{ url: 'wss://nostr.mom/', scope: 'both' }
]
export const GROUP_METADATA_EVENT_KIND = 39000
export const ExtendedKind = {

View File

@@ -589,6 +589,50 @@ export default {
'Write your thoughts about this highlight...': 'اكتب أفكارك حول هذا التمييز...',
'Publish Highlight': 'نشر التمييز',
'Show replies': 'إظهار الردود',
'Hide replies': 'إخفاء الردود'
'Hide replies': 'إخفاء الردود',
'Welcome to Jumble!': 'مرحبًا بك في Jumble!',
'Your feed is empty because you are not following anyone yet. Start by exploring interesting content and following users you like!':
'خلاصتك فارغة لأنك لا تتابع أي شخص بعد. ابدأ باستكشاف محتوى مثير للاهتمام ومتابعة المستخدمين الذين تحبهم!',
'Search Users': 'البحث عن المستخدمين',
'Create New Account': 'إنشاء حساب جديد',
Important: 'مهم',
'Generate Your Account': 'إنشاء حسابك',
'Your private key IS your account. Keep it safe!': 'مفتاحك الخاص هو حسابك. احتفظ به بأمان!',
'In Nostr, your private key IS your account. If you lose your private key, you lose your account forever.':
'في Nostr، مفتاحك الخاص هو حسابك. إذا فقدت مفتاحك الخاص، ستفقد حسابك إلى الأبد.',
'Your Private Key': 'مفتاحك الخاص',
'Generate new key': 'إنشاء مفتاح جديد',
'Download Backup File': 'تنزيل ملف النسخ الاحتياطي',
'Copied to Clipboard': 'تم النسخ إلى الحافظة',
'Copy to Clipboard': 'نسخ إلى الحافظة',
'I already saved my private key securely.': 'لقد حفظت مفتاحي الخاص بشكل آمن بالفعل.',
'Almost Done!': 'على وشك الانتهاء!',
'Set a password to encrypt your key, or skip to finish':
'قم بتعيين كلمة مرور لتشفير مفتاحك، أو تخطى للانتهاء',
'Password Protection (Optional)': 'الحماية بكلمة مرور (اختياري)',
'Setting a password encrypts your private key in this browser. You can skip this step, but we recommend setting one for added security.':
'يؤدي تعيين كلمة مرور إلى تشفير مفتاحك الخاص في هذا المتصفح. يمكنك تخطي هذه الخطوة، لكننا نوصي بتعيين واحدة لمزيد من الأمان.',
'Password (Optional)': 'كلمة المرور (اختياري)',
'Enter password or leave empty to skip': 'أدخل كلمة المرور أو اتركها فارغة للتخطي',
'Confirm Password': 'تأكيد كلمة المرور',
'Re-enter password': 'أعد إدخال كلمة المرور',
'Passwords do not match': 'كلمات المرور غير متطابقة',
'Finish Signup': 'إنهاء التسجيل',
// New improved signup copy
'Create Your Nostr Account': 'أنشئ حساب Nostr الخاص بك',
'Generate your unique private key. This is your digital identity.':
'أنشئ مفتاحك الخاص الفريد. هذه هي هويتك الرقمية.',
'Critical: Save Your Private Key': 'حرج: احفظ مفتاحك الخاص',
'Your private key IS your account. There is no password recovery. If you lose it, you lose your account forever. Please save it in a secure location.':
'مفتاحك الخاص هو حسابك. لا يوجد استرداد لكلمة المرور. إذا فقدته، ستفقد حسابك للأبد. يرجى حفظه في مكان آمن.',
'I have safely backed up my private key': 'لقد قمت بعمل نسخة احتياطية آمنة لمفتاحي الخاص',
'Secure Your Account': 'أمّن حسابك',
'Add an extra layer of protection with a password': 'أضف طبقة إضافية من الحماية بكلمة مرور',
'Password Protection (Recommended)': 'الحماية بكلمة مرور (موصى به)',
'Add a password to encrypt your private key in this browser. This is optional but strongly recommended for better security.':
'أضف كلمة مرور لتشفير مفتاحك الخاص في هذا المتصفح. هذا اختياري لكنه موصى به بشدة لأمان أفضل.',
'Create a password (or skip)': 'أنشئ كلمة مرور (أو تخطى)',
'Enter your password again': 'أدخل كلمة المرور مرة أخرى',
'Complete Signup': 'إكمال التسجيل'
}
}

View File

@@ -606,6 +606,54 @@ export default {
'Schreiben Sie Ihre Gedanken zu dieser Markierung...',
'Publish Highlight': 'Markierung Veröffentlichen',
'Show replies': 'Antworten anzeigen',
'Hide replies': 'Antworten ausblenden'
'Hide replies': 'Antworten ausblenden',
'Welcome to Jumble!': 'Willkommen bei Jumble!',
'Your feed is empty because you are not following anyone yet. Start by exploring interesting content and following users you like!':
'Ihr Feed ist leer, weil Sie noch niemandem folgen. Beginnen Sie damit, interessante Inhalte zu erkunden und Benutzern zu folgen, die Ihnen gefallen!',
'Search Users': 'Benutzer suchen',
'Create New Account': 'Neues Konto erstellen',
Important: 'Wichtig',
'Generate Your Account': 'Konto generieren',
'Your private key IS your account. Keep it safe!':
'Ihr privater Schlüssel IST Ihr Konto. Bewahren Sie ihn sicher auf!',
'In Nostr, your private key IS your account. If you lose your private key, you lose your account forever.':
'In Nostr IST Ihr privater Schlüssel Ihr Konto. Wenn Sie Ihren privaten Schlüssel verlieren, verlieren Sie Ihr Konto für immer.',
'Your Private Key': 'Ihr privater Schlüssel',
'Generate new key': 'Neuen Schlüssel generieren',
'Download Backup File': 'Sicherungsdatei herunterladen',
'Copied to Clipboard': 'In Zwischenablage kopiert',
'Copy to Clipboard': 'In Zwischenablage kopieren',
'I already saved my private key securely.':
'Ich habe meinen privaten Schlüssel bereits sicher gespeichert.',
'Almost Done!': 'Fast fertig!',
'Set a password to encrypt your key, or skip to finish':
'Legen Sie ein Passwort fest, um Ihren Schlüssel zu verschlüsseln, oder überspringen Sie, um fertig zu werden',
'Password Protection (Optional)': 'Passwortschutz (optional)',
'Setting a password encrypts your private key in this browser. You can skip this step, but we recommend setting one for added security.':
'Das Festlegen eines Passworts verschlüsselt Ihren privaten Schlüssel in diesem Browser. Sie können diesen Schritt überspringen, aber wir empfehlen, eines für zusätzliche Sicherheit festzulegen.',
'Password (Optional)': 'Passwort (optional)',
'Enter password or leave empty to skip':
'Passwort eingeben oder leer lassen, um zu überspringen',
'Confirm Password': 'Passwort bestätigen',
'Re-enter password': 'Passwort erneut eingeben',
'Passwords do not match': 'Passwörter stimmen nicht überein',
'Finish Signup': 'Registrierung abschließen',
// New improved signup copy
'Create Your Nostr Account': 'Erstellen Sie Ihr Nostr-Konto',
'Generate your unique private key. This is your digital identity.':
'Generieren Sie Ihren einzigartigen privaten Schlüssel. Dies ist Ihre digitale Identität.',
'Critical: Save Your Private Key': 'Kritisch: Speichern Sie Ihren privaten Schlüssel',
'Your private key IS your account. There is no password recovery. If you lose it, you lose your account forever. Please save it in a secure location.':
'Ihr privater Schlüssel IST Ihr Konto. Es gibt keine Passwortwiederherstellung. Wenn Sie ihn verlieren, verlieren Sie Ihr Konto für immer. Bitte speichern Sie ihn an einem sicheren Ort.',
'I have safely backed up my private key': 'Ich habe meinen privaten Schlüssel sicher gesichert',
'Secure Your Account': 'Sichern Sie Ihr Konto',
'Add an extra layer of protection with a password':
'Fügen Sie eine zusätzliche Schutzebene mit einem Passwort hinzu',
'Password Protection (Recommended)': 'Passwortschutz (empfohlen)',
'Add a password to encrypt your private key in this browser. This is optional but strongly recommended for better security.':
'Fügen Sie ein Passwort hinzu, um Ihren privaten Schlüssel in diesem Browser zu verschlüsseln. Dies ist optional, aber für bessere Sicherheit dringend empfohlen.',
'Create a password (or skip)': 'Erstellen Sie ein Passwort (oder überspringen)',
'Enter your password again': 'Geben Sie Ihr Passwort erneut ein',
'Complete Signup': 'Registrierung abschließen'
}
}

View File

@@ -592,6 +592,52 @@ export default {
'Write your thoughts about this highlight...': 'Write your thoughts about this highlight...',
'Publish Highlight': 'Publish Highlight',
'Show replies': 'Show replies',
'Hide replies': 'Hide replies'
'Hide replies': 'Hide replies',
'Welcome to Jumble!': 'Welcome to Jumble!',
'Your feed is empty because you are not following anyone yet. Start by exploring interesting content and following users you like!':
'Your feed is empty because you are not following anyone yet. Start by exploring interesting content and following users you like!',
'Search Users': 'Search Users',
'Create New Account': 'Create New Account',
Important: 'Important',
'Generate Your Account': 'Generate Your Account',
'Your private key IS your account. Keep it safe!':
'Your private key IS your account. Keep it safe!',
'In Nostr, your private key IS your account. If you lose your private key, you lose your account forever.':
'In Nostr, your private key IS your account. If you lose your account forever.',
'Your Private Key': 'Your Private Key',
'Generate new key': 'Generate new key',
'Download Backup File': 'Download Backup File',
'Copied to Clipboard': 'Copied to Clipboard',
'Copy to Clipboard': 'Copy to Clipboard',
'I already saved my private key securely.': 'I already saved my private key securely.',
'Almost Done!': 'Almost Done!',
'Set a password to encrypt your key, or skip to finish':
'Set a password to encrypt your key, or skip to finish',
'Password Protection (Optional)': 'Password Protection (Optional)',
'Setting a password encrypts your private key in this browser. You can skip this step, but we recommend setting one for added security.':
'Setting a password encrypts your private key in this browser. You can skip this step, but we recommend setting one for added security.',
'Password (Optional)': 'Password (Optional)',
'Enter password or leave empty to skip': 'Enter password or leave empty to skip',
'Confirm Password': 'Confirm Password',
'Re-enter password': 'Re-enter password',
'Passwords do not match': 'Passwords do not match',
'Finish Signup': 'Finish Signup',
// New improved signup copy
'Create Your Nostr Account': 'Create Your Nostr Account',
'Generate your unique private key. This is your digital identity.':
'Generate your unique private key. This is your digital identity.',
'Critical: Save Your Private Key': 'Critical: Save Your Private Key',
'Your private key IS your account. There is no password recovery. If you lose it, you lose your account forever. Please save it in a secure location.':
'Your private key IS your account. There is no password recovery. If you lose it, you lose your account forever. Please save it in a secure location.',
'I have safely backed up my private key': 'I have safely backed up my private key',
'Secure Your Account': 'Secure Your Account',
'Add an extra layer of protection with a password':
'Add an extra layer of protection with a password',
'Password Protection (Recommended)': 'Password Protection (Recommended)',
'Add a password to encrypt your private key in this browser. This is optional but strongly recommended for better security.':
'Add a password to encrypt your private key in this browser. This is optional but strongly recommended for better security.',
'Create a password (or skip)': 'Create a password (or skip)',
'Enter your password again': 'Enter your password again',
'Complete Signup': 'Complete Signup'
}
}

View File

@@ -602,6 +602,52 @@ export default {
'Escribe tus pensamientos sobre este resaltado...',
'Publish Highlight': 'Publicar Resaltado',
'Show replies': 'Mostrar respuestas',
'Hide replies': 'Ocultar respuestas'
'Hide replies': 'Ocultar respuestas',
'Welcome to Jumble!': '¡Bienvenido a Jumble!',
'Your feed is empty because you are not following anyone yet. Start by exploring interesting content and following users you like!':
'Tu feed está vacío porque aún no sigues a nadie. ¡Comienza explorando contenido interesante y siguiendo a los usuarios que te gusten!',
'Search Users': 'Buscar Usuarios',
'Create New Account': 'Crear nueva cuenta',
Important: 'Importante',
'Generate Your Account': 'Generar tu cuenta',
'Your private key IS your account. Keep it safe!':
'¡Tu clave privada ES tu cuenta. Mantenla segura!',
'In Nostr, your private key IS your account. If you lose your private key, you lose your account forever.':
'En Nostr, tu clave privada ES tu cuenta. Si pierdes tu clave privada, pierdes tu cuenta para siempre.',
'Your Private Key': 'Tu clave privada',
'Generate new key': 'Generar nueva clave',
'Download Backup File': 'Descargar archivo de respaldo',
'Copied to Clipboard': 'Copiado al portapapeles',
'Copy to Clipboard': 'Copiar al portapapeles',
'I already saved my private key securely.': 'Ya guardé mi clave privada de forma segura.',
'Almost Done!': '¡Casi terminado!',
'Set a password to encrypt your key, or skip to finish':
'Establece una contraseña para cifrar tu clave, o omítela para finalizar',
'Password Protection (Optional)': 'Protección con contraseña (opcional)',
'Setting a password encrypts your private key in this browser. You can skip this step, but we recommend setting one for added security.':
'Establecer una contraseña cifra tu clave privada en este navegador. Puedes omitir este paso, pero recomendamos establecer una para mayor seguridad.',
'Password (Optional)': 'Contraseña (opcional)',
'Enter password or leave empty to skip': 'Ingresa una contraseña o déjalo vacío para omitir',
'Confirm Password': 'Confirmar contraseña',
'Re-enter password': 'Vuelve a ingresar la contraseña',
'Passwords do not match': 'Las contraseñas no coinciden',
'Finish Signup': 'Finalizar registro',
// New improved signup copy
'Create Your Nostr Account': 'Crea tu cuenta de Nostr',
'Generate your unique private key. This is your digital identity.':
'Genera tu clave privada única. Esta es tu identidad digital.',
'Critical: Save Your Private Key': 'Crítico: Guarda tu clave privada',
'Your private key IS your account. There is no password recovery. If you lose it, you lose your account forever. Please save it in a secure location.':
'Tu clave privada ES tu cuenta. No hay recuperación de contraseña. Si la pierdes, perderás tu cuenta para siempre. Por favor, guárdala en un lugar seguro.',
'I have safely backed up my private key': 'He respaldado mi clave privada de forma segura',
'Secure Your Account': 'Asegura tu cuenta',
'Add an extra layer of protection with a password':
'Añade una capa adicional de protección con una contraseña',
'Password Protection (Recommended)': 'Protección con contraseña (recomendado)',
'Add a password to encrypt your private key in this browser. This is optional but strongly recommended for better security.':
'Añade una contraseña para cifrar tu clave privada en este navegador. Esto es opcional pero muy recomendado para mayor seguridad.',
'Create a password (or skip)': 'Crear una contraseña (o saltar)',
'Enter your password again': 'Ingresa tu contraseña nuevamente',
'Complete Signup': 'Completar registro'
}
}

View File

@@ -595,6 +595,54 @@ export default {
'Write your thoughts about this highlight...': 'نظرات خود را درباره این برجسته‌سازی بنویسید...',
'Publish Highlight': 'انتشار برجسته‌سازی',
'Show replies': 'نمایش پاسخ‌ها',
'Hide replies': 'پنهان کردن پاسخ‌ها'
'Hide replies': 'پنهان کردن پاسخ‌ها',
'Welcome to Jumble!': 'به Jumble خوش آمدید!',
'Your feed is empty because you are not following anyone yet. Start by exploring interesting content and following users you like!':
'فید شما خالی است زیرا هنوز کسی را دنبال نمی‌کنید. با کاوش محتوای جالب و دنبال کردن کاربرانی که دوست دارید شروع کنید!',
'Search Users': 'جستجوی کاربران',
'Create New Account': 'ایجاد حساب کاربری جدید',
Important: 'مهم',
'Generate Your Account': 'ایجاد حساب کاربری',
'Your private key IS your account. Keep it safe!':
'کلید خصوصی شما همان حساب کاربری شماست. آن را ایمن نگه دارید!',
'In Nostr, your private key IS your account. If you lose your private key, you lose your account forever.':
'در Nostr، کلید خصوصی شما همان حساب کاربری شماست. اگر کلید خصوصی خود را گم کنید، برای همیشه حساب خود را از دست می‌دهید.',
'Your Private Key': 'کلید خصوصی شما',
'Generate new key': 'ایجاد کلید جدید',
'Download Backup File': 'دانلود فایل پشتیبان',
'Copied to Clipboard': 'در کلیپ‌بورد کپی شد',
'Copy to Clipboard': 'کپی در کلیپ‌بورد',
'I already saved my private key securely.':
'من قبلاً کلید خصوصی خود را به طور ایمن ذخیره کرده‌ام.',
'Almost Done!': 'تقریباً تمام شد!',
'Set a password to encrypt your key, or skip to finish':
'یک رمز عبور برای رمزگذاری کلید خود تنظیم کنید، یا برای پایان دادن رد کنید',
'Password Protection (Optional)': 'حفاظت با رمز عبور (اختیاری)',
'Setting a password encrypts your private key in this browser. You can skip this step, but we recommend setting one for added security.':
'تنظیم رمز عبور، کلید خصوصی شما را در این مرورگر رمزگذاری می‌کند. می‌توانید این مرحله را رد کنید، اما ما برای امنیت بیشتر توصیه می‌کنیم یکی تنظیم کنید.',
'Password (Optional)': 'رمز عبور (اختیاری)',
'Enter password or leave empty to skip': 'رمز عبور را وارد کنید یا برای رد کردن خالی بگذارید',
'Confirm Password': 'تأیید رمز عبور',
'Re-enter password': 'رمز عبور را دوباره وارد کنید',
'Passwords do not match': 'رمزهای عبور مطابقت ندارند',
'Finish Signup': 'پایان ثبت‌نام',
// New improved signup copy
'Create Your Nostr Account': 'حساب Nostr خود را ایجاد کنید',
'Generate your unique private key. This is your digital identity.':
'کلید خصوصی منحصر به فرد خود را ایجاد کنید. این هویت دیجیتال شماست.',
'Critical: Save Your Private Key': 'حیاتی: کلید خصوصی خود را ذخیره کنید',
'Your private key IS your account. There is no password recovery. If you lose it, you lose your account forever. Please save it in a secure location.':
'کلید خصوصی شما حساب شماست. بازیابی رمز عبور وجود ندارد. اگر آن را گم کنید، حساب خود را برای همیشه از دست خواهید داد. لطفاً آن را در مکانی امن ذخیره کنید.',
'I have safely backed up my private key':
'من به طور ایمن از کلید خصوصی خود نسخه پشتیبان تهیه کرده‌ام',
'Secure Your Account': 'حساب خود را ایمن کنید',
'Add an extra layer of protection with a password':
'یک لایه حفاظتی اضافی با رمز عبور اضافه کنید',
'Password Protection (Recommended)': 'حفاظت با رمز عبور (توصیه شده)',
'Add a password to encrypt your private key in this browser. This is optional but strongly recommended for better security.':
'یک رمز عبور برای رمزگذاری کلید خصوصی خود در این مرورگر اضافه کنید. این اختیاری است اما برای امنیت بهتر به شدت توصیه می‌شود.',
'Create a password (or skip)': 'یک رمز عبور ایجاد کنید (یا رد کنید)',
'Enter your password again': 'رمز عبور خود را دوباره وارد کنید',
'Complete Signup': 'تکمیل ثبت‌نام'
}
}

View File

@@ -604,6 +604,53 @@ export default {
'Write your thoughts about this highlight...': 'Écrivez vos pensées sur ce surlignage...',
'Publish Highlight': 'Publier le Surlignage',
'Show replies': 'Afficher les réponses',
'Hide replies': 'Masquer les réponses'
'Hide replies': 'Masquer les réponses',
'Welcome to Jumble!': 'Bienvenue sur Jumble !',
'Your feed is empty because you are not following anyone yet. Start by exploring interesting content and following users you like!':
'Votre flux est vide car vous ne suivez personne pour le moment. Commencez par explorer du contenu intéressant et suivez les utilisateurs que vous aimez !',
'Search Users': 'Rechercher des utilisateurs',
'Create New Account': 'Créer un nouveau compte',
Important: 'Important',
'Generate Your Account': 'Générer votre compte',
'Your private key IS your account. Keep it safe!':
'Votre clé privée EST votre compte. Gardez-la en sécurité !',
'In Nostr, your private key IS your account. If you lose your private key, you lose your account forever.':
'Dans Nostr, votre clé privée EST votre compte. Si vous perdez votre clé privée, vous perdez votre compte pour toujours.',
'Your Private Key': 'Votre clé privée',
'Generate new key': 'Générer une nouvelle clé',
'Download Backup File': 'Télécharger le fichier de sauvegarde',
'Copied to Clipboard': 'Copié dans le presse-papiers',
'Copy to Clipboard': 'Copier dans le presse-papiers',
'I already saved my private key securely.':
"J'ai déjà sauvegardé ma clé privée en toute sécurité.",
'Almost Done!': 'Presque terminé !',
'Set a password to encrypt your key, or skip to finish':
'Définissez un mot de passe pour chiffrer votre clé, ou ignorez pour terminer',
'Password Protection (Optional)': 'Protection par mot de passe (facultatif)',
'Setting a password encrypts your private key in this browser. You can skip this step, but we recommend setting one for added security.':
"Définir un mot de passe chiffre votre clé privée dans ce navigateur. Vous pouvez ignorer cette étape, mais nous recommandons d'en définir un pour plus de sécurité.",
'Password (Optional)': 'Mot de passe (facultatif)',
'Enter password or leave empty to skip': 'Entrez un mot de passe ou laissez vide pour ignorer',
'Confirm Password': 'Confirmer le mot de passe',
'Re-enter password': 'Ressaisissez le mot de passe',
'Passwords do not match': 'Les mots de passe ne correspondent pas',
'Finish Signup': "Terminer l'inscription",
// New improved signup copy
'Create Your Nostr Account': 'Créez votre compte Nostr',
'Generate your unique private key. This is your digital identity.':
"Générez votre clé privée unique. C'est votre identité numérique.",
'Critical: Save Your Private Key': 'Critique : Sauvegardez votre clé privée',
'Your private key IS your account. There is no password recovery. If you lose it, you lose your account forever. Please save it in a secure location.':
"Votre clé privée EST votre compte. Il n'y a pas de récupération de mot de passe. Si vous la perdez, vous perdrez votre compte pour toujours. Veuillez la sauvegarder dans un endroit sécurisé.",
'I have safely backed up my private key': "J'ai sauvegardé ma clé privée en toute sécurité",
'Secure Your Account': 'Sécurisez votre compte',
'Add an extra layer of protection with a password':
'Ajoutez une couche de protection supplémentaire avec un mot de passe',
'Password Protection (Recommended)': 'Protection par mot de passe (recommandé)',
'Add a password to encrypt your private key in this browser. This is optional but strongly recommended for better security.':
"Ajoutez un mot de passe pour chiffrer votre clé privée dans ce navigateur. C'est facultatif mais fortement recommandé pour une meilleure sécurité.",
'Create a password (or skip)': 'Créez un mot de passe (ou ignorez)',
'Enter your password again': 'Entrez à nouveau votre mot de passe',
'Complete Signup': "Terminer l'inscription"
}
}

View File

@@ -596,6 +596,54 @@ export default {
'Write your thoughts about this highlight...': 'इस हाइलाइट के बारे में अपने विचार लिखें...',
'Publish Highlight': 'हाइलाइट प्रकाशित करें',
'Show replies': 'जवाब दिखाएं',
'Hide replies': 'जवाब छुपाएं'
'Hide replies': 'जवाब छुपाएं',
'Welcome to Jumble!': 'Jumble में आपका स्वागत है!',
'Your feed is empty because you are not following anyone yet. Start by exploring interesting content and following users you like!':
'आपका फ़ीड खाली है क्योंकि आप अभी तक किसी को फ़ॉलो नहीं कर रहे हैं। दिलचस्प सामग्री का अन्वेषण करके और अपनी पसंद के उपयोगकर्ताओं को फ़ॉलो करके शुरू करें!',
'Search Users': 'उपयोगकर्ता खोजें',
'Create New Account': 'नया खाता बनाएं',
Important: 'महत्वपूर्ण',
'Generate Your Account': 'अपना खाता बनाएं',
'Your private key IS your account. Keep it safe!':
'आपकी निजी कुंजी ही आपका खाता है। इसे सुरक्षित रखें!',
'In Nostr, your private key IS your account. If you lose your private key, you lose your account forever.':
'Nostr में, आपकी निजी कुंजी ही आपका खाता है। यदि आप अपनी निजी कुंजी खो देते हैं, तो आप अपना खाता हमेशा के लिए खो देते हैं।',
'Your Private Key': 'आपकी निजी कुंजी',
'Generate new key': 'नई कुंजी बनाएं',
'Download Backup File': 'बैकअप फ़ाइल डाउनलोड करें',
'Copied to Clipboard': 'क्लिपबोर्ड पर कॉपी किया गया',
'Copy to Clipboard': 'क्लिपबोर्ड पर कॉपी करें',
'I already saved my private key securely.':
'मैंने पहले ही अपनी निजी कुंजी को सुरक्षित रूप से सहेज लिया है।',
'Almost Done!': 'लगभग हो गया!',
'Set a password to encrypt your key, or skip to finish':
'अपनी कुंजी को एन्क्रिप्ट करने के लिए पासवर्ड सेट करें, या समाप्त करने के लिए छोड़ें',
'Password Protection (Optional)': 'पासवर्ड सुरक्षा (वैकल्पिक)',
'Setting a password encrypts your private key in this browser. You can skip this step, but we recommend setting one for added security.':
'पासवर्ड सेट करने से इस ब्राउज़र में आपकी निजी कुंजी एन्क्रिप्ट हो जाती है। आप इस चरण को छोड़ सकते हैं, लेकिन हम अतिरिक्त सुरक्षा के लिए एक सेट करने की सलाह देते हैं।',
'Password (Optional)': 'पासवर्ड (वैकल्पिक)',
'Enter password or leave empty to skip': 'पासवर्ड दर्ज करें या छोड़ने के लिए खाली छोड़ें',
'Confirm Password': 'पासवर्ड की पुष्टि करें',
'Re-enter password': 'पासवर्ड फिर से दर्ज करें',
'Passwords do not match': 'पासवर्ड मेल नहीं खाते',
'Finish Signup': 'साइनअप समाप्त करें',
// New improved signup copy
'Create Your Nostr Account': 'अपना Nostr खाता बनाएं',
'Generate your unique private key. This is your digital identity.':
'अपनी अद्वितीय निजी कुंजी उत्पन्न करें। यह आपकी डिजिटल पहचान है।',
'Critical: Save Your Private Key': 'महत्वपूर्ण: अपनी निजी कुंजी सहेजें',
'Your private key IS your account. There is no password recovery. If you lose it, you lose your account forever. Please save it in a secure location.':
'आपकी निजी कुंजी आपका खाता है। कोई पासवर्ड पुनर्प्राप्ति नहीं है। यदि आप इसे खो देते हैं, तो आप हमेशा के लिए अपना खाता खो देंगे। कृपया इसे सुरक्षित स्थान पर सहेजें।',
'I have safely backed up my private key':
'मैंने अपनी निजी कुंजी को सुरक्षित रूप से बैकअप कर लिया है',
'Secure Your Account': 'अपने खाते को सुरक्षित करें',
'Add an extra layer of protection with a password':
'पासवर्ड के साथ सुरक्षा की एक अतिरिक्त परत जोड़ें',
'Password Protection (Recommended)': 'पासवर्ड सुरक्षा (अनुशंसित)',
'Add a password to encrypt your private key in this browser. This is optional but strongly recommended for better security.':
'इस ब्राउज़र में अपनी निजी कुंजी को एन्क्रिप्ट करने के लिए पासवर्ड जोड़ें। यह वैकल्पिक है लेकिन बेहतर सुरक्षा के लिए दृढ़ता से अनुशंसित है।',
'Create a password (or skip)': 'एक पासवर्ड बनाएं (या छोड़ें)',
'Enter your password again': 'अपना पासवर्ड फिर से दर्ज करें',
'Complete Signup': 'साइनअप पूर्ण करें'
}
}

View File

@@ -590,6 +590,52 @@ export default {
'Write your thoughts about this highlight...': 'Írd le a gondolataidat erről a kiemelésről...',
'Publish Highlight': 'Kiemelés Közzététele',
'Show replies': 'Válaszok megjelenítése',
'Hide replies': 'Válaszok elrejtése'
'Hide replies': 'Válaszok elrejtése',
'Welcome to Jumble!': 'Üdvözlünk a Jumble-ban!',
'Your feed is empty because you are not following anyone yet. Start by exploring interesting content and following users you like!':
'A hírcsatornád üres, mert még nem követsz senkit. Kezdd el érdekes tartalmak felfedezésével és kövesd azokat a felhasználókat, akik tetszenek!',
'Search Users': 'Felhasználók keresése',
'Create New Account': 'Új fiók létrehozása',
Important: 'Fontos',
'Generate Your Account': 'Fiók létrehozása',
'Your private key IS your account. Keep it safe!':
'A privát kulcsod A fiókodat jelenti. Tartsd biztonságban!',
'In Nostr, your private key IS your account. If you lose your private key, you lose your account forever.':
'A Nostr-ban a privát kulcsod A fiókodat jelenti. Ha elveszíted a privát kulcsodat, örökre elveszíted a fiókodat.',
'Your Private Key': 'Privát kulcsod',
'Generate new key': 'Új kulcs generálása',
'Download Backup File': 'Biztonsági mentés letöltése',
'Copied to Clipboard': 'Vágólapra másolva',
'Copy to Clipboard': 'Másolás vágólapra',
'I already saved my private key securely.': 'Már biztonságosan elmentettem a privát kulcsomat.',
'Almost Done!': 'Majdnem kész!',
'Set a password to encrypt your key, or skip to finish':
'Állíts be jelszót a kulcsod titkosításához, vagy hagyd ki a befejezéshez',
'Password Protection (Optional)': 'Jelszavas védelem (opcionális)',
'Setting a password encrypts your private key in this browser. You can skip this step, but we recommend setting one for added security.':
'A jelszó beállítása titkosítja a privát kulcsodat ebben a böngészőben. Kihagyhatod ezt a lépést, de javasoljuk a beállítását a nagyobb biztonság érdekében.',
'Password (Optional)': 'Jelszó (opcionális)',
'Enter password or leave empty to skip': 'Írj be jelszót, vagy hagyd üresen a kihagyáshoz',
'Confirm Password': 'Jelszó megerősítése',
'Re-enter password': 'Jelszó újbóli megadása',
'Passwords do not match': 'A jelszavak nem egyeznek',
'Finish Signup': 'Regisztráció befejezése',
// New improved signup copy
'Create Your Nostr Account': 'Hozd létre Nostr fiókodat',
'Generate your unique private key. This is your digital identity.':
'Generáld le egyedi privát kulcsodat. Ez a digitális identitásod.',
'Critical: Save Your Private Key': 'Kritikus: Mentsd el a privát kulcsodat',
'Your private key IS your account. There is no password recovery. If you lose it, you lose your account forever. Please save it in a secure location.':
'A privát kulcsod A fiókod. Nincs jelszó-visszaállítás. Ha elveszíted, örökre elveszíted a fiókodat. Kérjük, mentsd el biztonságos helyre.',
'I have safely backed up my private key': 'Biztonságosan elmentettem a privát kulcsomat',
'Secure Your Account': 'Védd meg a fiókodat',
'Add an extra layer of protection with a password':
'Adj hozzá egy extra védelmi réteget jelszóval',
'Password Protection (Recommended)': 'Jelszavas védelem (ajánlott)',
'Add a password to encrypt your private key in this browser. This is optional but strongly recommended for better security.':
'Adj hozzá jelszót a privát kulcsod titkosításához ebben a böngészőben. Ez opcionális, de erősen ajánlott a jobb biztonság érdekében.',
'Create a password (or skip)': 'Hozz létre jelszót (vagy hagyd ki)',
'Enter your password again': 'Add meg újra a jelszavad',
'Complete Signup': 'Regisztráció befejezése'
}
}

View File

@@ -601,6 +601,53 @@ export default {
'Scrivi i tuoi pensieri su questa evidenziazione...',
'Publish Highlight': 'Pubblica Evidenziazione',
'Show replies': 'Mostra risposte',
'Hide replies': 'Nascondi risposte'
'Hide replies': 'Nascondi risposte',
'Welcome to Jumble!': 'Benvenuto su Jumble!',
'Your feed is empty because you are not following anyone yet. Start by exploring interesting content and following users you like!':
'Il tuo feed è vuoto perché non stai ancora seguendo nessuno. Inizia esplorando contenuti interessanti e seguendo gli utenti che ti piacciono!',
'Search Users': 'Cerca Utenti',
'Create New Account': 'Crea nuovo account',
Important: 'Importante',
'Generate Your Account': 'Genera il tuo account',
'Your private key IS your account. Keep it safe!':
'La tua chiave privata È il tuo account. Tienila al sicuro!',
'In Nostr, your private key IS your account. If you lose your private key, you lose your account forever.':
'In Nostr, la tua chiave privata È il tuo account. Se perdi la tua chiave privata, perdi il tuo account per sempre.',
'Your Private Key': 'La tua chiave privata',
'Generate new key': 'Genera nuova chiave',
'Download Backup File': 'Scarica file di backup',
'Copied to Clipboard': 'Copiato negli appunti',
'Copy to Clipboard': 'Copia negli appunti',
'I already saved my private key securely.':
'Ho già salvato la mia chiave privata in modo sicuro.',
'Almost Done!': 'Quasi fatto!',
'Set a password to encrypt your key, or skip to finish':
'Imposta una password per crittografare la tua chiave, o salta per finire',
'Password Protection (Optional)': 'Protezione con password (facoltativo)',
'Setting a password encrypts your private key in this browser. You can skip this step, but we recommend setting one for added security.':
'Impostare una password crittografa la tua chiave privata in questo browser. Puoi saltare questo passaggio, ma ti consigliamo di impostarne una per maggiore sicurezza.',
'Password (Optional)': 'Password (facoltativo)',
'Enter password or leave empty to skip': 'Inserisci la password o lascia vuoto per saltare',
'Confirm Password': 'Conferma password',
'Re-enter password': 'Reinserisci la password',
'Passwords do not match': 'Le password non corrispondono',
'Finish Signup': 'Completa registrazione',
// New improved signup copy
'Create Your Nostr Account': 'Crea il tuo account Nostr',
'Generate your unique private key. This is your digital identity.':
'Genera la tua chiave privata unica. Questa è la tua identità digitale.',
'Critical: Save Your Private Key': 'Critico: Salva la tua chiave privata',
'Your private key IS your account. There is no password recovery. If you lose it, you lose your account forever. Please save it in a secure location.':
"La tua chiave privata È il tuo account. Non c'è recupero password. Se la perdi, perderai il tuo account per sempre. Per favore salvala in un luogo sicuro.",
'I have safely backed up my private key': 'Ho salvato in modo sicuro la mia chiave privata',
'Secure Your Account': 'Proteggi il tuo account',
'Add an extra layer of protection with a password':
'Aggiungi un ulteriore livello di protezione con una password',
'Password Protection (Recommended)': 'Protezione con password (consigliato)',
'Add a password to encrypt your private key in this browser. This is optional but strongly recommended for better security.':
'Aggiungi una password per crittografare la tua chiave privata in questo browser. È facoltativo ma fortemente consigliato per una migliore sicurezza.',
'Create a password (or skip)': 'Crea una password (o salta)',
'Enter your password again': 'Inserisci di nuovo la tua password',
'Complete Signup': 'Completa registrazione'
}
}

View File

@@ -596,6 +596,52 @@ export default {
'このハイライトについての考えを書いてください...',
'Publish Highlight': 'ハイライトを公開',
'Show replies': '返信を表示',
'Hide replies': '返信を非表示'
'Hide replies': '返信を非表示',
'Welcome to Jumble!': 'Jumbleへようこそ',
'Your feed is empty because you are not following anyone yet. Start by exploring interesting content and following users you like!':
'まだ誰もフォローしていないため、フィードが空です。興味深いコンテンツを探索して、好きなユーザーをフォローしてみましょう!',
'Search Users': 'ユーザーを検索',
'Create New Account': '新しいアカウントを作成',
Important: '重要',
'Generate Your Account': 'アカウントを生成',
'Your private key IS your account. Keep it safe!':
'秘密鍵があなたのアカウントです。安全に保管してください!',
'In Nostr, your private key IS your account. If you lose your private key, you lose your account forever.':
'Nostrでは、秘密鍵があなたのアカウントです。秘密鍵を紛失すると、アカウントを永久に失います。',
'Your Private Key': 'あなたの秘密鍵',
'Generate new key': '新しい鍵を生成',
'Download Backup File': 'バックアップファイルをダウンロード',
'Copied to Clipboard': 'クリップボードにコピーしました',
'Copy to Clipboard': 'クリップボードにコピー',
'I already saved my private key securely.': '秘密鍵を安全に保存しました。',
'Almost Done!': 'もう少しで完了です!',
'Set a password to encrypt your key, or skip to finish':
'鍵を暗号化するためのパスワードを設定するか、スキップして完了してください',
'Password Protection (Optional)': 'パスワード保護(オプション)',
'Setting a password encrypts your private key in this browser. You can skip this step, but we recommend setting one for added security.':
'パスワードを設定すると、このブラウザで秘密鍵が暗号化されます。この手順はスキップできますが、セキュリティ強化のために設定することをお勧めします。',
'Password (Optional)': 'パスワード(オプション)',
'Enter password or leave empty to skip':
'パスワードを入力するか、空のままにしてスキップしてください',
'Confirm Password': 'パスワードを確認',
'Re-enter password': 'パスワードを再入力',
'Passwords do not match': 'パスワードが一致しません',
'Finish Signup': '登録を完了',
// New improved signup copy
'Create Your Nostr Account': 'Nostrアカウントを作成',
'Generate your unique private key. This is your digital identity.':
'あなた専用の秘密鍵を生成します。これがあなたのデジタルアイデンティティです。',
'Critical: Save Your Private Key': '重要:秘密鍵を保存してください',
'Your private key IS your account. There is no password recovery. If you lose it, you lose your account forever. Please save it in a secure location.':
'あなたの秘密鍵があなたのアカウントそのものです。パスワード復旧機能はありません。紛失すると、アカウントを永久に失います。安全な場所に保存してください。',
'I have safely backed up my private key': '秘密鍵を安全にバックアップしました',
'Secure Your Account': 'アカウントを保護',
'Add an extra layer of protection with a password': 'パスワードで追加の保護層を追加',
'Password Protection (Recommended)': 'パスワード保護(推奨)',
'Add a password to encrypt your private key in this browser. This is optional but strongly recommended for better security.':
'このブラウザで秘密鍵を暗号化するパスワードを追加します。オプションですが、より良いセキュリティのために強くお勧めします。',
'Create a password (or skip)': 'パスワードを作成(またはスキップ)',
'Enter your password again': 'パスワードをもう一度入力',
'Complete Signup': '登録を完了'
}
}

View File

@@ -594,6 +594,51 @@ export default {
'Write your thoughts about this highlight...': '이 하이라이트에 대한 생각을 작성하세요...',
'Publish Highlight': '하이라이트 게시',
'Show replies': '답글 표시',
'Hide replies': '답글 숨기기'
'Hide replies': '답글 숨기기',
'Welcome to Jumble!': 'Jumble에 오신 것을 환영합니다!',
'Your feed is empty because you are not following anyone yet. Start by exploring interesting content and following users you like!':
'아직 아무도 팔로우하지 않아서 피드가 비어 있습니다. 흥미로운 콘텐츠를 탐색하고 마음에 드는 사용자를 팔로우해보세요!',
'Search Users': '사용자 검색',
'Create New Account': '새 계정 만들기',
Important: '중요',
'Generate Your Account': '계정 생성',
'Your private key IS your account. Keep it safe!':
'개인 키가 바로 당신의 계정입니다. 안전하게 보관하세요!',
'In Nostr, your private key IS your account. If you lose your private key, you lose your account forever.':
'Nostr에서는 개인 키가 바로 당신의 계정입니다. 개인 키를 잃으면 계정을 영구적으로 잃게 됩니다.',
'Your Private Key': '개인 키',
'Generate new key': '새 키 생성',
'Download Backup File': '백업 파일 다운로드',
'Copied to Clipboard': '클립보드에 복사됨',
'Copy to Clipboard': '클립보드에 복사',
'I already saved my private key securely.': '이미 개인 키를 안전하게 저장했습니다.',
'Almost Done!': '거의 완료되었습니다!',
'Set a password to encrypt your key, or skip to finish':
'키를 암호화할 비밀번호를 설정하거나 건너뛰어 완료하세요',
'Password Protection (Optional)': '비밀번호 보호 (선택사항)',
'Setting a password encrypts your private key in this browser. You can skip this step, but we recommend setting one for added security.':
'비밀번호를 설정하면 이 브라우저에서 개인 키가 암호화됩니다. 이 단계를 건너뛸 수 있지만 보안 강화를 위해 설정하는 것을 권장합니다.',
'Password (Optional)': '비밀번호 (선택사항)',
'Enter password or leave empty to skip': '비밀번호를 입력하거나 비워두어 건너뛰세요',
'Confirm Password': '비밀번호 확인',
'Re-enter password': '비밀번호 재입력',
'Passwords do not match': '비밀번호가 일치하지 않습니다',
'Finish Signup': '가입 완료',
// New improved signup copy
'Create Your Nostr Account': 'Nostr 계정 만들기',
'Generate your unique private key. This is your digital identity.':
'고유한 개인 키를 생성합니다. 이것이 당신의 디지털 신원입니다.',
'Critical: Save Your Private Key': '중요: 개인 키를 저장하세요',
'Your private key IS your account. There is no password recovery. If you lose it, you lose your account forever. Please save it in a secure location.':
'개인 키가 곧 계정 그 자체입니다. 비밀번호 복구 기능이 없습니다. 분실하면 계정을 영구적으로 잃게 됩니다. 안전한 곳에 저장하세요.',
'I have safely backed up my private key': '개인 키를 안전하게 백업했습니다',
'Secure Your Account': '계정 보호하기',
'Add an extra layer of protection with a password': '비밀번호로 추가 보호 계층 추가',
'Password Protection (Recommended)': '비밀번호 보호 (권장)',
'Add a password to encrypt your private key in this browser. This is optional but strongly recommended for better security.':
'이 브라우저에서 개인 키를 암호화할 비밀번호를 추가합니다. 선택사항이지만 더 나은 보안을 위해 강력히 권장합니다.',
'Create a password (or skip)': '비밀번호 생성(또는 건너뛰기)',
'Enter your password again': '비밀번호를 다시 입력하세요',
'Complete Signup': '가입 완료'
}
}

View File

@@ -602,6 +602,53 @@ export default {
'Napisz swoje przemyślenia na temat tego wyróżnienienia...',
'Publish Highlight': 'Opublikuj wyróżnienie',
'Show replies': 'Pokaż odpowiedzi',
'Hide replies': 'Ukryj odpowiedzi'
'Hide replies': 'Ukryj odpowiedzi',
'Welcome to Jumble!': 'Witamy w Jumble!',
'Your feed is empty because you are not following anyone yet. Start by exploring interesting content and following users you like!':
'Twój kanał jest pusty, ponieważ jeszcze nikogo nie obserwujesz. Zacznij od odkrywania ciekawych treści i obserwowania użytkowników, którzy Ci się podobają!',
'Search Users': 'Szukaj użytkowników',
'Create New Account': 'Utwórz nowe konto',
Important: 'Ważne',
'Generate Your Account': 'Wygeneruj swoje konto',
'Your private key IS your account. Keep it safe!':
'Twój klucz prywatny TO twoje konto. Przechowuj go bezpiecznie!',
'In Nostr, your private key IS your account. If you lose your private key, you lose your account forever.':
'W Nostr twój klucz prywatny TO twoje konto. Jeśli stracisz swój klucz prywatny, stracisz swoje konto na zawsze.',
'Your Private Key': 'Twój klucz prywatny',
'Generate new key': 'Wygeneruj nowy klucz',
'Download Backup File': 'Pobierz plik kopii zapasowej',
'Copied to Clipboard': 'Skopiowano do schowka',
'Copy to Clipboard': 'Kopiuj do schowka',
'I already saved my private key securely.': 'Już bezpiecznie zapisałem mój klucz prywatny.',
'Almost Done!': 'Prawie gotowe!',
'Set a password to encrypt your key, or skip to finish':
'Ustaw hasło, aby zaszyfrować swój klucz, lub pomiń, aby zakończyć',
'Password Protection (Optional)': 'Ochrona hasłem (opcjonalnie)',
'Setting a password encrypts your private key in this browser. You can skip this step, but we recommend setting one for added security.':
'Ustawienie hasła szyfruje twój klucz prywatny w tej przeglądarce. Możesz pominąć ten krok, ale zalecamy ustawienie hasła dla dodatkowego bezpieczeństwa.',
'Password (Optional)': 'Hasło (opcjonalnie)',
'Enter password or leave empty to skip': 'Wprowadź hasło lub pozostaw puste, aby pominąć',
'Confirm Password': 'Potwierdź hasło',
'Re-enter password': 'Wprowadź hasło ponownie',
'Passwords do not match': 'Hasła nie pasują do siebie',
'Finish Signup': 'Zakończ rejestrację',
// New improved signup copy
'Create Your Nostr Account': 'Utwórz swoje konto Nostr',
'Generate your unique private key. This is your digital identity.':
'Wygeneruj swój unikalny klucz prywatny. To jest twoja cyfrowa tożsamość.',
'Critical: Save Your Private Key': 'Krytyczne: Zapisz swój klucz prywatny',
'Your private key IS your account. There is no password recovery. If you lose it, you lose your account forever. Please save it in a secure location.':
'Twój klucz prywatny TO JEST twoje konto. Nie ma odzyskiwania hasła. Jeśli go stracisz, na zawsze stracisz swoje konto. Proszę zapisać go w bezpiecznym miejscu.',
'I have safely backed up my private key':
'Bezpiecznie wykonałem kopię zapasową mojego klucza prywatnego',
'Secure Your Account': 'Zabezpiecz swoje konto',
'Add an extra layer of protection with a password':
'Dodaj dodatkową warstwę ochrony za pomocą hasła',
'Password Protection (Recommended)': 'Ochrona hasłem (zalecane)',
'Add a password to encrypt your private key in this browser. This is optional but strongly recommended for better security.':
'Dodaj hasło, aby zaszyfrować swój klucz prywatny w tej przeglądarce. Jest to opcjonalne, ale zdecydowanie zalecane dla lepszego bezpieczeństwa.',
'Create a password (or skip)': 'Utwórz hasło (lub pomiń)',
'Enter your password again': 'Wprowadź hasło ponownie',
'Complete Signup': 'Zakończ rejestrację'
}
}

View File

@@ -161,7 +161,8 @@ export default {
'calculating...': 'Calculando...',
'Calculate optimal read relays': 'Calcular relays de leitura ideais',
'Login to set': 'Entrar no conjunto',
'Please login to view following feed': 'Por favor, faça login para ver o conteúdo das pessoas que você segue',
'Please login to view following feed':
'Por favor, faça login para ver o conteúdo das pessoas que você segue',
'Send only to r': 'Enviar apenas para {{r}}',
'Send only to these relays': 'Enviar apenas para estes relays',
Explore: 'Explorar',
@@ -597,6 +598,52 @@ export default {
'Escreva seus pensamentos sobre este destaque...',
'Publish Highlight': 'Publicar Destaque',
'Show replies': 'Mostrar respostas',
'Hide replies': 'Ocultar respostas'
'Hide replies': 'Ocultar respostas',
'Welcome to Jumble!': 'Bem-vindo ao Jumble!',
'Your feed is empty because you are not following anyone yet. Start by exploring interesting content and following users you like!':
'Seu feed está vazio porque você ainda não está seguindo ninguém. Comece explorando conteúdo interessante e seguindo usuários que você gosta!',
'Search Users': 'Buscar Usuários',
'Create New Account': 'Criar nova conta',
Important: 'Importante',
'Generate Your Account': 'Gerar sua conta',
'Your private key IS your account. Keep it safe!':
'Sua chave privada É sua conta. Mantenha-a segura!',
'In Nostr, your private key IS your account. If you lose your private key, you lose your account forever.':
'No Nostr, sua chave privada É sua conta. Se você perder sua chave privada, perderá sua conta para sempre.',
'Your Private Key': 'Sua chave privada',
'Generate new key': 'Gerar nova chave',
'Download Backup File': 'Baixar arquivo de backup',
'Copied to Clipboard': 'Copiado para a área de transferência',
'Copy to Clipboard': 'Copiar para a área de transferência',
'I already saved my private key securely.': 'Já salvei minha chave privada com segurança.',
'Almost Done!': 'Quase pronto!',
'Set a password to encrypt your key, or skip to finish':
'Defina uma senha para criptografar sua chave ou pule para finalizar',
'Password Protection (Optional)': 'Proteção por senha (opcional)',
'Setting a password encrypts your private key in this browser. You can skip this step, but we recommend setting one for added security.':
'Definir uma senha criptografa sua chave privada neste navegador. Você pode pular esta etapa, mas recomendamos definir uma para maior segurança.',
'Password (Optional)': 'Senha (opcional)',
'Enter password or leave empty to skip': 'Digite a senha ou deixe em branco para pular',
'Confirm Password': 'Confirmar senha',
'Re-enter password': 'Digite a senha novamente',
'Passwords do not match': 'As senhas não coincidem',
'Finish Signup': 'Concluir cadastro',
// New improved signup copy
'Create Your Nostr Account': 'Crie sua conta Nostr',
'Generate your unique private key. This is your digital identity.':
'Gere sua chave privada única. Esta é sua identidade digital.',
'Critical: Save Your Private Key': 'Crítico: Salve sua chave privada',
'Your private key IS your account. There is no password recovery. If you lose it, you lose your account forever. Please save it in a secure location.':
'Sua chave privada É sua conta. Não há recuperação de senha. Se você perdê-la, perderá sua conta para sempre. Por favor, salve-a em um local seguro.',
'I have safely backed up my private key': 'Fiz backup seguro da minha chave privada',
'Secure Your Account': 'Proteja sua conta',
'Add an extra layer of protection with a password':
'Adicione uma camada extra de proteção com uma senha',
'Password Protection (Recommended)': 'Proteção por senha (recomendado)',
'Add a password to encrypt your private key in this browser. This is optional but strongly recommended for better security.':
'Adicione uma senha para criptografar sua chave privada neste navegador. Isso é opcional, mas fortemente recomendado para melhor segurança.',
'Create a password (or skip)': 'Crie uma senha (ou pule)',
'Enter your password again': 'Digite sua senha novamente',
'Complete Signup': 'Concluir cadastro'
}
}

View File

@@ -600,6 +600,53 @@ export default {
'Escreva os seus pensamentos sobre este destaque...',
'Publish Highlight': 'Publicar Destaque',
'Show replies': 'Mostrar respostas',
'Hide replies': 'Ocultar respostas'
'Hide replies': 'Ocultar respostas',
'Welcome to Jumble!': 'Bem-vindo ao Jumble!',
'Your feed is empty because you are not following anyone yet. Start by exploring interesting content and following users you like!':
'O seu feed está vazio porque ainda não está a seguir ninguém. Comece por explorar conteúdo interessante e siga utilizadores de que gosta!',
'Search Users': 'Procurar Utilizadores',
'Create New Account': 'Criar nova conta',
Important: 'Importante',
'Generate Your Account': 'Gerar a sua conta',
'Your private key IS your account. Keep it safe!':
'A sua chave privada É a sua conta. Mantenha-a segura!',
'In Nostr, your private key IS your account. If you lose your private key, you lose your account forever.':
'No Nostr, a sua chave privada É a sua conta. Se perder a sua chave privada, perde a sua conta para sempre.',
'Your Private Key': 'A sua chave privada',
'Generate new key': 'Gerar nova chave',
'Download Backup File': 'Transferir ficheiro de cópia de segurança',
'Copied to Clipboard': 'Copiado para a área de transferência',
'Copy to Clipboard': 'Copiar para a área de transferência',
'I already saved my private key securely.': 'Já guardei a minha chave privada de forma segura.',
'Almost Done!': 'Quase pronto!',
'Set a password to encrypt your key, or skip to finish':
'Defina uma palavra-passe para encriptar a sua chave ou ignore para finalizar',
'Password Protection (Optional)': 'Proteção por palavra-passe (opcional)',
'Setting a password encrypts your private key in this browser. You can skip this step, but we recommend setting one for added security.':
'Definir uma palavra-passe encripta a sua chave privada neste navegador. Pode ignorar este passo, mas recomendamos que defina uma para maior segurança.',
'Password (Optional)': 'Palavra-passe (opcional)',
'Enter password or leave empty to skip':
'Introduza a palavra-passe ou deixe vazio para ignorar',
'Confirm Password': 'Confirmar palavra-passe',
'Re-enter password': 'Introduza novamente a palavra-passe',
'Passwords do not match': 'As palavras-passe não coincidem',
'Finish Signup': 'Concluir registo',
// New improved signup copy
'Create Your Nostr Account': 'Crie a sua conta Nostr',
'Generate your unique private key. This is your digital identity.':
'Gere a sua chave privada única. Esta é a sua identidade digital.',
'Critical: Save Your Private Key': 'Crítico: Guarde a sua chave privada',
'Your private key IS your account. There is no password recovery. If you lose it, you lose your account forever. Please save it in a secure location.':
'A sua chave privada É a sua conta. Não há recuperação de palavra-passe. Se a perder, perderá a sua conta para sempre. Por favor, guarde-a num local seguro.',
'I have safely backed up my private key': 'Fiz uma cópia de segurança da minha chave privada',
'Secure Your Account': 'Proteja a sua conta',
'Add an extra layer of protection with a password':
'Adicione uma camada extra de proteção com uma palavra-passe',
'Password Protection (Recommended)': 'Proteção por palavra-passe (recomendado)',
'Add a password to encrypt your private key in this browser. This is optional but strongly recommended for better security.':
'Adicione uma palavra-passe para encriptar a sua chave privada neste navegador. Isto é opcional, mas fortemente recomendado para melhor segurança.',
'Create a password (or skip)': 'Crie uma palavra-passe (ou ignore)',
'Enter your password again': 'Introduza novamente a sua palavra-passe',
'Complete Signup': 'Concluir registo'
}
}

View File

@@ -601,6 +601,53 @@ export default {
'Write your thoughts about this highlight...': 'Напишите свои мысли об этом выделении...',
'Publish Highlight': 'Опубликовать Выделение',
'Show replies': 'Показать ответы',
'Hide replies': 'Скрыть ответы'
'Hide replies': 'Скрыть ответы',
'Welcome to Jumble!': 'Добро пожаловать в Jumble!',
'Your feed is empty because you are not following anyone yet. Start by exploring interesting content and following users you like!':
'Ваша лента пуста, потому что вы еще ни на кого не подписаны. Начните с изучения интересного контента и подписки на понравившихся пользователей!',
'Search Users': 'Поиск пользователей',
'Create New Account': 'Создать новый аккаунт',
Important: 'Важно',
'Generate Your Account': 'Создать аккаунт',
'Your private key IS your account. Keep it safe!':
'Ваш приватный ключ — это ваш аккаунт. Храните его в безопасности!',
'In Nostr, your private key IS your account. If you lose your private key, you lose your account forever.':
'В Nostr ваш приватный ключ — это ваш аккаунт. Если вы потеряете приватный ключ, вы навсегда потеряете свой аккаунт.',
'Your Private Key': 'Ваш приватный ключ',
'Generate new key': 'Создать новый ключ',
'Download Backup File': 'Скачать файл резервной копии',
'Copied to Clipboard': 'Скопировано в буфер обмена',
'Copy to Clipboard': 'Копировать в буфер обмена',
'I already saved my private key securely.':
'Я уже сохранил свой приватный ключ в безопасном месте.',
'Almost Done!': 'Почти готово!',
'Set a password to encrypt your key, or skip to finish':
'Установите пароль для шифрования ключа или пропустите, чтобы завершить',
'Password Protection (Optional)': 'Защита паролем (необязательно)',
'Setting a password encrypts your private key in this browser. You can skip this step, but we recommend setting one for added security.':
'Установка пароля шифрует ваш приватный ключ в этом браузере. Вы можете пропустить этот шаг, но мы рекомендуем установить пароль для дополнительной безопасности.',
'Password (Optional)': 'Пароль (необязательно)',
'Enter password or leave empty to skip': 'Введите пароль или оставьте пустым, чтобы пропустить',
'Confirm Password': 'Подтвердите пароль',
'Re-enter password': 'Введите пароль повторно',
'Passwords do not match': 'Пароли не совпадают',
'Finish Signup': 'Завершить регистрацию',
// New improved signup copy
'Create Your Nostr Account': 'Создайте свой аккаунт Nostr',
'Generate your unique private key. This is your digital identity.':
'Сгенерируйте ваш уникальный приватный ключ. Это ваша цифровая личность.',
'Critical: Save Your Private Key': 'Критично: Сохраните ваш приватный ключ',
'Your private key IS your account. There is no password recovery. If you lose it, you lose your account forever. Please save it in a secure location.':
'Ваш приватный ключ И ЕСТЬ ваш аккаунт. Восстановление пароля невозможно. Если вы его потеряете, вы навсегда потеряете свой аккаунт. Пожалуйста, сохраните его в безопасном месте.',
'I have safely backed up my private key': 'Я безопасно сохранил свой приватный ключ',
'Secure Your Account': 'Защитите ваш аккаунт',
'Add an extra layer of protection with a password':
'Добавьте дополнительный уровень защиты с помощью пароля',
'Password Protection (Recommended)': 'Защита паролем (рекомендуется)',
'Add a password to encrypt your private key in this browser. This is optional but strongly recommended for better security.':
'Добавьте пароль для шифрования вашего приватного ключа в этом браузере. Это необязательно, но настоятельно рекомендуется для лучшей безопасности.',
'Create a password (or skip)': 'Создайте пароль (или пропустите)',
'Enter your password again': 'Введите пароль еще раз',
'Complete Signup': 'Завершить регистрацию'
}
}

View File

@@ -588,6 +588,51 @@ export default {
'Write your thoughts about this highlight...': 'เขียนความคิดของคุณเกี่ยวกับไฮไลท์นี้...',
'Publish Highlight': 'เผยแพร่ไฮไลท์',
'Show replies': 'แสดงการตอบกลับ',
'Hide replies': 'ซ่อนการตอบกลับ'
'Hide replies': 'ซ่อนการตอบกลับ',
'Welcome to Jumble!': 'ยินดีต้อนรับสู่ Jumble!',
'Your feed is empty because you are not following anyone yet. Start by exploring interesting content and following users you like!':
'ฟีดของคุณว่างเปล่าเพราะคุณยังไม่ได้ติดตามใครเลย เริ่มต้นด้วยการสำรวจเนื้อหาที่น่าสนใจและติดตามผู้ใช้ที่คุณชอบ!',
'Search Users': 'ค้นหาผู้ใช้',
'Create New Account': 'สร้างบัญชีใหม่',
Important: 'สำคัญ',
'Generate Your Account': 'สร้างบัญชีของคุณ',
'Your private key IS your account. Keep it safe!':
'คีย์ส่วนตัวของคุณคือบัญชีของคุณ เก็บไว้ให้ปลอดภัย!',
'In Nostr, your private key IS your account. If you lose your private key, you lose your account forever.':
'ใน Nostr คีย์ส่วนตัวของคุณคือบัญชีของคุณ หากคุณสูญเสียคีย์ส่วนตัว คุณจะสูญเสียบัญชีของคุณตลอดไป',
'Your Private Key': 'คีย์ส่วนตัวของคุณ',
'Generate new key': 'สร้างคีย์ใหม่',
'Download Backup File': 'ดาวน์โหลดไฟล์สำรอง',
'Copied to Clipboard': 'คัดลอกไปยังคลิปบอร์ดแล้ว',
'Copy to Clipboard': 'คัดลอกไปยังคลิปบอร์ด',
'I already saved my private key securely.': 'ฉันได้บันทึกคีย์ส่วนตัวของฉันอย่างปลอดภัยแล้ว',
'Almost Done!': 'เกือบเสร็จแล้ว!',
'Set a password to encrypt your key, or skip to finish':
'ตั้งรหัสผ่านเพื่อเข้ารหัสคีย์ของคุณ หรือข้ามเพื่อเสร็จสิ้น',
'Password Protection (Optional)': 'การป้องกันด้วยรหัสผ่าน (ไม่บังคับ)',
'Setting a password encrypts your private key in this browser. You can skip this step, but we recommend setting one for added security.':
'การตั้งรหัสผ่านจะเข้ารหัสคีย์ส่วนตัวของคุณในเบราว์เซอร์นี้ คุณสามารถข้ามขั้นตอนนี้ได้ แต่เราแนะนำให้ตั้งรหัสผ่านเพื่อความปลอดภัยเพิ่มเติม',
'Password (Optional)': 'รหัสผ่าน (ไม่บังคับ)',
'Enter password or leave empty to skip': 'ป้อนรหัสผ่านหรือเว้นว่างเพื่อข้าม',
'Confirm Password': 'ยืนยันรหัสผ่าน',
'Re-enter password': 'ป้อนรหัสผ่านอีกครั้ง',
'Passwords do not match': 'รหัสผ่านไม่ตรงกัน',
'Finish Signup': 'เสร็จสิ้นการลงทะเบียน',
// New improved signup copy
'Create Your Nostr Account': 'สร้างบัญชี Nostr ของคุณ',
'Generate your unique private key. This is your digital identity.':
'สร้างคีย์ส่วนตัวที่ไม่ซ้ำของคุณ นี่คือตัวตนดิจิทัลของคุณ',
'Critical: Save Your Private Key': 'สำคัญมาก: บันทึกคีย์ส่วนตัวของคุณ',
'Your private key IS your account. There is no password recovery. If you lose it, you lose your account forever. Please save it in a secure location.':
'คีย์ส่วนตัวของคุณคือบัญชีของคุณ ไม่มีการกู้คืนรหัสผ่าน หากคุณทำหาย คุณจะสูญเสียบัญชีของคุณตลอดไป โปรดบันทึกไว้ในที่ปลอดภัย',
'I have safely backed up my private key': 'ฉันได้สำรองคีย์ส่วนตัวของฉันอย่างปลอดภัยแล้ว',
'Secure Your Account': 'รักษาความปลอดภัยบัญชีของคุณ',
'Add an extra layer of protection with a password': 'เพิ่มชั้นความปลอดภัยเพิ่มเติมด้วยรหัสผ่าน',
'Password Protection (Recommended)': 'การป้องกันด้วยรหัสผ่าน (แนะนำ)',
'Add a password to encrypt your private key in this browser. This is optional but strongly recommended for better security.':
'เพิ่มรหัสผ่านเพื่อเข้ารหัสคีย์ส่วนตัวของคุณในเบราว์เซอร์นี้ เป็นตัวเลือก แต่แนะนำอย่างยิ่งเพื่อความปลอดภัยที่ดีขึ้น',
'Create a password (or skip)': 'สร้างรหัสผ่าน (หรือข้าม)',
'Enter your password again': 'ป้อนรหัสผ่านของคุณอีกครั้ง',
'Complete Signup': 'เสร็จสิ้นการลงทะเบียน'
}
}

View File

@@ -320,7 +320,8 @@ export default {
Media: '媒體',
'Republish to ...': '重新發布到 ...',
'Successfully republish to your write relays': '成功重新發布到您的寫入伺服器',
'Failed to republish to your write relays: {{error}}': '重新發布到您的寫入伺服器失敗:{{error}}',
'Failed to republish to your write relays: {{error}}':
'重新發布到您的寫入伺服器失敗:{{error}}',
'Successfully republish to relay set: {{name}}': '成功重新發布到伺服器組:{{name}}',
'Failed to republish to relay set: {{name}}. Error: {{error}}':
'重新發布到伺服器組:{{name}} 失敗。錯誤:{{error}}',
@@ -575,6 +576,49 @@ export default {
'Special Follow': '特別關注',
'Unfollow Special': '取消特別關注',
'Personal Feeds': '個人訂閱',
'Relay Feeds': '中繼訂閱'
'Relay Feeds': '中繼訂閱',
'Welcome to Jumble!': '歡迎來到 Jumble',
'Your feed is empty because you are not following anyone yet. Start by exploring interesting content and following users you like!':
'你的動態是空的,因為你還沒有關注任何人。開始探索有趣的內容並關注你喜歡的用戶吧!',
'Search Users': '搜尋用戶',
'Create New Account': '建立新帳戶',
Important: '重要',
'Generate Your Account': '生成你的帳戶',
'Your private key IS your account. Keep it safe!': '你的私鑰就是你的帳戶。請妥善保管!',
'In Nostr, your private key IS your account. If you lose your private key, you lose your account forever.':
'在 Nostr 中,你的私鑰就是你的帳戶。如果你遺失了私鑰,你將永遠失去你的帳戶。',
'Your Private Key': '你的私鑰',
'Generate new key': '生成新金鑰',
'Download Backup File': '下載備份檔案',
'Copied to Clipboard': '已複製到剪貼簿',
'Copy to Clipboard': '複製到剪貼簿',
'I already saved my private key securely.': '我已經安全地儲存了我的私鑰。',
'Almost Done!': '即將完成!',
'Set a password to encrypt your key, or skip to finish': '設定密碼來加密你的金鑰,或跳過以完成',
'Password Protection (Optional)': '密碼保護(可選)',
'Setting a password encrypts your private key in this browser. You can skip this step, but we recommend setting one for added security.':
'設定密碼會在此瀏覽器中加密你的私鑰。你可以跳過此步驟,但我們建議設定密碼以增強安全性。',
'Password (Optional)': '密碼(可選)',
'Enter password or leave empty to skip': '輸入密碼或留空以跳過',
'Confirm Password': '確認密碼',
'Re-enter password': '重新輸入密碼',
'Passwords do not match': '密碼不符合',
'Finish Signup': '完成註冊',
// New improved signup copy
'Create Your Nostr Account': '建立你的 Nostr 帳戶',
'Generate your unique private key. This is your digital identity.':
'生成你的專屬私鑰。這是你的數位身份。',
'Critical: Save Your Private Key': '重要:儲存你的私鑰',
'Your private key IS your account. There is no password recovery. If you lose it, you lose your account forever. Please save it in a secure location.':
'你的私鑰就是你的帳戶。沒有密碼找回功能。如果遺失,你將永遠失去你的帳戶。請將其儲存在安全的地方。',
'I have safely backed up my private key': '我已安全備份我的私鑰',
'Secure Your Account': '保護你的帳戶',
'Add an extra layer of protection with a password': '使用密碼新增額外的保護層',
'Password Protection (Recommended)': '密碼保護(推薦)',
'Add a password to encrypt your private key in this browser. This is optional but strongly recommended for better security.':
'新增密碼以在此瀏覽器中加密你的私鑰。這是可選的,但強烈建議設定以獲得更好的安全性。',
'Create a password (or skip)': '建立密碼(或跳過)',
'Enter your password again': '再次輸入你的密碼',
'Complete Signup': '完成註冊'
}
}

View File

@@ -581,6 +581,49 @@ export default {
'Write your thoughts about this highlight...': '写下你对这段高亮的想法...',
'Publish Highlight': '发布高亮',
'Show replies': '显示回复',
'Hide replies': '隐藏回复'
'Hide replies': '隐藏回复',
'Welcome to Jumble!': '欢迎来到 Jumble',
'Your feed is empty because you are not following anyone yet. Start by exploring interesting content and following users you like!':
'你的动态是空的,因为你还没有关注任何人。开始探索有趣的内容并关注你喜欢的用户吧!',
'Search Users': '搜索用户',
'Create New Account': '创建新账户',
Important: '重要',
'Generate Your Account': '生成你的账户',
'Your private key IS your account. Keep it safe!': '你的私钥就是你的账户。请妥善保管!',
'In Nostr, your private key IS your account. If you lose your private key, you lose your account forever.':
'在 Nostr 中,你的私钥就是你的账户。如果你丢失了私钥,你将永远失去你的账户。',
'Your Private Key': '你的私钥',
'Generate new key': '生成新密钥',
'Download Backup File': '下载备份文件',
'Copied to Clipboard': '已复制到剪贴板',
'Copy to Clipboard': '复制到剪贴板',
'I already saved my private key securely.': '我已经安全地保存了我的私钥。',
'Almost Done!': '即将完成!',
'Set a password to encrypt your key, or skip to finish': '设置密码来加密你的密钥,或跳过以完成',
'Password Protection (Optional)': '密码保护(可选)',
'Setting a password encrypts your private key in this browser. You can skip this step, but we recommend setting one for added security.':
'设置密码会在此浏览器中加密你的私钥。你可以跳过此步骤,但我们建议设置密码以增强安全性。',
'Password (Optional)': '密码(可选)',
'Enter password or leave empty to skip': '输入密码或留空以跳过',
'Confirm Password': '确认密码',
'Re-enter password': '重新输入密码',
'Passwords do not match': '密码不匹配',
'Finish Signup': '完成注册',
// New improved signup copy
'Create Your Nostr Account': '创建你的 Nostr 账户',
'Generate your unique private key. This is your digital identity.':
'生成你的专属私钥。这是你的数字身份。',
'Critical: Save Your Private Key': '重要:保存你的私钥',
'Your private key IS your account. There is no password recovery. If you lose it, you lose your account forever. Please save it in a secure location.':
'你的私钥就是你的账户。没有密码找回功能。如果丢失,你将永远失去你的账户。请将其保存在安全的地方。',
'I have safely backed up my private key': '我已安全备份我的私钥',
'Secure Your Account': '保护你的账户',
'Add an extra layer of protection with a password': '使用密码添加额外的保护层',
'Password Protection (Recommended)': '密码保护(推荐)',
'Add a password to encrypt your private key in this browser. This is optional but strongly recommended for better security.':
'添加密码以在此浏览器中加密你的私钥。这是可选的,但强烈建议设置以获得更好的安全性。',
'Create a password (or skip)': '创建密码(或跳过)',
'Enter your password again': '再次输入你的密码',
'Complete Signup': '完成注册'
}
}

View File

@@ -1,28 +1,79 @@
import NormalFeed from '@/components/NormalFeed'
import { useFeed } from '@/providers/FeedProvider'
import { Button } from '@/components/ui/button'
import { usePrimaryPage } from '@/PageManager'
import { useFollowList } from '@/providers/FollowListProvider'
import { useNostr } from '@/providers/NostrProvider'
import client from '@/services/client.service'
import { TFeedSubRequest } from '@/types'
import { useEffect, useState } from 'react'
import { Compass, Search, UserPlus } from 'lucide-react'
import { useEffect, useRef, useState } from 'react'
import { useTranslation } from 'react-i18next'
export default function FollowingFeed() {
const { t } = useTranslation()
const { pubkey } = useNostr()
const { feedInfo } = useFeed()
const { followingSet } = useFollowList()
const { navigate } = usePrimaryPage()
const [subRequests, setSubRequests] = useState<TFeedSubRequest[]>([])
const [hasFollowings, setHasFollowings] = useState<boolean | null>(null)
const [refreshCount, setRefreshCount] = useState(0)
const initializedRef = useRef(false)
useEffect(() => {
if (initializedRef.current) return
async function init() {
if (feedInfo?.feedType !== 'following' || !pubkey) {
if (!pubkey) {
setSubRequests([])
setHasFollowings(null)
return
}
const followings = await client.fetchFollowings(pubkey)
setHasFollowings(followings.length > 0)
setSubRequests(await client.generateSubRequestsForPubkeys([pubkey, ...followings], pubkey))
if (followings.length) {
initializedRef.current = true
}
}
init()
}, [feedInfo?.feedType, pubkey])
}, [pubkey, followingSet, refreshCount])
return <NormalFeed subRequests={subRequests} isMainFeed />
// Show empty state when user has no followings
if (hasFollowings === false && subRequests.length > 0) {
return (
<div className="flex flex-col items-center justify-center min-h-[60vh] px-6 text-center">
<UserPlus size={64} className="text-muted-foreground mb-4" strokeWidth={1.5} />
<h2 className="text-2xl font-semibold mb-2">{t('Welcome to Jumble!')}</h2>
<p className="text-muted-foreground mb-6 max-w-md">
{t(
'Your feed is empty because you are not following anyone yet. Start by exploring interesting content and following users you like!'
)}
</p>
<div className="flex flex-col sm:flex-row gap-3 w-full max-w-md">
<Button size="lg" onClick={() => navigate('explore')} className="w-full">
<Compass className="size-5" />
{t('Explore')}
</Button>
<Button size="lg" variant="outline" onClick={() => navigate('search')} className="w-full">
<Search className="size-5" />
{t('Search Users')}
</Button>
</div>
</div>
)
}
return (
<NormalFeed
subRequests={subRequests}
onRefresh={() => {
initializedRef.current = false
setRefreshCount((count) => count + 1)
}}
isMainFeed
/>
)
}

View File

@@ -1,5 +1,4 @@
import NormalFeed from '@/components/NormalFeed'
import { useFeed } from '@/providers/FeedProvider'
import { useNostr } from '@/providers/NostrProvider'
import { usePinnedUsers } from '@/providers/PinnedUsersProvider'
import client from '@/services/client.service'
@@ -8,7 +7,6 @@ import { useEffect, useRef, useState } from 'react'
export default function PinnedFeed() {
const { pubkey } = useNostr()
const { feedInfo } = useFeed()
const { pinnedPubkeySet } = usePinnedUsers()
const [subRequests, setSubRequests] = useState<TFeedSubRequest[]>([])
const initializedRef = useRef(false)
@@ -17,7 +15,7 @@ export default function PinnedFeed() {
if (initializedRef.current) return
async function init() {
if (feedInfo?.feedType !== 'pinned' || !pubkey || pinnedPubkeySet.size === 0) {
if (!pubkey || pinnedPubkeySet.size === 0) {
setSubRequests([])
return
}
@@ -28,7 +26,7 @@ export default function PinnedFeed() {
}
init()
}, [feedInfo?.feedType, pubkey, pinnedPubkeySet])
}, [pubkey, pinnedPubkeySet])
return <NormalFeed subRequests={subRequests} isMainFeed />
}

View File

@@ -5,7 +5,7 @@ import relayInfoService from '@/services/relay-info.service'
import { useEffect, useState } from 'react'
export default function RelaysFeed() {
const { feedInfo, relayUrls } = useFeed()
const { relayUrls } = useFeed()
const [isReady, setIsReady] = useState(false)
const [areAlgoRelays, setAreAlgoRelays] = useState(false)
@@ -22,10 +22,6 @@ export default function RelaysFeed() {
return null
}
if (!feedInfo || (feedInfo.feedType !== 'relay' && feedInfo.feedType !== 'relays')) {
return null
}
return (
<NormalFeed
subRequests={[{ urls: relayUrls, filter: {} }]}

View File

@@ -199,7 +199,7 @@ function WelcomeGuide() {
<div className="flex flex-col sm:flex-row gap-3 w-full max-w-md">
<Button size="lg" className="w-full" onClick={() => navigate('explore')}>
<Compass className="size-5" />
{t('Explore Relays')}
{t('Explore')}
</Button>
<Button size="lg" className="w-full" variant="outline" onClick={() => checkLogin()}>

View File

@@ -1,5 +1,5 @@
import LoginDialog from '@/components/LoginDialog'
import { ApplicationDataKey, BIG_RELAY_URLS, ExtendedKind } from '@/constants'
import { ApplicationDataKey, BIG_RELAY_URLS, ExtendedKind, NEW_USER_RELAY_LIST } from '@/constants'
import {
createDeletionRequestDraftEvent,
createFollowListDraftEvent,
@@ -614,14 +614,13 @@ export function NostrProvider({ children }: { children: React.ReactNode }) {
}
const setupNewUser = async (signer: ISigner) => {
const relays = NEW_USER_RELAY_LIST.map((item) => item.url)
await Promise.allSettled([
client.publishEvent(BIG_RELAY_URLS, await signer.signEvent(createFollowListDraftEvent([]))),
client.publishEvent(BIG_RELAY_URLS, await signer.signEvent(createMuteListDraftEvent([]))),
client.publishEvent(relays, await signer.signEvent(createFollowListDraftEvent([]))),
client.publishEvent(relays, await signer.signEvent(createMuteListDraftEvent([]))),
client.publishEvent(
BIG_RELAY_URLS,
await signer.signEvent(
createRelayListDraftEvent(BIG_RELAY_URLS.map((url) => ({ url, scope: 'both' })))
)
relays.concat(BIG_RELAY_URLS),
await signer.signEvent(createRelayListDraftEvent(NEW_USER_RELAY_LIST))
)
])
}