Rework login modal: translations, layout, and UX

Overhaul AuthDialog's login step:
- Add translation keys for every previously-hardcoded string (titles,
  buttons, placeholders, status labels, validation/errors) across all
  sixteen locales.
- The secret-key form is no longer collapsible — it's always open and is
  the first option, followed by 'Log in with extension', then a
  text-with-arrow link to the remote-signer step.
- Move the key-file upload icon onto the same row as the nsec input
  (instead of beside the submit button); submit button is now full-width
  below.
- Surface extension-login errors as a destructive toast rather than
  writing them into the nsec input's inline error.
- Replace the centered 'Back' text buttons with a back arrow in the
  top-left of the dialog header.

Also correct AGENTS.md's i18n section: the project ships fifteen
non-English locales (hi, id, sw, tr, zh-Hant were missing from the list).
This commit is contained in:
lemon
2026-06-21 00:08:52 -07:00
parent b01f573bf9
commit 97f5f82b05
18 changed files with 560 additions and 142 deletions
+109 -123
View File
@@ -3,12 +3,14 @@ import {
Upload,
ChevronDown,
ChevronUp,
ArrowLeft,
ArrowRight,
Loader2,
ExternalLink,
} from 'lucide-react';
import { Button } from '@/components/ui/button';
import { Input } from '@/components/ui/input';
import { Dialog, DialogContent, DialogHeader, DialogTitle } from '@/components/ui/dialog';
import { Dialog, DialogContent, DialogTitle } from '@/components/ui/dialog';
import {
Collapsible,
CollapsibleContent,
@@ -26,8 +28,10 @@ import {
type NostrConnectStatus,
} from '@/hooks/useLoginActions';
import { useIsMobile } from '@/hooks/useIsMobile';
import { useToast } from '@/hooks/useToast';
import { useOnboarding } from '@/contexts/onboardingContextDef';
import { useTranslation } from 'react-i18next';
import { cn } from '@/lib/utils';
interface AuthDialogProps {
isOpen: boolean;
@@ -45,17 +49,6 @@ type Step = 'welcome' | 'login' | 'connect';
const validateNsec = (nsec: string) => /^nsec1[a-zA-Z0-9]{58}$/.test(nsec);
const validateBunkerUri = (uri: string) => uri.startsWith('bunker://');
const connectStatusLabel = (status: NostrConnectStatus | null): string => {
switch (status) {
case 'awaiting-connect':
return 'Waiting for signer connection…';
case 'getting-public-key':
return 'Getting public key…';
default:
return '';
}
};
/** Check if running on an actual mobile device (not just a small screen). */
function isMobileDevice(): boolean {
if (typeof navigator === 'undefined') return false;
@@ -69,7 +62,6 @@ const AuthDialog: React.FC<AuthDialogProps> = ({ isOpen, onClose }) => {
const [loginNsec, setLoginNsec] = useState('');
const [isLoggingIn, setIsLoggingIn] = useState(false);
const [loginError, setLoginError] = useState('');
const [showMoreOptions, setShowMoreOptions] = useState(false);
// Nostrconnect / bunker state
const [nostrConnectParams, setNostrConnectParams] = useState<NostrConnectParams | null>(null);
@@ -93,7 +85,19 @@ const AuthDialog: React.FC<AuthDialogProps> = ({ isOpen, onClose }) => {
const login = useLoginActions();
const { config } = useAppContext();
const { startSignup } = useOnboarding();
const { toast } = useToast();
const { t } = useTranslation();
const connectStatusLabel = (status: NostrConnectStatus | null): string => {
switch (status) {
case 'awaiting-connect':
return t('auth.waitingForSigner');
case 'getting-public-key':
return t('auth.gettingPublicKey');
default:
return '';
}
};
// Stable refs so the nostrconnect listening effect below doesn't restart on
// every parent render. Parents typically pass inline arrow functions for
// onClose, and useLoginActions returns a fresh object each render — without
@@ -125,7 +129,6 @@ const AuthDialog: React.FC<AuthDialogProps> = ({ isOpen, onClose }) => {
setLoginNsec('');
setIsLoggingIn(false);
setLoginError('');
setShowMoreOptions(false);
setNostrConnectParams(null);
setNostrConnectUri('');
setConnectError(null);
@@ -228,7 +231,7 @@ const AuthDialog: React.FC<AuthDialogProps> = ({ isOpen, onClose }) => {
await login.bunker(bunkerUri);
onClose();
} catch {
setConnectError('Failed to connect. Check the bunker URI.');
setConnectError(t('auth.errorBunkerConnect'));
setIsLoggingIn(false);
}
};
@@ -255,11 +258,11 @@ const AuthDialog: React.FC<AuthDialogProps> = ({ isOpen, onClose }) => {
// Login: submit the entered nsec.
const handleLogin = () => {
if (!loginNsec.trim()) {
setLoginError('Enter your secret key.');
setLoginError(t('auth.errorEnterSecretKey'));
return;
}
if (!validateNsec(loginNsec)) {
setLoginError('Invalid secret key. Must start with nsec1.');
setLoginError(t('auth.errorInvalidSecretKey'));
return;
}
@@ -271,7 +274,7 @@ const AuthDialog: React.FC<AuthDialogProps> = ({ isOpen, onClose }) => {
login.nsec(loginNsec);
onClose();
} catch {
setLoginError("Couldn't log in with this key.");
setLoginError(t('auth.errorLoginFailed'));
setIsLoggingIn(false);
}
}, 50);
@@ -287,10 +290,10 @@ const AuthDialog: React.FC<AuthDialogProps> = ({ isOpen, onClose }) => {
if (content && validateNsec(content.trim())) {
setLoginNsec(content.trim());
} else {
setLoginError('File does not contain a valid secret key.');
setLoginError(t('auth.errorFileNoKey'));
}
};
reader.onerror = () => setLoginError('Failed to read file.');
reader.onerror = () => setLoginError(t('auth.errorFileRead'));
reader.readAsText(file);
};
@@ -301,7 +304,11 @@ const AuthDialog: React.FC<AuthDialogProps> = ({ isOpen, onClose }) => {
await login.extension();
onClose();
} catch (e) {
setLoginError(e instanceof Error ? e.message : 'Extension login failed.');
toast({
variant: 'destructive',
title: t('auth.extensionErrorTitle'),
description: e instanceof Error ? e.message : t('auth.errorExtensionFailed'),
});
setIsLoggingIn(false);
}
};
@@ -309,9 +316,9 @@ const AuthDialog: React.FC<AuthDialogProps> = ({ isOpen, onClose }) => {
const getTitle = () => {
switch (step) {
case 'login':
return 'Log in';
return t('auth.loginTitle');
case 'connect':
return 'Connect signer';
return t('auth.connectSignerTitle');
default:
return '';
}
@@ -367,85 +374,57 @@ const AuthDialog: React.FC<AuthDialogProps> = ({ isOpen, onClose }) => {
</div>
) : (
<>
<DialogHeader className="px-6 pt-6">
<DialogTitle className="text-lg font-semibold leading-none tracking-tight text-center">
<div className="relative px-6 pt-6">
<button
type="button"
onClick={() => setStep(step === 'connect' ? 'login' : 'welcome')}
aria-label={t('auth.back')}
className="absolute left-4 top-5 size-9 rounded-full flex items-center justify-center text-muted-foreground hover:text-foreground hover:bg-secondary motion-safe:transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary"
>
<ArrowLeft className="size-5 rtl:rotate-180" />
</button>
<DialogTitle className="text-lg font-semibold leading-none tracking-tight text-center px-9">
{getTitle()}
</DialogTitle>
</DialogHeader>
</div>
<div className="px-6 pb-6 pt-4 space-y-5">
{/* Login step. */}
{/* Login step. The secret-key form is always visible and first,
followed by the extension button (when available), then a
text link out to the remote-signer (connect) step. */}
{step === 'login' && (
<div className="space-y-4">
{hasExtension ? (
<>
<Button
onClick={handleExtensionLogin}
disabled={isLoggingIn}
className="w-full h-12"
>
{isLoggingIn ? 'Logging in…' : 'Log in with extension'}
</Button>
<NsecLoginForm
loginNsec={loginNsec}
setLoginNsec={setLoginNsec}
loginError={loginError}
setLoginError={setLoginError}
isLoggingIn={isLoggingIn}
onSubmit={handleLogin}
onFileChange={handleFileUpload}
fileInputRef={fileInputRef}
t={t}
/>
<Button
variant="outline"
onClick={goToConnect}
className="w-full h-12"
>
Use remote signer
</Button>
<Collapsible open={showMoreOptions} onOpenChange={setShowMoreOptions}>
<CollapsibleTrigger className="w-full flex items-center justify-center gap-1 text-sm text-muted-foreground hover:text-foreground py-2">
<span>Use secret key</span>
<ChevronDown
className={`w-4 h-4 transition-transform ${
showMoreOptions ? 'rotate-180' : ''
}`}
/>
</CollapsibleTrigger>
<CollapsibleContent className="space-y-3 pt-1">
<NsecLoginForm
loginNsec={loginNsec}
setLoginNsec={setLoginNsec}
loginError={loginError}
setLoginError={setLoginError}
isLoggingIn={isLoggingIn}
onSubmit={handleLogin}
onFileChange={handleFileUpload}
fileInputRef={fileInputRef}
/>
</CollapsibleContent>
</Collapsible>
</>
) : (
<>
<NsecLoginForm
loginNsec={loginNsec}
setLoginNsec={setLoginNsec}
loginError={loginError}
setLoginError={setLoginError}
isLoggingIn={isLoggingIn}
onSubmit={handleLogin}
onFileChange={handleFileUpload}
fileInputRef={fileInputRef}
/>
<Button
variant="outline"
onClick={goToConnect}
className="w-full"
>
Use remote signer
</Button>
</>
{hasExtension && (
<Button
variant="outline"
onClick={handleExtensionLogin}
disabled={isLoggingIn}
className="w-full h-12"
>
{isLoggingIn ? t('auth.loggingIn') : t('auth.loginWithExtension')}
</Button>
)}
<button
onClick={() => setStep('welcome')}
className="w-full text-sm text-muted-foreground hover:text-foreground"
type="button"
onClick={goToConnect}
className="w-full flex items-center justify-center gap-1 text-sm text-muted-foreground hover:text-foreground motion-safe:transition-colors py-2"
>
Back
<span>{t('auth.useRemoteSigner')}</span>
<ArrowRight className="w-4 h-4 rtl:rotate-180" />
</button>
</div>
)}
@@ -458,7 +437,7 @@ const AuthDialog: React.FC<AuthDialogProps> = ({ isOpen, onClose }) => {
<div className="flex flex-col items-center space-y-3 py-4">
<p className="text-sm text-destructive text-center">{connectError}</p>
<Button variant="outline" onClick={handleConnectRetry}>
Try again
{t('auth.tryAgain')}
</Button>
</div>
) : showProgressView ? (
@@ -476,7 +455,7 @@ const AuthDialog: React.FC<AuthDialogProps> = ({ isOpen, onClose }) => {
onClick={handleConnectRetry}
className="text-sm text-primary hover:underline underline-offset-4 font-medium"
>
Cancel
{t('auth.cancel')}
</button>
</div>
) : nostrConnectUri ? (
@@ -490,7 +469,7 @@ const AuthDialog: React.FC<AuthDialogProps> = ({ isOpen, onClose }) => {
{isMobile && (
<Button onClick={handleOpenSignerApp} className="w-full h-12">
<ExternalLink className="w-5 h-5 mr-2" />
Open signer app
{t('auth.openSignerApp')}
</Button>
)}
</>
@@ -504,7 +483,7 @@ const AuthDialog: React.FC<AuthDialogProps> = ({ isOpen, onClose }) => {
{/* Manual bunker URI fallback. */}
<Collapsible open={showBunkerInput} onOpenChange={setShowBunkerInput}>
<CollapsibleTrigger className="w-full flex items-center justify-center gap-1 text-sm text-muted-foreground hover:text-foreground py-2">
<span>Enter bunker URI manually</span>
<span>{t('auth.enterBunkerManually')}</span>
{showBunkerInput ? (
<ChevronUp className="w-4 h-4" />
) : (
@@ -515,12 +494,12 @@ const AuthDialog: React.FC<AuthDialogProps> = ({ isOpen, onClose }) => {
<Input
value={bunkerUri}
onChange={(e) => setBunkerUri(e.target.value)}
placeholder="bunker://…"
placeholder={t('auth.bunkerPlaceholder')}
className="text-base md:text-sm"
/>
{bunkerUri && !validateBunkerUri(bunkerUri) && (
<Alert variant="destructive">
<AlertDescription>Invalid bunker URI format.</AlertDescription>
<AlertDescription>{t('auth.invalidBunkerFormat')}</AlertDescription>
</Alert>
)}
<Button
@@ -531,17 +510,10 @@ const AuthDialog: React.FC<AuthDialogProps> = ({ isOpen, onClose }) => {
}
className="w-full"
>
{isLoggingIn ? 'Connecting' : 'Connect'}
{isLoggingIn ? t('auth.connecting') : t('auth.connect')}
</Button>
</CollapsibleContent>
</Collapsible>
<button
onClick={() => setStep('login')}
className="w-full text-sm text-muted-foreground hover:text-foreground"
>
Back
</button>
</div>
)}
</div>
@@ -562,6 +534,7 @@ interface NsecLoginFormProps {
onSubmit: () => void;
onFileChange: (e: React.ChangeEvent<HTMLInputElement>) => void;
fileInputRef: React.RefObject<HTMLInputElement | null>;
t: (key: string) => string;
}
const NsecLoginForm: React.FC<NsecLoginFormProps> = ({
@@ -573,6 +546,7 @@ const NsecLoginForm: React.FC<NsecLoginFormProps> = ({
onSubmit,
onFileChange,
fileInputRef,
t,
}) => (
<form
onSubmit={(e) => {
@@ -582,27 +556,26 @@ const NsecLoginForm: React.FC<NsecLoginFormProps> = ({
className="space-y-3"
data-nsec-allowed
>
<Input
type="password"
value={loginNsec}
onChange={(e) => {
setLoginNsec(e.target.value);
if (loginError) setLoginError('');
}}
placeholder="nsec1…"
autoComplete="off"
className={loginError ? 'border-destructive focus-visible:ring-destructive' : ''}
/>
{loginError && <p className="text-sm text-destructive">{loginError}</p>}
<span className="block text-sm font-medium text-foreground">
{t('auth.secretKeyLabel')}
</span>
{/* nsec input and the key-file upload icon share a row. */}
<div className="flex gap-2">
<Button
type="submit"
disabled={isLoggingIn || !loginNsec.trim()}
className="flex-1"
>
{isLoggingIn ? 'Logging in…' : 'Log in'}
</Button>
<Input
type="password"
value={loginNsec}
onChange={(e) => {
setLoginNsec(e.target.value);
if (loginError) setLoginError('');
}}
placeholder={t('auth.nsecPlaceholder')}
autoComplete="off"
className={cn(
'flex-1',
loginError && 'border-destructive focus-visible:ring-destructive',
)}
/>
<input
type="file"
accept=".txt"
@@ -614,11 +587,24 @@ const NsecLoginForm: React.FC<NsecLoginFormProps> = ({
type="button"
variant="outline"
size="icon"
className="shrink-0"
aria-label={t('auth.uploadKeyFile')}
title={t('auth.uploadKeyFile')}
onClick={() => fileInputRef.current?.click()}
>
<Upload className="w-4 h-4" />
</Button>
</div>
{loginError && <p className="text-sm text-destructive">{loginError}</p>}
<Button
type="submit"
disabled={isLoggingIn || !loginNsec.trim()}
className="w-full h-12"
>
{isLoggingIn ? t('auth.loggingIn') : t('auth.login')}
</Button>
</form>
);
+28 -1
View File
@@ -131,7 +131,34 @@
"logout": "تسجيل الخروج",
"addAccount": "إضافة حساب آخر",
"createNewAccount": "إنشاء حساب جديد",
"loginExisting": "تسجيل الدخول بحساب موجود"
"loginExisting": "تسجيل الدخول بحساب موجود",
"loginTitle": "تسجيل الدخول",
"connectSignerTitle": "ربط أداة التوقيع",
"back": "رجوع",
"secretKeyLabel": "استخدام المفتاح السري",
"nsecPlaceholder": "nsec1…",
"uploadKeyFile": "رفع ملف المفتاح",
"loggingIn": "جارٍ تسجيل الدخول…",
"loginWithExtension": "تسجيل الدخول باستخدام إضافة",
"useRemoteSigner": "استخدام أداة توقيع عن بُعد",
"tryAgain": "حاول مرة أخرى",
"cancel": "إلغاء",
"openSignerApp": "فتح تطبيق التوقيع",
"enterBunkerManually": "إدخال رابط البنكر يدويًا",
"bunkerPlaceholder": "bunker://…",
"invalidBunkerFormat": "صيغة رابط البنكر غير صالحة.",
"connecting": "جارٍ الاتصال…",
"connect": "اتصال",
"waitingForSigner": "في انتظار اتصال أداة التوقيع…",
"gettingPublicKey": "جارٍ الحصول على المفتاح العام…",
"errorEnterSecretKey": "أدخل مفتاحك السري.",
"errorInvalidSecretKey": "مفتاح سري غير صالح. يجب أن يبدأ بـ nsec1.",
"errorLoginFailed": "تعذّر تسجيل الدخول بهذا المفتاح.",
"errorFileNoKey": "الملف لا يحتوي على مفتاح سري صالح.",
"errorFileRead": "فشل في قراءة الملف.",
"errorExtensionFailed": "فشل تسجيل الدخول باستخدام الإضافة.",
"errorBunkerConnect": "فشل الاتصال. تحقق من رابط البنكر.",
"extensionErrorTitle": "فشل تسجيل الدخول باستخدام الإضافة"
},
"onboarding": {
"ariaLabel": "إعداد الحساب",
+28 -1
View File
@@ -132,7 +132,34 @@
"logout": "Log out",
"addAccount": "Add another account",
"createNewAccount": "Create new account",
"loginExisting": "Log in with existing"
"loginExisting": "Log in with existing",
"loginTitle": "Log in",
"connectSignerTitle": "Connect signer",
"back": "Back",
"secretKeyLabel": "Use secret key",
"nsecPlaceholder": "nsec1…",
"uploadKeyFile": "Upload key file",
"loggingIn": "Logging in…",
"loginWithExtension": "Log in with extension",
"useRemoteSigner": "Use a remote signer",
"tryAgain": "Try again",
"cancel": "Cancel",
"openSignerApp": "Open signer app",
"enterBunkerManually": "Enter bunker URI manually",
"bunkerPlaceholder": "bunker://…",
"invalidBunkerFormat": "Invalid bunker URI format.",
"connecting": "Connecting…",
"connect": "Connect",
"waitingForSigner": "Waiting for signer connection…",
"gettingPublicKey": "Getting public key…",
"errorEnterSecretKey": "Enter your secret key.",
"errorInvalidSecretKey": "Invalid secret key. Must start with nsec1.",
"errorLoginFailed": "Couldn't log in with this key.",
"errorFileNoKey": "File does not contain a valid secret key.",
"errorFileRead": "Failed to read file.",
"errorExtensionFailed": "Extension login failed.",
"errorBunkerConnect": "Failed to connect. Check the bunker URI.",
"extensionErrorTitle": "Extension login failed"
},
"onboarding": {
"ariaLabel": "Account setup",
+28 -1
View File
@@ -131,7 +131,34 @@
"logout": "Cerrar sesión",
"addAccount": "Agregar otra cuenta",
"createNewAccount": "Crear cuenta nueva",
"loginExisting": "Iniciar sesión con una existente"
"loginExisting": "Iniciar sesión con una existente",
"loginTitle": "Iniciar sesión",
"connectSignerTitle": "Conectar firmante",
"back": "Atrás",
"secretKeyLabel": "Usar clave secreta",
"nsecPlaceholder": "nsec1…",
"uploadKeyFile": "Subir archivo de clave",
"loggingIn": "Iniciando sesión…",
"loginWithExtension": "Iniciar sesión con extensión",
"useRemoteSigner": "Usar un firmante remoto",
"tryAgain": "Intentar de nuevo",
"cancel": "Cancelar",
"openSignerApp": "Abrir aplicación de firma",
"enterBunkerManually": "Introducir URI de bunker manualmente",
"bunkerPlaceholder": "bunker://…",
"invalidBunkerFormat": "Formato de URI de bunker no válido.",
"connecting": "Conectando…",
"connect": "Conectar",
"waitingForSigner": "Esperando la conexión del firmante…",
"gettingPublicKey": "Obteniendo clave pública…",
"errorEnterSecretKey": "Introduce tu clave secreta.",
"errorInvalidSecretKey": "Clave secreta no válida. Debe empezar con nsec1.",
"errorLoginFailed": "No se pudo iniciar sesión con esta clave.",
"errorFileNoKey": "El archivo no contiene una clave secreta válida.",
"errorFileRead": "No se pudo leer el archivo.",
"errorExtensionFailed": "Error al iniciar sesión con la extensión.",
"errorBunkerConnect": "No se pudo conectar. Comprueba el URI del bunker.",
"extensionErrorTitle": "Error al iniciar sesión con la extensión"
},
"onboarding": {
"ariaLabel": "Configuración de la cuenta",
+28 -1
View File
@@ -131,7 +131,34 @@
"logout": "خروج",
"addAccount": "افزودن حساب دیگر",
"createNewAccount": "ایجاد حساب جدید",
"loginExisting": "ورود با حساب موجود"
"loginExisting": "ورود با حساب موجود",
"loginTitle": "ورود",
"connectSignerTitle": "اتصال امضاکننده",
"back": "بازگشت",
"secretKeyLabel": "استفاده از کلید مخفی",
"nsecPlaceholder": "nsec1…",
"uploadKeyFile": "بارگذاری فایل کلید",
"loggingIn": "در حال ورود…",
"loginWithExtension": "ورود با افزونه",
"useRemoteSigner": "استفاده از امضاکننده راه دور",
"tryAgain": "تلاش دوباره",
"cancel": "لغو",
"openSignerApp": "باز کردن برنامه امضاکننده",
"enterBunkerManually": "وارد کردن دستی نشانی bunker",
"bunkerPlaceholder": "bunker://…",
"invalidBunkerFormat": "قالب نشانی bunker نامعتبر است.",
"connecting": "در حال اتصال…",
"connect": "اتصال",
"waitingForSigner": "در انتظار اتصال امضاکننده…",
"gettingPublicKey": "در حال دریافت کلید عمومی…",
"errorEnterSecretKey": "کلید مخفی خود را وارد کنید.",
"errorInvalidSecretKey": "کلید مخفی نامعتبر است. باید با nsec1 شروع شود.",
"errorLoginFailed": "ورود با این کلید ممکن نشد.",
"errorFileNoKey": "فایل حاوی کلید مخفی معتبری نیست.",
"errorFileRead": "خواندن فایل ناموفق بود.",
"errorExtensionFailed": "ورود با افزونه ناموفق بود.",
"errorBunkerConnect": "اتصال ناموفق بود. نشانی bunker را بررسی کنید.",
"extensionErrorTitle": "ورود با افزونه ناموفق بود"
},
"onboarding": {
"ariaLabel": "راه‌اندازی حساب",
+28 -1
View File
@@ -131,7 +131,34 @@
"logout": "Se déconnecter",
"addAccount": "Ajouter un autre compte",
"createNewAccount": "Créer un compte",
"loginExisting": "Se connecter avec un compte existant"
"loginExisting": "Se connecter avec un compte existant",
"loginTitle": "Se connecter",
"connectSignerTitle": "Connecter le signataire",
"back": "Retour",
"secretKeyLabel": "Utiliser la clé secrète",
"nsecPlaceholder": "nsec1…",
"uploadKeyFile": "Importer un fichier de clé",
"loggingIn": "Connexion…",
"loginWithExtension": "Se connecter avec l'extension",
"useRemoteSigner": "Utiliser un signataire distant",
"tryAgain": "Réessayer",
"cancel": "Annuler",
"openSignerApp": "Ouvrir l'application de signature",
"enterBunkerManually": "Saisir l'URI bunker manuellement",
"bunkerPlaceholder": "bunker://…",
"invalidBunkerFormat": "Format d'URI bunker invalide.",
"connecting": "Connexion…",
"connect": "Connecter",
"waitingForSigner": "En attente de la connexion du signataire…",
"gettingPublicKey": "Récupération de la clé publique…",
"errorEnterSecretKey": "Saisissez votre clé secrète.",
"errorInvalidSecretKey": "Clé secrète invalide. Elle doit commencer par nsec1.",
"errorLoginFailed": "Impossible de se connecter avec cette clé.",
"errorFileNoKey": "Le fichier ne contient pas de clé secrète valide.",
"errorFileRead": "Échec de la lecture du fichier.",
"errorExtensionFailed": "Échec de la connexion par extension.",
"errorBunkerConnect": "Échec de la connexion. Vérifiez l'URI bunker.",
"extensionErrorTitle": "Échec de la connexion par extension"
},
"onboarding": {
"ariaLabel": "Configuration du compte",
+28 -1
View File
@@ -131,7 +131,34 @@
"logout": "लॉग आउट करें",
"addAccount": "एक और अकाउंट जोड़ें",
"createNewAccount": "नया खाता बनाएँ",
"loginExisting": "मौजूदा खाते से लॉग इन करें"
"loginExisting": "मौजूदा खाते से लॉग इन करें",
"loginTitle": "लॉग इन करें",
"connectSignerTitle": "साइनर कनेक्ट करें",
"back": "वापस",
"secretKeyLabel": "गुप्त कुंजी का उपयोग करें",
"nsecPlaceholder": "nsec1…",
"uploadKeyFile": "कुंजी फ़ाइल अपलोड करें",
"loggingIn": "लॉग इन हो रहा है…",
"loginWithExtension": "एक्सटेंशन से लॉग इन करें",
"useRemoteSigner": "रिमोट साइनर का उपयोग करें",
"tryAgain": "पुनः प्रयास करें",
"cancel": "रद्द करें",
"openSignerApp": "साइनर ऐप खोलें",
"enterBunkerManually": "बंकर URI मैन्युअल रूप से दर्ज करें",
"bunkerPlaceholder": "bunker://…",
"invalidBunkerFormat": "अमान्य बंकर URI प्रारूप।",
"connecting": "कनेक्ट हो रहा है…",
"connect": "कनेक्ट करें",
"waitingForSigner": "साइनर कनेक्शन की प्रतीक्षा हो रही है…",
"gettingPublicKey": "सार्वजनिक कुंजी प्राप्त हो रही है…",
"errorEnterSecretKey": "अपनी गुप्त कुंजी दर्ज करें।",
"errorInvalidSecretKey": "अमान्य गुप्त कुंजी। इसे nsec1 से शुरू होना चाहिए।",
"errorLoginFailed": "इस कुंजी से लॉग इन नहीं हो सका।",
"errorFileNoKey": "फ़ाइल में मान्य गुप्त कुंजी नहीं है।",
"errorFileRead": "फ़ाइल पढ़ने में विफल।",
"errorExtensionFailed": "एक्सटेंशन लॉगिन विफल।",
"errorBunkerConnect": "कनेक्ट करने में विफल। बंकर URI जाँचें।",
"extensionErrorTitle": "एक्सटेंशन लॉगिन विफल"
},
"onboarding": {
"ariaLabel": "अकाउंट सेटअप",
+28 -1
View File
@@ -131,7 +131,34 @@
"logout": "Keluar",
"addAccount": "Tambah akun lain",
"createNewAccount": "Buat akun baru",
"loginExisting": "Masuk dengan akun yang ada"
"loginExisting": "Masuk dengan akun yang ada",
"loginTitle": "Masuk",
"connectSignerTitle": "Hubungkan penanda tangan",
"back": "Kembali",
"secretKeyLabel": "Gunakan kunci rahasia",
"nsecPlaceholder": "nsec1…",
"uploadKeyFile": "Unggah berkas kunci",
"loggingIn": "Sedang masuk…",
"loginWithExtension": "Masuk dengan ekstensi",
"useRemoteSigner": "Gunakan penanda tangan jarak jauh",
"tryAgain": "Coba lagi",
"cancel": "Batal",
"openSignerApp": "Buka aplikasi penanda tangan",
"enterBunkerManually": "Masukkan URI bunker secara manual",
"bunkerPlaceholder": "bunker://…",
"invalidBunkerFormat": "Format URI bunker tidak valid.",
"connecting": "Menghubungkan…",
"connect": "Hubungkan",
"waitingForSigner": "Menunggu koneksi penanda tangan…",
"gettingPublicKey": "Mengambil kunci publik…",
"errorEnterSecretKey": "Masukkan kunci rahasia Anda.",
"errorInvalidSecretKey": "Kunci rahasia tidak valid. Harus diawali dengan nsec1.",
"errorLoginFailed": "Tidak dapat masuk dengan kunci ini.",
"errorFileNoKey": "Berkas tidak berisi kunci rahasia yang valid.",
"errorFileRead": "Gagal membaca berkas.",
"errorExtensionFailed": "Login ekstensi gagal.",
"errorBunkerConnect": "Gagal menghubungkan. Periksa URI bunker.",
"extensionErrorTitle": "Login ekstensi gagal"
},
"onboarding": {
"ariaLabel": "Penyiapan akun",
+28 -1
View File
@@ -131,7 +131,34 @@
"logout": "ចេញពីគណនី",
"addAccount": "បន្ថែមគណនីផ្សេងទៀត",
"createNewAccount": "បង្កើតគណនីថ្មី",
"loginExisting": "ចូលដោយគណនីដែលមានស្រាប់"
"loginExisting": "ចូលដោយគណនីដែលមានស្រាប់",
"loginTitle": "ចូល",
"connectSignerTitle": "ភ្ជាប់កម្មវិធីចុះហត្ថលេខា",
"back": "ត្រឡប់",
"secretKeyLabel": "ប្រើសោសម្ងាត់",
"nsecPlaceholder": "nsec1…",
"uploadKeyFile": "ផ្ទុកឯកសារសោឡើង",
"loggingIn": "កំពុងចូល…",
"loginWithExtension": "ចូលដោយផ្នែកបន្ថែម",
"useRemoteSigner": "ប្រើកម្មវិធីចុះហត្ថលេខាពីចម្ងាយ",
"tryAgain": "ព្យាយាមម្តងទៀត",
"cancel": "បោះបង់",
"openSignerApp": "បើកកម្មវិធីចុះហត្ថលេខា",
"enterBunkerManually": "បញ្ចូល URI bunker ដោយដៃ",
"bunkerPlaceholder": "bunker://…",
"invalidBunkerFormat": "ទម្រង់ URI bunker មិនត្រឹមត្រូវ។",
"connecting": "កំពុងភ្ជាប់…",
"connect": "ភ្ជាប់",
"waitingForSigner": "កំពុងរង់ចាំការភ្ជាប់កម្មវិធីចុះហត្ថលេខា…",
"gettingPublicKey": "កំពុងទាញយកសោសាធារណៈ…",
"errorEnterSecretKey": "បញ្ចូលសោសម្ងាត់របស់អ្នក។",
"errorInvalidSecretKey": "សោសម្ងាត់មិនត្រឹមត្រូវ។ ត្រូវចាប់ផ្តើមដោយ nsec1។",
"errorLoginFailed": "មិនអាចចូលដោយសោនេះបានទេ។",
"errorFileNoKey": "ឯកសារមិនមានសោសម្ងាត់ត្រឹមត្រូវទេ។",
"errorFileRead": "បរាជ័យក្នុងការអានឯកសារ។",
"errorExtensionFailed": "ការចូលដោយផ្នែកបន្ថែមបានបរាជ័យ។",
"errorBunkerConnect": "បរាជ័យក្នុងការភ្ជាប់។ ពិនិត្យ URI bunker។",
"extensionErrorTitle": "ការចូលដោយផ្នែកបន្ថែមបានបរាជ័យ"
},
"onboarding": {
"ariaLabel": "ការរៀបចំគណនី",
+28 -1
View File
@@ -131,7 +131,34 @@
"logout": "وتل",
"addAccount": "بل حساب اضافه کول",
"createNewAccount": "نوی حساب جوړ کړئ",
"loginExisting": "د موجوده حساب سره ننوتل"
"loginExisting": "د موجوده حساب سره ننوتل",
"loginTitle": "ننوتل",
"connectSignerTitle": "لاسلیک کوونکی نښلول",
"back": "شاته",
"secretKeyLabel": "پټ کیلي وکاروئ",
"nsecPlaceholder": "nsec1…",
"uploadKeyFile": "د کیلي فایل پورته کول",
"loggingIn": "ننوتل کیږي…",
"loginWithExtension": "د توسیع په مرسته ننوتل",
"useRemoteSigner": "لیرې لاسلیک کوونکی وکاروئ",
"tryAgain": "بیا هڅه وکړئ",
"cancel": "لغوه کول",
"openSignerApp": "د لاسلیک کوونکي اپلیکیشن پرانیستل",
"enterBunkerManually": "د bunker URI په لاس داخل کړئ",
"bunkerPlaceholder": "bunker://…",
"invalidBunkerFormat": "د bunker URI ناسم بڼه.",
"connecting": "نښلول کیږي…",
"connect": "نښلول",
"waitingForSigner": "د لاسلیک کوونکي د نښلون په تمه…",
"gettingPublicKey": "عامه کیلي ترلاسه کیږي…",
"errorEnterSecretKey": "خپله پټه کیلي داخل کړئ.",
"errorInvalidSecretKey": "ناسمه پټه کیلي. باید په nsec1 پیل شي.",
"errorLoginFailed": "د دې کیلي سره ننوتل ونشول.",
"errorFileNoKey": "فایل کې سمه پټه کیلي نشته.",
"errorFileRead": "د فایل لوستل پاتې راغلل.",
"errorExtensionFailed": "د توسیع ننوتل پاتې راغلل.",
"errorBunkerConnect": "نښلول پاتې راغلل. د bunker URI وګورئ.",
"extensionErrorTitle": "د توسیع ننوتل پاتې راغلل"
},
"onboarding": {
"ariaLabel": "د حساب جوړونه",
+28 -1
View File
@@ -131,7 +131,34 @@
"logout": "Sair",
"addAccount": "Adicionar outra conta",
"createNewAccount": "Criar nova conta",
"loginExisting": "Entrar com uma conta existente"
"loginExisting": "Entrar com uma conta existente",
"loginTitle": "Entrar",
"connectSignerTitle": "Conectar assinador",
"back": "Voltar",
"secretKeyLabel": "Usar chave secreta",
"nsecPlaceholder": "nsec1…",
"uploadKeyFile": "Enviar arquivo de chave",
"loggingIn": "Entrando…",
"loginWithExtension": "Entrar com extensão",
"useRemoteSigner": "Usar um assinador remoto",
"tryAgain": "Tentar novamente",
"cancel": "Cancelar",
"openSignerApp": "Abrir aplicativo assinador",
"enterBunkerManually": "Inserir URI bunker manualmente",
"bunkerPlaceholder": "bunker://…",
"invalidBunkerFormat": "Formato de URI bunker inválido.",
"connecting": "Conectando…",
"connect": "Conectar",
"waitingForSigner": "Aguardando conexão do assinador…",
"gettingPublicKey": "Obtendo chave pública…",
"errorEnterSecretKey": "Insira sua chave secreta.",
"errorInvalidSecretKey": "Chave secreta inválida. Deve começar com nsec1.",
"errorLoginFailed": "Não foi possível entrar com esta chave.",
"errorFileNoKey": "O arquivo não contém uma chave secreta válida.",
"errorFileRead": "Falha ao ler o arquivo.",
"errorExtensionFailed": "Falha no login com extensão.",
"errorBunkerConnect": "Falha ao conectar. Verifique o URI bunker.",
"extensionErrorTitle": "Falha no login com extensão"
},
"onboarding": {
"ariaLabel": "Configuração da conta",
+28 -1
View File
@@ -131,7 +131,34 @@
"logout": "Выйти",
"addAccount": "Добавить ещё один аккаунт",
"createNewAccount": "Создать новый аккаунт",
"loginExisting": "Войти в существующий"
"loginExisting": "Войти в существующий",
"loginTitle": "Войти",
"connectSignerTitle": "Подключить подписывающее устройство",
"back": "Назад",
"secretKeyLabel": "Использовать секретный ключ",
"nsecPlaceholder": "nsec1…",
"uploadKeyFile": "Загрузить файл ключа",
"loggingIn": "Вход…",
"loginWithExtension": "Войти через расширение",
"useRemoteSigner": "Использовать удалённое подписывающее устройство",
"tryAgain": "Попробовать снова",
"cancel": "Отмена",
"openSignerApp": "Открыть приложение подписи",
"enterBunkerManually": "Ввести URI bunker вручную",
"bunkerPlaceholder": "bunker://…",
"invalidBunkerFormat": "Неверный формат URI bunker.",
"connecting": "Подключение…",
"connect": "Подключить",
"waitingForSigner": "Ожидание подключения подписывающего устройства…",
"gettingPublicKey": "Получение открытого ключа…",
"errorEnterSecretKey": "Введите ваш секретный ключ.",
"errorInvalidSecretKey": "Неверный секретный ключ. Должен начинаться с nsec1.",
"errorLoginFailed": "Не удалось войти с этим ключом.",
"errorFileNoKey": "Файл не содержит действительного секретного ключа.",
"errorFileRead": "Не удалось прочитать файл.",
"errorExtensionFailed": "Не удалось войти через расширение.",
"errorBunkerConnect": "Не удалось подключиться. Проверьте URI bunker.",
"extensionErrorTitle": "Не удалось войти через расширение"
},
"onboarding": {
"ariaLabel": "Настройка аккаунта",
+28 -1
View File
@@ -131,7 +131,34 @@
"logout": "Buda",
"addAccount": "Wedzera imwe akaunti",
"createNewAccount": "Gadzira account itsva",
"loginExisting": "Pinda neyiripo"
"loginExisting": "Pinda neyiripo",
"loginTitle": "Pinda",
"connectSignerTitle": "Batanidza chisaini",
"back": "Dzokera",
"secretKeyLabel": "Shandisa kiyi yakavanzika",
"nsecPlaceholder": "nsec1…",
"uploadKeyFile": "Tumira faira rekiyi",
"loggingIn": "Kupinda…",
"loginWithExtension": "Pinda neextension",
"useRemoteSigner": "Shandisa chisaini chiri kure",
"tryAgain": "Edza zvakare",
"cancel": "Kanzura",
"openSignerApp": "Vhura app yechisaini",
"enterBunkerManually": "Isa URI ye bunker pachako",
"bunkerPlaceholder": "bunker://…",
"invalidBunkerFormat": "Fomati ye URI ye bunker isina kunaka.",
"connecting": "Kubatanidza…",
"connect": "Batanidza",
"waitingForSigner": "Kumirira kubatana kwechisaini…",
"gettingPublicKey": "Kutora kiyi yeruzhinji…",
"errorEnterSecretKey": "Isa kiyi yako yakavanzika.",
"errorInvalidSecretKey": "Kiyi yakavanzika isina kunaka. Inofanira kutanga ne nsec1.",
"errorLoginFailed": "Hazvina kukwanisa kupinda nekiyi iyi.",
"errorFileNoKey": "Faira harina kiyi yakavanzika iri nani.",
"errorFileRead": "Hazvina kukwanisa kuverenga faira.",
"errorExtensionFailed": "Kupinda neextension kwakundikana.",
"errorBunkerConnect": "Hazvina kukwanisa kubatanidza. Ongorora URI ye bunker.",
"extensionErrorTitle": "Kupinda neextension kwakundikana"
},
"onboarding": {
"ariaLabel": "Kugadzira akaunti",
+28 -1
View File
@@ -131,7 +131,34 @@
"logout": "Toka",
"addAccount": "Ongeza akaunti nyingine",
"createNewAccount": "Fungua akaunti mpya",
"loginExisting": "Ingia kwa iliyopo"
"loginExisting": "Ingia kwa iliyopo",
"loginTitle": "Ingia",
"connectSignerTitle": "Unganisha kifaa cha kusaini",
"back": "Rudi",
"secretKeyLabel": "Tumia ufunguo wa siri",
"nsecPlaceholder": "nsec1…",
"uploadKeyFile": "Pakia faili ya ufunguo",
"loggingIn": "Inaingia…",
"loginWithExtension": "Ingia kwa kiendelezi",
"useRemoteSigner": "Tumia kifaa cha kusaini cha mbali",
"tryAgain": "Jaribu tena",
"cancel": "Ghairi",
"openSignerApp": "Fungua programu ya kusaini",
"enterBunkerManually": "Weka URI ya bunker mwenyewe",
"bunkerPlaceholder": "bunker://…",
"invalidBunkerFormat": "Muundo wa URI ya bunker si sahihi.",
"connecting": "Inaunganisha…",
"connect": "Unganisha",
"waitingForSigner": "Inasubiri muunganisho wa kifaa cha kusaini…",
"gettingPublicKey": "Inapata ufunguo wa umma…",
"errorEnterSecretKey": "Weka ufunguo wako wa siri.",
"errorInvalidSecretKey": "Ufunguo wa siri si sahihi. Lazima uanze na nsec1.",
"errorLoginFailed": "Imeshindwa kuingia kwa ufunguo huu.",
"errorFileNoKey": "Faili haina ufunguo wa siri halali.",
"errorFileRead": "Imeshindwa kusoma faili.",
"errorExtensionFailed": "Kuingia kwa kiendelezi kumeshindwa.",
"errorBunkerConnect": "Imeshindwa kuunganisha. Angalia URI ya bunker.",
"extensionErrorTitle": "Kuingia kwa kiendelezi kumeshindwa"
},
"onboarding": {
"ariaLabel": "Usanidi wa akaunti",
+28 -1
View File
@@ -131,7 +131,34 @@
"logout": "Çıkış yap",
"addAccount": "Başka hesap ekle",
"createNewAccount": "Yeni hesap oluştur",
"loginExisting": "Mevcut hesapla giriş yap"
"loginExisting": "Mevcut hesapla giriş yap",
"loginTitle": "Giriş yap",
"connectSignerTitle": "İmzalayıcıya bağlan",
"back": "Geri",
"secretKeyLabel": "Gizli anahtar kullan",
"nsecPlaceholder": "nsec1…",
"uploadKeyFile": "Anahtar dosyası yükle",
"loggingIn": "Giriş yapılıyor…",
"loginWithExtension": "Eklenti ile giriş yap",
"useRemoteSigner": "Uzak imzalayıcı kullan",
"tryAgain": "Tekrar dene",
"cancel": "İptal",
"openSignerApp": "İmzalayıcı uygulamasını aç",
"enterBunkerManually": "Bunker URI'sini elle gir",
"bunkerPlaceholder": "bunker://…",
"invalidBunkerFormat": "Geçersiz bunker URI biçimi.",
"connecting": "Bağlanılıyor…",
"connect": "Bağlan",
"waitingForSigner": "İmzalayıcı bağlantısı bekleniyor…",
"gettingPublicKey": "Açık anahtar alınıyor…",
"errorEnterSecretKey": "Gizli anahtarınızı girin.",
"errorInvalidSecretKey": "Geçersiz gizli anahtar. nsec1 ile başlamalı.",
"errorLoginFailed": "Bu anahtarla giriş yapılamadı.",
"errorFileNoKey": "Dosya geçerli bir gizli anahtar içermiyor.",
"errorFileRead": "Dosya okunamadı.",
"errorExtensionFailed": "Eklenti ile giriş başarısız oldu.",
"errorBunkerConnect": "Bağlanılamadı. Bunker URI'sini kontrol edin.",
"extensionErrorTitle": "Eklenti ile giriş başarısız oldu"
},
"onboarding": {
"ariaLabel": "Hesap kurulumu",
+28 -1
View File
@@ -131,7 +131,34 @@
"logout": "退出登入",
"addAccount": "新增其他賬戶",
"createNewAccount": "建立新帳戶",
"loginExisting": "使用現有帳戶登入"
"loginExisting": "使用現有帳戶登入",
"loginTitle": "登入",
"connectSignerTitle": "連接簽名器",
"back": "返回",
"secretKeyLabel": "使用私鑰",
"nsecPlaceholder": "nsec1…",
"uploadKeyFile": "上傳金鑰檔案",
"loggingIn": "正在登入…",
"loginWithExtension": "使用擴充功能登入",
"useRemoteSigner": "使用遠端簽名器",
"tryAgain": "重試",
"cancel": "取消",
"openSignerApp": "開啟簽名器應用程式",
"enterBunkerManually": "手動輸入 bunker URI",
"bunkerPlaceholder": "bunker://…",
"invalidBunkerFormat": "bunker URI 格式無效。",
"connecting": "正在連接…",
"connect": "連接",
"waitingForSigner": "正在等待簽名器連接…",
"gettingPublicKey": "正在取得公鑰…",
"errorEnterSecretKey": "請輸入您的私鑰。",
"errorInvalidSecretKey": "私鑰無效。必須以 nsec1 開頭。",
"errorLoginFailed": "無法使用此金鑰登入。",
"errorFileNoKey": "檔案不包含有效的私鑰。",
"errorFileRead": "讀取檔案失敗。",
"errorExtensionFailed": "擴充功能登入失敗。",
"errorBunkerConnect": "連接失敗。請檢查 bunker URI。",
"extensionErrorTitle": "擴充功能登入失敗"
},
"onboarding": {
"ariaLabel": "帳號設定",
+28 -1
View File
@@ -131,7 +131,34 @@
"logout": "退出登录",
"addAccount": "添加其他账户",
"createNewAccount": "创建新账户",
"loginExisting": "使用现有账户登录"
"loginExisting": "使用现有账户登录",
"loginTitle": "登录",
"connectSignerTitle": "连接签名器",
"back": "返回",
"secretKeyLabel": "使用私钥",
"nsecPlaceholder": "nsec1…",
"uploadKeyFile": "上传密钥文件",
"loggingIn": "正在登录…",
"loginWithExtension": "使用扩展登录",
"useRemoteSigner": "使用远程签名器",
"tryAgain": "重试",
"cancel": "取消",
"openSignerApp": "打开签名器应用",
"enterBunkerManually": "手动输入 bunker URI",
"bunkerPlaceholder": "bunker://…",
"invalidBunkerFormat": "bunker URI 格式无效。",
"connecting": "正在连接…",
"connect": "连接",
"waitingForSigner": "正在等待签名器连接…",
"gettingPublicKey": "正在获取公钥…",
"errorEnterSecretKey": "请输入您的私钥。",
"errorInvalidSecretKey": "私钥无效。必须以 nsec1 开头。",
"errorLoginFailed": "无法使用此密钥登录。",
"errorFileNoKey": "文件不包含有效的私钥。",
"errorFileRead": "读取文件失败。",
"errorExtensionFailed": "扩展登录失败。",
"errorBunkerConnect": "连接失败。请检查 bunker URI。",
"extensionErrorTitle": "扩展登录失败"
},
"onboarding": {
"ariaLabel": "账户设置",